Log keystore key creation events using statsd.

This is the first CL on migrating keystore logging to use statsd.
This migrates the logging for key creation events
	(generation/import).
A work-around is implemented to handle repeated fields via bitmaps
	because statsd does not support repeated fields as of now.

Test: Adding tests for logging is yet to be decided.
Bug: 157664923
Change-Id: Id23724cfbd21dca8ef5fd77e5712c0bc2e727f4b
Merged-In: Id23724cfbd21dca8ef5fd77e5712c0bc2e727f4b
diff --git a/keystore/Android.bp b/keystore/Android.bp
index b881757..b41ad18 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -34,8 +34,7 @@
         "blob.cpp",
         "confirmation_manager.cpp",
         "grant_store.cpp",
-        "key_config.proto",
-        "key_proto_handler.cpp",
+        "key_creation_log_handler.cpp",
         "key_store_service.cpp",
         "keyblob_utils.cpp",
         "keymaster_enforcement.cpp",
@@ -74,6 +73,7 @@
         "libservices",
         "libsoftkeymasterdevice",
         "libutils",
+        "libstatslog",
     ],
     init_rc: ["keystore.rc"],
     aidl: {
diff --git a/keystore/key_config.proto b/keystore/key_config.proto
deleted file mode 100644
index 0b1a398..0000000
--- a/keystore/key_config.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-syntax = "proto2";
-
-package keystore;
-
-option optimize_for = LITE_RUNTIME;
-
-message KeyConfig {
-  // What type of encryption algorithm is this key being generated/imported for
-  // e.g. AES, RSA, etc
-  optional string algorithm = 1;
-
-  // Size of the key being generated/imported
-  optional int32 key_size = 2;
-
-  // Log whether the key was generated, imported, securely imported, or derived.
-  optional string origin = 3;
-
-  // What auth types does this key require? If none, then no auth required.
-  optional string user_auth_type = 4;
-
-  // If user authentication is required, is the requirement time based? If it
-  // is not time based then this field will not be used and the key is per
-  // operation. Per operation keys must be user authenticated on each usage.
-  optional int32 user_auth_key_timeout = 5;
-
-  // Track which padding modes this key supports.
-  repeated string padding = 6;
-
-  // Track which digests this key supports
-  repeated string digest = 7;
-
-  // Check what block mode is being used depending on the mode of encryption
-  repeated string block_mode = 8;
-
-  // Was the key generated/imported successfully?
-  optional bool was_creation_successful = 9;
-
-  // What purposes can this key be used for?
-  repeated string purpose = 10;
-
-  // Which ec curve was selected if elliptic curve cryptography is in use
-  optional string ec_curve = 11;
-
-  // Standalone or is a file system required
-  optional string key_blob_usage_reqs = 12;
-}
diff --git a/keystore/key_creation_log_handler.cpp b/keystore/key_creation_log_handler.cpp
new file mode 100644
index 0000000..d846257
--- /dev/null
+++ b/keystore/key_creation_log_handler.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#define LOG_TAG "KeystoreOperation"
+
+#include "key_creation_log_handler.h"
+#include <statslog.h>
+
+namespace keystore {
+
+template <typename Tag>
+int32_t getEnumTagValue(const AuthorizationSet& authorization_set, Tag tag) {
+    auto tagValue = authorization_set.GetTagValue(tag);
+    if (tagValue.isOk()) {
+        static_assert(sizeof(decltype(tagValue.value())) <= sizeof(int32_t),
+                      "Tag type value will be truncated, if cast to int32_t");
+        return static_cast<int32_t>(tagValue.value());
+    }
+    // Usually, if the value is not present, 0 is set. However, since 0 is a valid
+    // enum value, -1 is set for single enum fields.
+    return -1;
+}
+
+int32_t generateBitMapForPaddingModeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_PADDING);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_PADDING, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_PADDING, keyParam);
+        switch (tagValue) {
+        case PaddingMode::NONE:
+            bitMap |= (1 << NONE_BIT_POS);
+            break;
+        case PaddingMode::RSA_OAEP:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS);
+            break;
+        case PaddingMode::RSA_PSS:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PSS_BIT_POS);
+            break;
+        case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS);
+            break;
+        case PaddingMode::RSA_PKCS1_1_5_SIGN:
+            bitMap |= (1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS);
+            break;
+        case PaddingMode::PKCS7:
+            bitMap |= (1 << PaddingModeBitPosition::PKCS7_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForDigestValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_DIGEST);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_DIGEST, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_DIGEST, keyParam);
+        switch (tagValue) {
+        case Digest::NONE:
+            bitMap |= (1 << NONE_BIT_POS);
+            break;
+        case Digest::MD5:
+            bitMap |= (1 << DigestBitPosition::MD5_BIT_POS);
+            break;
+        case Digest::SHA1:
+            bitMap |= (1 << DigestBitPosition::SHA1_BIT_POS);
+            break;
+        case Digest::SHA_2_224:
+            bitMap |= (1 << DigestBitPosition::SHA_2_224_BIT_POS);
+            break;
+        case Digest::SHA_2_256:
+            bitMap |= (1 << DigestBitPosition::SHA_2_256_BIT_POS);
+            break;
+        case Digest::SHA_2_384:
+            bitMap |= (1 << DigestBitPosition::SHA_2_384_BIT_POS);
+            break;
+        case Digest::SHA_2_512:
+            bitMap |= (1 << DigestBitPosition::SHA_2_512_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForBlockModeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_BLOCK_MODE);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_BLOCK_MODE, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_BLOCK_MODE, keyParam);
+        switch (tagValue) {
+        case BlockMode::ECB:
+            bitMap |= (1 << BlockModeBitPosition::ECB_BIT_POS);
+            break;
+        case BlockMode::CBC:
+            bitMap |= (1 << BlockModeBitPosition::CBC_BIT_POS);
+            break;
+        case BlockMode::CTR:
+            bitMap |= (1 << BlockModeBitPosition::CTR_BIT_POS);
+            break;
+        case BlockMode::GCM:
+            bitMap |= (1 << BlockModeBitPosition::GCM_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+int32_t generateBitMapForKeyPurposeValues(const AuthorizationSet& authorization_set) {
+    int32_t bitMap = 0;
+    int32_t tagValueCount = authorization_set.GetTagCount(TAG_PURPOSE);
+    if (tagValueCount == 0) {
+        // unlike in the single enum fields, if no value is provided,
+        // 0 is set for the bitmap
+        return bitMap;
+    }
+    int current_offset = -1;
+    while (tagValueCount > 0) {
+        current_offset = authorization_set.find(TAG_PURPOSE, current_offset);
+        KeyParameter keyParam = authorization_set[current_offset];
+        auto tagValue = accessTagValue(TAG_PURPOSE, keyParam);
+        switch (tagValue) {
+        case KeyPurpose::ENCRYPT:
+            bitMap |= (1 << KeyPurposeBitPosition::ENCRYPT_BIT_POS);
+            break;
+        case KeyPurpose::DECRYPT:
+            bitMap |= (1 << KeyPurposeBitPosition::DECRYPT_BIT_POS);
+            break;
+        case KeyPurpose::SIGN:
+            bitMap |= (1 << KeyPurposeBitPosition::SIGN_BIT_POS);
+            break;
+        case KeyPurpose::VERIFY:
+            bitMap |= (1 << KeyPurposeBitPosition::VERIFY_BIT_POS);
+            break;
+        case KeyPurpose::WRAP_KEY:
+            bitMap |= (1 << KeyPurposeBitPosition::WRAP_KEY_BIT_POS);
+            break;
+        default:
+            break;
+        }
+        tagValueCount -= 1;
+    }
+    return bitMap;
+}
+
+void logKeystoreKeyCreationEvent(const hidl_vec<KeyParameter>& keyParams,
+                                 bool wasCreationSuccessful, int32_t errorCode) {
+    AuthorizationSet authorization_set(keyParams);
+    authorization_set.Deduplicate();
+
+    android::util::stats_write(android::util::KEYSTORE_KEY_EVENT_REPORTED,
+                               getEnumTagValue(authorization_set, TAG_ALGORITHM),
+                               getEnumTagValue(authorization_set, TAG_KEY_SIZE),
+                               getEnumTagValue(authorization_set, TAG_ORIGIN),
+                               getEnumTagValue(authorization_set, TAG_USER_AUTH_TYPE),
+                               getEnumTagValue(authorization_set, TAG_AUTH_TIMEOUT),
+                               generateBitMapForPaddingModeValues(authorization_set),
+                               generateBitMapForDigestValues(authorization_set),
+                               generateBitMapForBlockModeValues(authorization_set),
+                               generateBitMapForKeyPurposeValues(authorization_set),
+                               getEnumTagValue(authorization_set, TAG_EC_CURVE),
+                               getEnumTagValue(authorization_set, TAG_BLOB_USAGE_REQUIREMENTS),
+                               android::util::KEYSTORE_KEY_EVENT_REPORTED__TYPE__KEY_CREATION,
+                               wasCreationSuccessful, errorCode);
+}
+
+}  // namespace keystore
diff --git a/keystore/key_creation_log_handler.h b/keystore/key_creation_log_handler.h
new file mode 100644
index 0000000..a314eb1
--- /dev/null
+++ b/keystore/key_creation_log_handler.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef KEY_CREATION_LOG_HANDLER_H_
+#define KEY_CREATION_LOG_HANDLER_H_
+
+#include <keystore/keystore_hidl_support.h>
+
+namespace keystore {
+
+/**
+ * Following enums are defined as a part of the workaround to log the repeated
+ * values of ENUM_REP type. The workaround is to represent the repeated values
+ * of ENUM_REP type as a bitmap and the following enums define their positions
+ * in the bitmap.
+ */
+
+enum PaddingModeBitPosition : int32_t {
+    RSA_OAEP_BIT_POS = 1,
+    RSA_PSS_BIT_POS = 2,
+    RSA_PKCS1_1_5_ENCRYPT_BIT_POS = 3,
+    RSA_PKCS1_1_5_SIGN_BIT_POS = 4,
+    PKCS7_BIT_POS = 5,
+};
+
+enum DigestBitPosition : int32_t {
+    MD5_BIT_POS = 1,
+    SHA1_BIT_POS = 2,
+    SHA_2_224_BIT_POS = 3,
+    SHA_2_256_BIT_POS = 4,
+    SHA_2_384_BIT_POS = 5,
+    SHA_2_512_BIT_POS = 6,
+};
+
+enum BlockModeBitPosition : int32_t {
+    ECB_BIT_POS = 1,
+    CBC_BIT_POS = 2,
+    CTR_BIT_POS = 3,
+    GCM_BIT_POS = 4,
+};
+
+enum KeyPurposeBitPosition : int32_t {
+    ENCRYPT_BIT_POS = 1,
+    DECRYPT_BIT_POS = 2,
+    SIGN_BIT_POS = 3,
+    VERIFY_BIT_POS = 4,
+    WRAP_KEY_BIT_POS = 5,
+};
+
+// None is an enum value for digest and a deprecated value for padding mode
+const int32_t NONE_BIT_POS = 0;
+
+void logKeystoreKeyCreationEvent(const hidl_vec<KeyParameter>& keyParams,
+                                 bool wasCreationSuccessful, int32_t errorCode);
+
+}  // namespace keystore
+
+#endif  // KEY_CREATION_LOG_HANDLER_H_
diff --git a/keystore/key_proto_handler.cpp b/keystore/key_proto_handler.cpp
deleted file mode 100644
index f8400af..0000000
--- a/keystore/key_proto_handler.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-#define LOG_TAG "KeystoreOperation"
-
-#include "key_proto_handler.h"
-
-#include <android/os/DropBoxManager.h>
-#include <google/protobuf/message_lite.h>
-#include <keymasterV4_1/Keymaster.h>
-#include <keystore/keymaster_types.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-
-#include "key_config.pb.h"
-
-namespace keystore {
-
-void checkEnforcedCharacteristics(const hidl_vec<KeyParameter>& keyParams, KeyConfig* keyConfig) {
-    for (auto& keyParam : keyParams) {
-        switch (keyParam.tag) {
-        case Tag::PURPOSE:
-            keyConfig->add_purpose(toString(accessTagValue(TAG_PURPOSE, keyParam)));
-            break;
-        case Tag::ALGORITHM:
-            keyConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, keyParam)));
-            break;
-        case Tag::KEY_SIZE:
-            keyConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, keyParam));
-            break;
-        case Tag::BLOCK_MODE:
-            keyConfig->add_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, keyParam)));
-            break;
-        case Tag::PADDING:
-            keyConfig->add_padding(toString(accessTagValue(TAG_PADDING, keyParam)));
-            break;
-        case Tag::DIGEST:
-            keyConfig->add_digest(toString(accessTagValue(TAG_DIGEST, keyParam)));
-            break;
-        case Tag::EC_CURVE:
-            keyConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, keyParam)));
-            break;
-        case Tag::AUTH_TIMEOUT:
-            keyConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, keyParam));
-            break;
-        case Tag::ORIGIN:
-            keyConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, keyParam)));
-            break;
-        case Tag::BLOB_USAGE_REQUIREMENTS:
-            keyConfig->set_key_blob_usage_reqs(
-                toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, keyParam)));
-            break;
-        case Tag::USER_AUTH_TYPE:
-            keyConfig->set_user_auth_type(toString(accessTagValue(TAG_USER_AUTH_TYPE, keyParam)));
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful) {
-    KeyConfig keyConfig;
-    checkEnforcedCharacteristics(keyParams, &keyConfig);
-    android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
-    keyConfig.set_was_creation_successful(wasCreationSuccessful);
-
-    size_t size = keyConfig.ByteSize();
-    auto data = std::make_unique<uint8_t[]>(size);
-    keyConfig.SerializeWithCachedSizesToArray(data.get());
-    dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
-}
-
-}  // namespace keystore
diff --git a/keystore/key_proto_handler.h b/keystore/key_proto_handler.h
deleted file mode 100644
index a2f6a24..0000000
--- a/keystore/key_proto_handler.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef KEYSTORE_KEY_PROTO_HANDLER_H_
-#define KEYSTORE_KEY_PROTO_HANDLER_H_
-
-#include <keystore/keystore_hidl_support.h>
-
-namespace keystore {
-
-void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams,
-                                     bool wasCreationSuccessful);
-
-}  // namespace keystore
-
-#endif  // KEYSTORE_KEY_PROTO_HANDLER_H_
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index 583f5b6..8501cdf 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -41,7 +41,6 @@
 #include <keymasterV4_0/keymaster_utils.h>
 
 #include "defaults.h"
-#include "key_proto_handler.h"
 #include "keystore_keymaster_enforcement.h"
 #include "keystore_utils.h"
 #include <keystore/keystore_attestation_id.h>
diff --git a/keystore/keymaster_worker.cpp b/keystore/keymaster_worker.cpp
index 911815e..e7fcf96 100644
--- a/keystore/keymaster_worker.cpp
+++ b/keystore/keymaster_worker.cpp
@@ -29,7 +29,7 @@
 #include "KeyStore.h"
 #include "keymaster_enforcement.h"
 
-#include "key_proto_handler.h"
+#include "key_creation_log_handler.h"
 #include "keystore_utils.h"
 
 #include <chrono>
@@ -800,8 +800,10 @@
         // by KeyStore::getFallbackDevice()
         bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
 
-        Finalize logOnFail(
-            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+        Finalize logOnFail([&] {
+            logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
+                                        rc.getErrorCode());
+        });
 
         KeyCharacteristics outCharacteristics;
         KeyStoreServiceReturnCode error;
@@ -870,7 +872,8 @@
 
         // log on success
         logOnFail.release();
-        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+        logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
+                                    error.getErrorCode());
 
         return worker_cb(error, std::move(outCharacteristics));
     });
@@ -904,11 +907,13 @@
         // by KeyStore::getFallbackDevice()
         bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
 
-        Finalize logOnFail(
-            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+        KeyStoreServiceReturnCode error;
+        Finalize logOnFail([&] {
+            logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
+                                        error.getErrorCode());
+        });
 
         KeyCharacteristics outCharacteristics;
-        KeyStoreServiceReturnCode error;
         auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
                            const KeyCharacteristics& keyCharacteristics) {
             keymasterDevice_->logIfKeymasterVendorError(ret);
@@ -975,7 +980,8 @@
 
         // log on success
         logOnFail.release();
-        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+        logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
+                                    error.getErrorCode());
 
         return worker_cb(error, std::move(outCharacteristics));
     });