Merge "Use P521 curve instead of P256" into sc-dev
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 32493c0..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: [
@@ -108,7 +106,7 @@
"libbinder_rs",
"libkeystore2",
"liblog_rust",
- "libvpnprofilestore-rust",
+ "liblegacykeystore-rust",
],
init_rc: ["keystore2.rc"],
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 1bfc98a..4a7b7b4 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -151,8 +151,8 @@
}
aidl_interface {
- name: "android.security.vpnprofilestore",
- srcs: [ "android/security/vpnprofilestore/*.aidl" ],
+ name: "android.security.legacykeystore",
+ srcs: [ "android/security/legacykeystore/*.aidl" ],
unstable: true,
backend: {
java: {
@@ -162,6 +162,32 @@
rust: {
enabled: true,
},
+ ndk: {
+ enabled: true,
+ apps_enabled: false,
+ }
+ },
+}
+
+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/legacykeystore/ILegacyKeystore.aidl b/keystore2/aidl/android/security/legacykeystore/ILegacyKeystore.aidl
new file mode 100644
index 0000000..e65efaa
--- /dev/null
+++ b/keystore2/aidl/android/security/legacykeystore/ILegacyKeystore.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 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.legacykeystore;
+
+/**
+ * Internal interface for accessing and storing legacy keystore blobs.
+ * Before Android S, Keystore offered a key-value store that was intended for storing
+ * data associated with certain types of keys. E.g., public certificates for asymmetric keys.
+ * This key value store no longer exists as part of the Keystore 2.0 protocol.
+ * However, there are some clients that used Keystore in an unintended way.
+ * This interface exists to give these clients a grace period to migrate their keys
+ * out of legacy keystore. In Android S, this legacy keystore may be used as keystore was
+ * used in earlier versions, and provides access to entries that were put into keystore
+ * before Android S.
+ *
+ * DEPRECATION NOTICE: In Android T, the `put` function is slated to be removed.
+ * This will allow clients to use the `get`, `list`, and `remove` API to migrate blobs out
+ * of legacy keystore.
+ * @hide
+ */
+interface ILegacyKeystore {
+
+ /**
+ * Special value indicating the callers uid.
+ */
+ const int UID_SELF = -1;
+
+ /**
+ * Service specific error code indicating that an unexpected system error occurred.
+ */
+ const int ERROR_SYSTEM_ERROR = 4;
+
+ /**
+ * Service specific error code indicating that the caller does not have the
+ * right to access the requested uid.
+ */
+ const int ERROR_PERMISSION_DENIED = 6;
+
+ /**
+ * Service specific error code indicating that the entry was not found.
+ */
+ const int ERROR_ENTRY_NOT_FOUND = 7;
+
+ /**
+ * Returns the blob stored under the given name.
+ *
+ * @param alias name of the blob entry.
+ * @param uid designates the legacy namespace. Specify UID_SELF for the caller's namespace.
+ * @return The unstructured blob that was passed as blob parameter into put()
+ */
+ byte[] get(in String alias, int uid);
+
+ /**
+ * Stores one entry as unstructured blob under the given alias.
+ * Overwrites existing entries with the same alias.
+ *
+ * @param alias name of the new entry.
+ * @param uid designates the legacy namespace. Specify UID_SELF for the caller's namespace.
+ * @param blob the payload of the new entry.
+ *
+ * IMPORTANT DEPRECATION NOTICE: This function is slated to be removed in Android T.
+ * Do not add new callers. The remaining functionality will remain for the purpose
+ * of migrating legacy configuration out.
+ */
+ void put(in String alias, int uid, in byte[] blob);
+
+ /**
+ * Deletes the entry under the given alias.
+ *
+ * @param alias name of the entry to be removed.
+ * @param uid designates the legacy namespace of the entry. Specify UID_SELF for the caller's
+ * namespace.
+ */
+ void remove(in String alias, int uid);
+
+ /**
+ * Returns a list of aliases of entries stored. The list is filtered by prefix.
+ * The resulting strings are the full aliases including the prefix.
+ *
+ * @param prefix used to filter results.
+ * @param uid legacy namespace to list. Specify UID_SELF for caller's namespace.
+ */
+ String[] list(in String prefix, int uid);
+}
\ No newline at end of file
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/aidl/android/security/vpnprofilestore/IVpnProfileStore.aidl b/keystore2/aidl/android/security/vpnprofilestore/IVpnProfileStore.aidl
deleted file mode 100644
index 8375b7b..0000000
--- a/keystore2/aidl/android/security/vpnprofilestore/IVpnProfileStore.aidl
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 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.vpnprofilestore;
-
-/**
- * Internal interface for accessing and storing VPN profiles.
- * @hide
- */
-interface IVpnProfileStore {
- /**
- * Service specific error code indicating that the profile was not found.
- */
- const int ERROR_PROFILE_NOT_FOUND = 1;
-
- /**
- * Service specific error code indicating that an unexpected system error occurred.
- */
- const int ERROR_SYSTEM_ERROR = 2;
-
- /**
- * Returns the profile stored under the given alias.
- *
- * @param alias name of the profile.
- * @return The unstructured blob that was passed as profile parameter into put()
- */
- byte[] get(in String alias);
-
- /**
- * Stores one profile as unstructured blob under the given alias.
- */
- void put(in String alias, in byte[] profile);
-
- /**
- * Deletes the profile under the given alias.
- */
- void remove(in String alias);
-
- /**
- * Returns a list of aliases of profiles stored. The list is filtered by prefix.
- * The resulting strings are the full aliases including the prefix.
- */
- String[] list(in String prefix);
-}
\ No newline at end of file
diff --git a/keystore2/vpnprofilestore/Android.bp b/keystore2/legacykeystore/Android.bp
similarity index 85%
rename from keystore2/vpnprofilestore/Android.bp
rename to keystore2/legacykeystore/Android.bp
index 7ddf0d6..c2890cc 100644
--- a/keystore2/vpnprofilestore/Android.bp
+++ b/keystore2/legacykeystore/Android.bp
@@ -22,13 +22,13 @@
}
rust_library {
- name: "libvpnprofilestore-rust",
- crate_name: "vpnprofilestore",
+ name: "liblegacykeystore-rust",
+ crate_name: "legacykeystore",
srcs: [
"lib.rs",
],
rustlibs: [
- "android.security.vpnprofilestore-rust",
+ "android.security.legacykeystore-rust",
"libanyhow",
"libbinder_rs",
"libkeystore2",
@@ -39,13 +39,13 @@
}
rust_test {
- name: "vpnprofilestore_test",
- crate_name: "vpnprofilestore",
+ name: "legacykeystore_test",
+ crate_name: "legacykeystore",
srcs: ["lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
rustlibs: [
- "android.security.vpnprofilestore-rust",
+ "android.security.legacykeystore-rust",
"libanyhow",
"libbinder_rs",
"libkeystore2",
diff --git a/keystore2/vpnprofilestore/lib.rs b/keystore2/legacykeystore/lib.rs
similarity index 63%
rename from keystore2/vpnprofilestore/lib.rs
rename to keystore2/legacykeystore/lib.rs
index 548bec5..8a4d7d8 100644
--- a/keystore2/vpnprofilestore/lib.rs
+++ b/keystore2/legacykeystore/lib.rs
@@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//! Implements the android.security.vpnprofilestore interface.
+//! Implements the android.security.legacykeystore interface.
-use android_security_vpnprofilestore::aidl::android::security::vpnprofilestore::{
- IVpnProfileStore::BnVpnProfileStore, IVpnProfileStore::IVpnProfileStore,
- IVpnProfileStore::ERROR_PROFILE_NOT_FOUND, IVpnProfileStore::ERROR_SYSTEM_ERROR,
+use android_security_legacykeystore::aidl::android::security::legacykeystore::{
+ ILegacyKeystore::BnLegacyKeystore, ILegacyKeystore::ILegacyKeystore,
+ ILegacyKeystore::ERROR_ENTRY_NOT_FOUND, ILegacyKeystore::ERROR_PERMISSION_DENIED,
+ ILegacyKeystore::ERROR_SYSTEM_ERROR, ILegacyKeystore::UID_SELF,
};
-use android_security_vpnprofilestore::binder::{
+use android_security_legacykeystore::binder::{
BinderFeatures, ExceptionCode, Result as BinderResult, Status as BinderStatus, Strong,
ThreadState,
};
@@ -42,7 +43,7 @@
conn: Connection::open(db_file).context("Failed to initialize SQLite connection.")?,
};
- db.init_tables().context("Trying to initialize vpnstore db.")?;
+ db.init_tables().context("Trying to initialize legacy keystore db.")?;
Ok(db)
}
@@ -110,11 +111,11 @@
})
}
- fn put(&mut self, caller_uid: u32, alias: &str, profile: &[u8]) -> Result<()> {
+ fn put(&mut self, caller_uid: u32, alias: &str, entry: &[u8]) -> Result<()> {
self.with_transaction(TransactionBehavior::Immediate, |tx| {
tx.execute(
"INSERT OR REPLACE INTO profiles (owner, alias, profile) values (?, ?, ?)",
- params![caller_uid, alias, profile,],
+ params![caller_uid, alias, entry,],
)
.context("In put: Failed to insert or replace.")?;
Ok(())
@@ -129,7 +130,7 @@
|row| row.get(0),
)
.optional()
- .context("In get: failed loading profile.")
+ .context("In get: failed loading entry.")
})
}
@@ -145,11 +146,11 @@
}
}
-/// This is the main VpnProfileStore error type, it wraps binder exceptions and the
-/// VnpStore errors.
+/// This is the main LegacyKeystore error type, it wraps binder exceptions and the
+/// LegacyKeystore errors.
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum Error {
- /// Wraps a VpnProfileStore error code.
+ /// Wraps a LegacyKeystore error code.
#[error("Error::Error({0:?})")]
Error(i32),
/// Wraps a Binder exception code other than a service specific exception.
@@ -163,16 +164,21 @@
Error::Error(ERROR_SYSTEM_ERROR)
}
- /// Short hand for `Error::Error(ERROR_PROFILE_NOT_FOUND)`
+ /// Short hand for `Error::Error(ERROR_ENTRY_NOT_FOUND)`
pub fn not_found() -> Self {
- Error::Error(ERROR_PROFILE_NOT_FOUND)
+ Error::Error(ERROR_ENTRY_NOT_FOUND)
+ }
+
+ /// Short hand for `Error::Error(ERROR_PERMISSION_DENIED)`
+ pub fn perm() -> Self {
+ Error::Error(ERROR_PERMISSION_DENIED)
}
}
-/// This function should be used by vpnprofilestore service calls to translate error conditions
+/// This function should be used by legacykeystore service calls to translate error conditions
/// into service specific exceptions.
///
-/// All error conditions get logged by this function, except for ERROR_PROFILE_NOT_FOUND error.
+/// All error conditions get logged by this function, except for ERROR_ENTRY_NOT_FOUND error.
///
/// `Error::Error(x)` variants get mapped onto a service specific error code of `x`.
///
@@ -189,8 +195,8 @@
|e| {
let root_cause = e.root_cause();
let (rc, log_error) = match root_cause.downcast_ref::<Error>() {
- // Make the profile not found errors silent.
- Some(Error::Error(ERROR_PROFILE_NOT_FOUND)) => (ERROR_PROFILE_NOT_FOUND, false),
+ // Make the entry not found errors silent.
+ Some(Error::Error(ERROR_ENTRY_NOT_FOUND)) => (ERROR_ENTRY_NOT_FOUND, false),
Some(Error::Error(e)) => (*e, true),
Some(Error::Binder(_, _)) | None => (ERROR_SYSTEM_ERROR, true),
};
@@ -203,8 +209,8 @@
)
}
-/// Implements IVpnProfileStore AIDL interface.
-pub struct VpnProfileStore {
+/// Implements ILegacyKeystore AIDL interface.
+pub struct LegacyKeystore {
db_path: PathBuf,
async_task: AsyncTask,
}
@@ -215,72 +221,93 @@
db_path: PathBuf,
}
-impl VpnProfileStore {
- /// Creates a new VpnProfileStore instance.
- pub fn new_native_binder(path: &Path) -> Strong<dyn IVpnProfileStore> {
+impl LegacyKeystore {
+ /// Note: The filename was chosen before the purpose of this module was extended.
+ /// It is kept for backward compatibility with early adopters.
+ const LEGACY_KEYSTORE_FILE_NAME: &'static str = "vpnprofilestore.sqlite";
+
+ /// Creates a new LegacyKeystore instance.
+ pub fn new_native_binder(path: &Path) -> Strong<dyn ILegacyKeystore> {
let mut db_path = path.to_path_buf();
- db_path.push("vpnprofilestore.sqlite");
+ db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
let result = Self { db_path, async_task: Default::default() };
result.init_shelf(path);
- BnVpnProfileStore::new_binder(result, BinderFeatures::default())
+ BnLegacyKeystore::new_binder(result, BinderFeatures::default())
}
fn open_db(&self) -> Result<DB> {
DB::new(&self.db_path).context("In open_db: Failed to open db.")
}
- fn get(&self, alias: &str) -> Result<Vec<u8>> {
- let mut db = self.open_db().context("In get.")?;
+ fn get_effective_uid(uid: i32) -> Result<u32> {
+ const AID_SYSTEM: u32 = 1000;
+ const AID_WIFI: u32 = 1010;
let calling_uid = ThreadState::get_calling_uid();
+ let uid = uid as u32;
- if let Some(profile) =
- db.get(calling_uid, alias).context("In get: Trying to load profile from DB.")?
- {
- return Ok(profile);
+ if uid == UID_SELF as u32 || uid == calling_uid {
+ Ok(calling_uid)
+ } else if calling_uid == AID_SYSTEM && uid == AID_WIFI {
+ // The only exception for legacy reasons is allowing SYSTEM to access
+ // the WIFI namespace.
+ // IMPORTANT: If you attempt to add more exceptions, it means you are adding
+ // more callers to this deprecated feature. DON'T!
+ Ok(AID_WIFI)
+ } else {
+ Err(Error::perm()).with_context(|| {
+ format!("In get_effective_uid: caller: {}, requested uid: {}.", calling_uid, uid)
+ })
}
- if self.get_legacy(calling_uid, alias).context("In get: Trying to migrate legacy blob.")? {
+ }
+
+ fn get(&self, alias: &str, uid: i32) -> Result<Vec<u8>> {
+ let mut db = self.open_db().context("In get.")?;
+ let uid = Self::get_effective_uid(uid).context("In get.")?;
+
+ if let Some(entry) = db.get(uid, alias).context("In get: Trying to load entry from DB.")? {
+ return Ok(entry);
+ }
+ if self.get_legacy(uid, alias).context("In get: Trying to migrate legacy blob.")? {
// If we were able to migrate a legacy blob try again.
- if let Some(profile) =
- db.get(calling_uid, alias).context("In get: Trying to load profile from DB.")?
+ if let Some(entry) =
+ db.get(uid, alias).context("In get: Trying to load entry from DB.")?
{
- return Ok(profile);
+ return Ok(entry);
}
}
- Err(Error::not_found()).context("In get: No such profile.")
+ Err(Error::not_found()).context("In get: No such entry.")
}
- fn put(&self, alias: &str, profile: &[u8]) -> Result<()> {
- let calling_uid = ThreadState::get_calling_uid();
- // In order to make sure that we don't have stale legacy profiles, make sure they are
+ fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> Result<()> {
+ let uid = Self::get_effective_uid(uid).context("In put.")?;
+ // In order to make sure that we don't have stale legacy entries, make sure they are
// migrated before replacing them.
- let _ = self.get_legacy(calling_uid, alias);
+ let _ = self.get_legacy(uid, alias);
let mut db = self.open_db().context("In put.")?;
- db.put(calling_uid, alias, profile).context("In put: Trying to insert profile into DB.")
+ db.put(uid, alias, entry).context("In put: Trying to insert entry into DB.")
}
- fn remove(&self, alias: &str) -> Result<()> {
- let calling_uid = ThreadState::get_calling_uid();
+ fn remove(&self, alias: &str, uid: i32) -> Result<()> {
+ let uid = Self::get_effective_uid(uid).context("In remove.")?;
let mut db = self.open_db().context("In remove.")?;
- // In order to make sure that we don't have stale legacy profiles, make sure they are
+ // In order to make sure that we don't have stale legacy entries, make sure they are
// migrated before removing them.
- let _ = self.get_legacy(calling_uid, alias);
- let removed = db
- .remove(calling_uid, alias)
- .context("In remove: Trying to remove profile from DB.")?;
+ let _ = self.get_legacy(uid, alias);
+ let removed =
+ db.remove(uid, alias).context("In remove: Trying to remove entry from DB.")?;
if removed {
Ok(())
} else {
- Err(Error::not_found()).context("In remove: No such profile.")
+ Err(Error::not_found()).context("In remove: No such entry.")
}
}
- fn list(&self, prefix: &str) -> Result<Vec<String>> {
+ fn list(&self, prefix: &str, uid: i32) -> Result<Vec<String>> {
let mut db = self.open_db().context("In list.")?;
- let calling_uid = ThreadState::get_calling_uid();
- let mut result = self.list_legacy(calling_uid).context("In list.")?;
- result
- .append(&mut db.list(calling_uid).context("In list: Trying to get list of profiles.")?);
+ let uid = Self::get_effective_uid(uid).context("In list.")?;
+ let mut result = self.list_legacy(uid).context("In list.")?;
+ result.append(&mut db.list(uid).context("In list: Trying to get list of entries.")?);
result = result.into_iter().filter(|s| s.starts_with(prefix)).collect();
result.sort_unstable();
result.dedup();
@@ -291,7 +318,7 @@
let mut db_path = path.to_path_buf();
self.async_task.queue_hi(move |shelf| {
let legacy_loader = LegacyBlobLoader::new(&db_path);
- db_path.push("vpnprofilestore.sqlite");
+ db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
shelf.put(AsyncState { legacy_loader, db_path, recently_imported: Default::default() });
})
@@ -313,8 +340,8 @@
self.do_serialized(move |state| {
state
.legacy_loader
- .list_vpn_profiles(uid)
- .context("Trying to list legacy vnp profiles.")
+ .list_legacy_keystore_entries(uid)
+ .context("Trying to list legacy keystore entries.")
})
.context("In list_legacy.")
}
@@ -327,8 +354,8 @@
}
let mut db = DB::new(&state.db_path).context("In open_db: Failed to open db.")?;
let migrated =
- Self::migrate_one_legacy_profile(uid, &alias, &state.legacy_loader, &mut db)
- .context("Trying to migrate legacy vpn profile.")?;
+ Self::migrate_one_legacy_entry(uid, &alias, &state.legacy_loader, &mut db)
+ .context("Trying to migrate legacy keystore entries.")?;
if migrated {
state.recently_imported.insert((uid, alias));
}
@@ -337,21 +364,21 @@
.context("In get_legacy.")
}
- fn migrate_one_legacy_profile(
+ fn migrate_one_legacy_entry(
uid: u32,
alias: &str,
legacy_loader: &LegacyBlobLoader,
db: &mut DB,
) -> Result<bool> {
let blob = legacy_loader
- .read_vpn_profile(uid, alias)
- .context("In migrate_one_legacy_profile: Trying to read legacy vpn profile.")?;
- if let Some(profile) = blob {
- db.put(uid, alias, &profile)
- .context("In migrate_one_legacy_profile: Trying to insert profile into DB.")?;
+ .read_legacy_keystore_entry(uid, alias)
+ .context("In migrate_one_legacy_entry: Trying to read legacy keystore entry.")?;
+ if let Some(entry) = blob {
+ db.put(uid, alias, &entry)
+ .context("In migrate_one_legacy_entry: Trying to insert entry into DB.")?;
legacy_loader
- .remove_vpn_profile(uid, alias)
- .context("In migrate_one_legacy_profile: Trying to delete legacy profile.")?;
+ .remove_legacy_keystore_entry(uid, alias)
+ .context("In migrate_one_legacy_entry: Trying to delete legacy keystore entry.")?;
Ok(true)
} else {
Ok(false)
@@ -359,24 +386,24 @@
}
}
-impl binder::Interface for VpnProfileStore {}
+impl binder::Interface for LegacyKeystore {}
-impl IVpnProfileStore for VpnProfileStore {
- fn get(&self, alias: &str) -> BinderResult<Vec<u8>> {
- let _wp = wd::watch_millis("IVpnProfileStore::get", 500);
- map_or_log_err(self.get(alias), Ok)
+impl ILegacyKeystore for LegacyKeystore {
+ fn get(&self, alias: &str, uid: i32) -> BinderResult<Vec<u8>> {
+ let _wp = wd::watch_millis("ILegacyKeystore::get", 500);
+ map_or_log_err(self.get(alias, uid), Ok)
}
- fn put(&self, alias: &str, profile: &[u8]) -> BinderResult<()> {
- let _wp = wd::watch_millis("IVpnProfileStore::put", 500);
- map_or_log_err(self.put(alias, profile), Ok)
+ fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> BinderResult<()> {
+ let _wp = wd::watch_millis("ILegacyKeystore::put", 500);
+ map_or_log_err(self.put(alias, uid, entry), Ok)
}
- fn remove(&self, alias: &str) -> BinderResult<()> {
- let _wp = wd::watch_millis("IVpnProfileStore::remove", 500);
- map_or_log_err(self.remove(alias), Ok)
+ fn remove(&self, alias: &str, uid: i32) -> BinderResult<()> {
+ let _wp = wd::watch_millis("ILegacyKeystore::remove", 500);
+ map_or_log_err(self.remove(alias, uid), Ok)
}
- fn list(&self, prefix: &str) -> BinderResult<Vec<String>> {
- let _wp = wd::watch_millis("IVpnProfileStore::list", 500);
- map_or_log_err(self.list(prefix), Ok)
+ fn list(&self, prefix: &str, uid: i32) -> BinderResult<Vec<String>> {
+ let _wp = wd::watch_millis("ILegacyKeystore::list", 500);
+ map_or_log_err(self.list(prefix, uid), Ok)
}
}
@@ -396,12 +423,12 @@
static TEST_BLOB4: &[u8] = &[3, 2, 3, 4, 5, 6, 7, 8, 9, 0];
#[test]
- fn test_profile_db() {
- let test_dir = TempDir::new("profiledb_test_").expect("Failed to create temp dir.");
- let mut db =
- DB::new(&test_dir.build().push("vpnprofile.sqlite")).expect("Failed to open database.");
+ fn test_entry_db() {
+ let test_dir = TempDir::new("entrydb_test_").expect("Failed to create temp dir.");
+ let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
+ .expect("Failed to open database.");
- // Insert three profiles for owner 2.
+ // Insert three entries for owner 2.
db.put(2, "test1", TEST_BLOB1).expect("Failed to insert test1.");
db.put(2, "test2", TEST_BLOB2).expect("Failed to insert test2.");
db.put(2, "test3", TEST_BLOB3).expect("Failed to insert test3.");
@@ -409,73 +436,59 @@
// Check list returns all inserted aliases.
assert_eq!(
vec!["test1".to_string(), "test2".to_string(), "test3".to_string(),],
- db.list(2).expect("Failed to list profiles.")
+ db.list(2).expect("Failed to list entries.")
);
- // There should be no profiles for owner 1.
- assert_eq!(Vec::<String>::new(), db.list(1).expect("Failed to list profiles."));
+ // There should be no entries for owner 1.
+ assert_eq!(Vec::<String>::new(), db.list(1).expect("Failed to list entries."));
// Check the content of the three entries.
- assert_eq!(
- Some(TEST_BLOB1),
- db.get(2, "test1").expect("Failed to get profile.").as_deref()
- );
- assert_eq!(
- Some(TEST_BLOB2),
- db.get(2, "test2").expect("Failed to get profile.").as_deref()
- );
- assert_eq!(
- Some(TEST_BLOB3),
- db.get(2, "test3").expect("Failed to get profile.").as_deref()
- );
+ assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
+ assert_eq!(Some(TEST_BLOB2), db.get(2, "test2").expect("Failed to get entry.").as_deref());
+ assert_eq!(Some(TEST_BLOB3), db.get(2, "test3").expect("Failed to get entry.").as_deref());
// Remove test2 and check and check that it is no longer retrievable.
- assert!(db.remove(2, "test2").expect("Failed to remove profile."));
- assert!(db.get(2, "test2").expect("Failed to get profile.").is_none());
+ assert!(db.remove(2, "test2").expect("Failed to remove entry."));
+ assert!(db.get(2, "test2").expect("Failed to get entry.").is_none());
// test2 should now no longer be in the list.
assert_eq!(
vec!["test1".to_string(), "test3".to_string(),],
- db.list(2).expect("Failed to list profiles.")
+ db.list(2).expect("Failed to list entries.")
);
// Put on existing alias replaces it.
// Verify test1 is TEST_BLOB1.
- assert_eq!(
- Some(TEST_BLOB1),
- db.get(2, "test1").expect("Failed to get profile.").as_deref()
- );
+ assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
db.put(2, "test1", TEST_BLOB4).expect("Failed to replace test1.");
// Verify test1 is TEST_BLOB4.
- assert_eq!(
- Some(TEST_BLOB4),
- db.get(2, "test1").expect("Failed to get profile.").as_deref()
- );
+ assert_eq!(Some(TEST_BLOB4), db.get(2, "test1").expect("Failed to get entry.").as_deref());
}
#[test]
- fn concurrent_vpn_profile_test() -> Result<()> {
+ fn concurrent_legacy_keystore_entry_test() -> Result<()> {
let temp_dir = Arc::new(
- TempDir::new("concurrent_vpn_profile_test_").expect("Failed to create temp dir."),
+ TempDir::new("concurrent_legacy_keystore_entry_test_")
+ .expect("Failed to create temp dir."),
);
- let db_path = temp_dir.build().push("vpnprofile.sqlite").to_owned();
+ let db_path = temp_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME).to_owned();
let test_begin = Instant::now();
let mut db = DB::new(&db_path).expect("Failed to open database.");
- const PROFILE_COUNT: u32 = 5000u32;
- const PROFILE_DB_COUNT: u32 = 5000u32;
+ const ENTRY_COUNT: u32 = 5000u32;
+ const ENTRY_DB_COUNT: u32 = 5000u32;
- let mut actual_profile_count = PROFILE_COUNT;
- // First insert PROFILE_COUNT profiles.
- for count in 0..PROFILE_COUNT {
+ let mut actual_entry_count = ENTRY_COUNT;
+ // First insert ENTRY_COUNT entries.
+ for count in 0..ENTRY_COUNT {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
- actual_profile_count = count;
+ actual_entry_count = count;
break;
}
let alias = format!("test_alias_{}", count);
- db.put(1, &alias, TEST_BLOB1).expect("Failed to add profile (1).");
+ db.put(1, &alias, TEST_BLOB1).expect("Failed to add entry (1).");
}
// Insert more keys from a different thread and into a different namespace.
@@ -483,16 +496,16 @@
let handle1 = thread::spawn(move || {
let mut db = DB::new(&db_path1).expect("Failed to open database.");
- for count in 0..actual_profile_count {
+ for count in 0..actual_entry_count {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
return;
}
let alias = format!("test_alias_{}", count);
- db.put(2, &alias, TEST_BLOB2).expect("Failed to add profile (2).");
+ db.put(2, &alias, TEST_BLOB2).expect("Failed to add entry (2).");
}
// Then delete them again.
- for count in 0..actual_profile_count {
+ for count in 0..actual_entry_count {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
return;
}
@@ -501,12 +514,12 @@
}
});
- // And start deleting the first set of profiles.
+ // And start deleting the first set of entries.
let db_path2 = db_path.clone();
let handle2 = thread::spawn(move || {
let mut db = DB::new(&db_path2).expect("Failed to open database.");
- for count in 0..actual_profile_count {
+ for count in 0..actual_entry_count {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
return;
}
@@ -516,16 +529,16 @@
});
// While a lot of inserting and deleting is going on we have to open database connections
- // successfully and then insert and delete a specific profile.
+ // successfully and then insert and delete a specific entry.
let db_path3 = db_path.clone();
let handle3 = thread::spawn(move || {
- for _count in 0..PROFILE_DB_COUNT {
+ for _count in 0..ENTRY_DB_COUNT {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
return;
}
let mut db = DB::new(&db_path3).expect("Failed to open database.");
- db.put(3, &TEST_ALIAS, TEST_BLOB3).expect("Failed to add profile (3).");
+ db.put(3, &TEST_ALIAS, TEST_BLOB3).expect("Failed to add entry (3).");
db.remove(3, &TEST_ALIAS).expect("Remove failed (3).");
}
@@ -534,14 +547,14 @@
// While thread 3 is inserting and deleting TEST_ALIAS, we try to get the alias.
// This may yield an entry or none, but it must not fail.
let handle4 = thread::spawn(move || {
- for _count in 0..PROFILE_DB_COUNT {
+ for _count in 0..ENTRY_DB_COUNT {
if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
return;
}
let mut db = DB::new(&db_path).expect("Failed to open database.");
// This may return Some or None but it must not fail.
- db.get(3, &TEST_ALIAS).expect("Failed to get profile (4).");
+ db.get(3, &TEST_ALIAS).expect("Failed to get entry (4).");
}
});
diff --git a/keystore2/src/attestation_key_utils.rs b/keystore2/src/attestation_key_utils.rs
index 425eec6..ca00539 100644
--- a/keystore2/src/attestation_key_utils.rs
+++ b/keystore2/src/attestation_key_utils.rs
@@ -22,7 +22,7 @@
use crate::remote_provisioning::RemProvState;
use crate::utils::check_key_permission;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- AttestationKey::AttestationKey, Certificate::Certificate, KeyParameter::KeyParameter,
+ AttestationKey::AttestationKey, Certificate::Certificate, KeyParameter::KeyParameter, Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, KeyDescriptor::KeyDescriptor,
@@ -47,8 +47,8 @@
}
/// This function loads and, optionally, assigns the caller's remote provisioned
-/// attestation key or, if `attest_key_descriptor` is given, it loads the user
-/// generated attestation key from the database.
+/// attestation key if a challenge is present. Alternatively, if `attest_key_descriptor` is given,
+/// it loads the user generated attestation key from the database.
pub fn get_attest_key_info(
key: &KeyDescriptor,
caller_uid: u32,
@@ -57,8 +57,9 @@
rem_prov_state: &RemProvState,
db: &mut KeystoreDB,
) -> Result<Option<AttestationKeyInfo>> {
+ let challenge_present = params.iter().any(|kp| kp.tag == Tag::ATTESTATION_CHALLENGE);
match attest_key_descriptor {
- None => rem_prov_state
+ None if challenge_present => rem_prov_state
.get_remotely_provisioned_attestation_key_and_certs(&key, caller_uid, params, db)
.context(concat!(
"In get_attest_key_and_cert_chain: ",
@@ -69,6 +70,7 @@
AttestationKeyInfo::RemoteProvisioned { attestation_key, attestation_certs }
})
}),
+ None => Ok(None),
Some(attest_key) => get_user_generated_attestation_key(&attest_key, caller_uid, db)
.context("In get_attest_key_and_cert_chain: Trying to load attest key")
.map(Some),
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 12f1558..ca346e0 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, |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 3d53a36..9535ecb 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -17,21 +17,22 @@
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};
use keystore2::{authorization::AuthorizationManager, id_rotation::IdRotationState};
+use legacykeystore::LegacyKeystore;
use log::{error, info};
use std::{panic, path::Path, sync::mpsc::channel};
-use vpnprofilestore::VpnProfileStore;
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 VPNPROFILESTORE_SERVICE_NAME: &str = "android.security.vpnprofilestore";
+static LEGACY_KEYSTORE_SERVICE_NAME: &str = "android.security.legacykeystore";
/// Keystore 2.0 takes one argument which is a path indicating its designated working directory.
fn main() {
@@ -105,6 +106,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() {
@@ -120,20 +128,18 @@
});
}
- let vpnprofilestore = VpnProfileStore::new_native_binder(
+ let legacykeystore = LegacyKeystore::new_native_binder(
&keystore2::globals::DB_PATH.read().expect("Could not get DB_PATH."),
);
- binder::add_service(VPNPROFILESTORE_SERVICE_NAME, vpnprofilestore.as_binder()).unwrap_or_else(
+ binder::add_service(LEGACY_KEYSTORE_SERVICE_NAME, legacykeystore.as_binder()).unwrap_or_else(
|e| {
panic!(
"Failed to register service {} because of {:?}.",
- VPNPROFILESTORE_SERVICE_NAME, e
+ LEGACY_KEYSTORE_SERVICE_NAME, e
);
},
);
- metrics::register_pull_metrics_callbacks();
-
info!("Successfully registered Keystore 2.0 service.");
info!("Joining thread pool now.");
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index 9eebb36..e0d2133 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -599,6 +599,15 @@
// * USRCERT was used for public certificates of USRPKEY entries. But KeyChain also
// used this for user installed certificates without private key material.
+ const KNOWN_KEYSTORE_PREFIXES: &'static [&'static str] =
+ &["USRPKEY_", "USRSKEY_", "USRCERT_", "CACERT_"];
+
+ fn is_keystore_alias(encoded_alias: &str) -> bool {
+ // We can check the encoded alias because the prefixes we are interested
+ // in are all in the printable range that don't get mangled.
+ Self::KNOWN_KEYSTORE_PREFIXES.iter().any(|prefix| encoded_alias.starts_with(prefix))
+ }
+
fn read_km_blob_file(&self, uid: u32, alias: &str) -> Result<Option<(Blob, String)>> {
let mut iter = ["USRPKEY", "USRSKEY"].iter();
@@ -630,28 +639,28 @@
Ok(Some(Self::new_from_stream(&mut file).context("In read_generic_blob.")?))
}
- /// Read a legacy vpn profile blob.
- pub fn read_vpn_profile(&self, uid: u32, alias: &str) -> Result<Option<Vec<u8>>> {
- let path = match self.make_vpn_profile_filename(uid, alias) {
+ /// Read a legacy keystore entry blob.
+ pub fn read_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<Option<Vec<u8>>> {
+ let path = match self.make_legacy_keystore_entry_filename(uid, alias) {
Some(path) => path,
None => return Ok(None),
};
- let blob =
- Self::read_generic_blob(&path).context("In read_vpn_profile: Failed to read blob.")?;
+ let blob = Self::read_generic_blob(&path)
+ .context("In read_legacy_keystore_entry: Failed to read blob.")?;
Ok(blob.and_then(|blob| match blob.value {
BlobValue::Generic(blob) => Some(blob),
_ => {
- log::info!("Unexpected vpn profile blob type. Ignoring");
+ log::info!("Unexpected legacy keystore entry blob type. Ignoring");
None
}
}))
}
- /// Remove a vpn profile by the name alias with owner uid.
- pub fn remove_vpn_profile(&self, uid: u32, alias: &str) -> Result<()> {
- let path = match self.make_vpn_profile_filename(uid, alias) {
+ /// Remove a legacy keystore entry by the name alias with owner uid.
+ pub fn remove_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<()> {
+ let path = match self.make_legacy_keystore_entry_filename(uid, alias) {
Some(path) => path,
None => return Ok(()),
};
@@ -659,25 +668,17 @@
if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
match e.kind() {
ErrorKind::NotFound => return Ok(()),
- _ => return Err(e).context("In remove_vpn_profile."),
+ _ => return Err(e).context("In remove_legacy_keystore_entry."),
}
}
let user_id = uid_to_android_user(uid);
self.remove_user_dir_if_empty(user_id)
- .context("In remove_vpn_profile: Trying to remove empty user dir.")
+ .context("In remove_legacy_keystore_entry: Trying to remove empty user dir.")
}
- fn is_vpn_profile(encoded_alias: &str) -> bool {
- // We can check the encoded alias because the prefixes we are interested
- // in are all in the printable range that don't get mangled.
- encoded_alias.starts_with("VPN_")
- || encoded_alias.starts_with("PLATFORM_VPN_")
- || encoded_alias == "LOCKDOWN_VPN"
- }
-
- /// List all profiles belonging to the given uid.
- pub fn list_vpn_profiles(&self, uid: u32) -> Result<Vec<String>> {
+ /// List all entries belonging to the given uid.
+ pub fn list_legacy_keystore_entries(&self, uid: u32) -> Result<Vec<String>> {
let mut path = self.path.clone();
let user_id = uid_to_android_user(uid);
path.push(format!("user_{}", user_id));
@@ -688,7 +689,10 @@
ErrorKind::NotFound => return Ok(Default::default()),
_ => {
return Err(e).context(format!(
- "In list_vpn_profiles: Failed to open legacy blob database. {:?}",
+ concat!(
+ "In list_legacy_keystore_entries: ,",
+ "Failed to open legacy blob database: {:?}"
+ ),
path
))
}
@@ -696,14 +700,15 @@
};
let mut result: Vec<String> = Vec::new();
for entry in dir {
- let file_name =
- entry.context("In list_vpn_profiles: Trying to access dir entry")?.file_name();
+ let file_name = entry
+ .context("In list_legacy_keystore_entries: Trying to access dir entry")?
+ .file_name();
if let Some(f) = file_name.to_str() {
let encoded_alias = &f[uid_str.len() + 1..];
- if f.starts_with(&uid_str) && Self::is_vpn_profile(encoded_alias) {
+ if f.starts_with(&uid_str) && !Self::is_keystore_alias(encoded_alias) {
result.push(
Self::decode_alias(encoded_alias)
- .context("In list_vpn_profiles: Trying to decode alias.")?,
+ .context("In list_legacy_keystore_entries: Trying to decode alias.")?,
)
}
}
@@ -711,12 +716,15 @@
Ok(result)
}
- /// This function constructs the vpn_profile file name which has the form:
- /// user_<android user id>/<uid>_<alias>.
- fn make_vpn_profile_filename(&self, uid: u32, alias: &str) -> Option<PathBuf> {
- // legacy vpn entries must start with VPN_ or PLATFORM_VPN_ or are literally called
- // LOCKDOWN_VPN.
- if !Self::is_vpn_profile(alias) {
+ /// This function constructs the legacy blob file name which has the form:
+ /// user_<android user id>/<uid>_<alias>. Legacy blob file names must not use
+ /// known keystore prefixes.
+ fn make_legacy_keystore_entry_filename(&self, uid: u32, alias: &str) -> Option<PathBuf> {
+ // Legacy entries must not use known keystore prefixes.
+ if Self::is_keystore_alias(alias) {
+ log::warn!(
+ "Known keystore prefixes cannot be used with legacy keystore -> ignoring request."
+ );
return None;
}
@@ -1376,11 +1384,11 @@
}
#[test]
- fn list_vpn_profiles_on_non_existing_user() -> Result<()> {
- let temp_dir = TempDir::new("list_vpn_profiles_on_non_existing_user")?;
+ fn list_legacy_keystore_entries_on_non_existing_user() -> Result<()> {
+ let temp_dir = TempDir::new("list_legacy_keystore_entries_on_non_existing_user")?;
let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
- assert!(legacy_blob_loader.list_vpn_profiles(20)?.is_empty());
+ assert!(legacy_blob_loader.list_legacy_keystore_entries(20)?.is_empty());
Ok(())
}
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 8d7ad0a..7171864 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, Asp};
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 f78d98b..365f8da 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::{
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index a6c7d72..bf6b9a6 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -37,6 +37,7 @@
using aidl::android::hardware::security::keymint::ProtectedData;
using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
+using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
using android::vintf::HalManifest;
using android::vintf::VintfObject;
@@ -46,12 +47,19 @@
DEFINE_bool(test_mode, false, "If enabled, a fake EEK key/cert are used.");
+DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
+
namespace {
const string kPackage = "android.hardware.security.keymint";
const string kInterface = "IRemotelyProvisionedComponent";
const string kFormattedName = kPackage + "." + kInterface + "/";
+// Various supported --output_format values.
+constexpr std::string_view kBinaryCsrOutput = "csr"; // Just the raw csr as binary
+constexpr std::string_view kBuildPlusCsr = "build+csr"; // Text-encoded (JSON) build
+ // fingerprint plus CSR.
+
constexpr size_t kChallengeSize = 16;
std::vector<uint8_t> generateChallenge() {
@@ -71,9 +79,8 @@
return challenge;
}
-std::vector<uint8_t> composeCertificateRequest(ProtectedData&& protectedData,
- DeviceInfo&& deviceInfo,
- const std::vector<uint8_t>& challenge) {
+Array composeCertificateRequest(ProtectedData&& protectedData, DeviceInfo&& deviceInfo,
+ const std::vector<uint8_t>& challenge) {
Array emptyMacedKeysToSign;
emptyMacedKeysToSign
.add(std::vector<uint8_t>(0)) // empty protected headers as bstr
@@ -85,7 +92,7 @@
.add(challenge)
.add(EncodedItem(std::move(protectedData.protectedData)))
.add(std::move(emptyMacedKeysToSign));
- return certificateRequest.encode();
+ return certificateRequest;
}
int32_t errorMsg(string name) {
@@ -106,6 +113,26 @@
return getProdEekChain();
}
+void writeOutput(const Array& csr) {
+ if (FLAGS_output_format == kBinaryCsrOutput) {
+ auto bytes = csr.encode();
+ std::copy(bytes.begin(), bytes.end(), std::ostream_iterator<char>(std::cout));
+ } else if (FLAGS_output_format == kBuildPlusCsr) {
+ auto [json, error] = jsonEncodeCsrWithBuild(csr);
+ if (!error.empty()) {
+ std::cerr << "Error JSON encoding the output: " << error;
+ exit(1);
+ }
+ std::cout << json << std::endl;
+ } else {
+ std::cerr << "Unexpected output_format '" << FLAGS_output_format << "'" << std::endl;
+ std::cerr << "Valid formats:" << std::endl;
+ std::cerr << " " << kBinaryCsrOutput << std::endl;
+ std::cerr << " " << kBuildPlusCsr << std::endl;
+ exit(1);
+ }
+}
+
} // namespace
int main(int argc, char** argv) {
@@ -140,10 +167,8 @@
ALOGE("Bundle extraction failed. Error code: %d", status.getServiceSpecificError());
return errorMsg(name);
}
- std::vector<uint8_t> certificateRequest = composeCertificateRequest(
- std::move(protectedData), std::move(deviceInfo), challenge);
- std::copy(certificateRequest.begin(), certificateRequest.end(),
- std::ostream_iterator<char>(std::cout));
+ writeOutput(composeCertificateRequest(std::move(protectedData), std::move(deviceInfo),
+ challenge));
}
}
}