1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "KeystoreOperation"
17
18 #include "operation_proto_handler.h"
19
20 #include <android/os/DropBoxManager.h>
21 #include <google/protobuf/message_lite.h>
22 #include <keymasterV4_1/Keymaster.h>
23 #include <keystore/keymaster_types.h>
24 #include <keystore/keystore_hidl_support.h>
25 #include <utils/String16.h>
26 #include <utils/StrongPointer.h>
27
28 using namespace std::chrono;
29
30 namespace keystore {
31
32 constexpr auto kCollectionTime = 1h;
33
determinePurpose(KeyPurpose purpose,OperationConfig * operationConfig)34 void determinePurpose(KeyPurpose purpose, OperationConfig* operationConfig) {
35 switch (purpose) {
36 case KeyPurpose::VERIFY:
37 operationConfig->set_purpose("verify");
38 break;
39 case KeyPurpose::ENCRYPT:
40 operationConfig->set_purpose("encrypt");
41 break;
42 case KeyPurpose::SIGN:
43 operationConfig->set_purpose("sign");
44 break;
45 case KeyPurpose::DECRYPT:
46 operationConfig->set_purpose("decrypt");
47 break;
48 case KeyPurpose::WRAP_KEY:
49 operationConfig->set_purpose("wrap");
50 break;
51 default:
52 break;
53 }
54 }
55
checkKeyCharacteristics(const hidl_vec<KeyParameter> & characteristics,OperationConfig * operationConfig)56 void checkKeyCharacteristics(const hidl_vec<KeyParameter>& characteristics,
57 OperationConfig* operationConfig) {
58 for (auto& opParam : characteristics) {
59 switch (opParam.tag) {
60 case Tag::ALGORITHM:
61 operationConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, opParam)));
62 break;
63 case Tag::KEY_SIZE:
64 operationConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, opParam));
65 break;
66 case Tag::EC_CURVE:
67 operationConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, opParam)));
68 break;
69 case Tag::AUTH_TIMEOUT:
70 operationConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, opParam));
71 break;
72 case Tag::ORIGIN:
73 operationConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, opParam)));
74 break;
75 case Tag::BLOB_USAGE_REQUIREMENTS:
76 operationConfig->set_key_blob_usage_reqs(
77 toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, opParam)));
78 break;
79 case Tag::USER_AUTH_TYPE:
80 operationConfig->set_user_auth_type(
81 toString(accessTagValue(TAG_USER_AUTH_TYPE, opParam)));
82 break;
83 default:
84 break;
85 }
86 }
87 }
88
checkOpCharacteristics(const hidl_vec<KeyParameter> & characteristics,OperationConfig * operationConfig)89 void checkOpCharacteristics(const hidl_vec<KeyParameter>& characteristics,
90 OperationConfig* operationConfig) {
91 for (auto& opParam : characteristics) {
92 switch (opParam.tag) {
93 case Tag::BLOCK_MODE:
94 operationConfig->set_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, opParam)));
95 break;
96 case Tag::PADDING:
97 operationConfig->set_padding(toString(accessTagValue(TAG_PADDING, opParam)));
98 break;
99 case Tag::DIGEST:
100 operationConfig->set_digest(toString(accessTagValue(TAG_DIGEST, opParam)));
101 break;
102 default:
103 break;
104 }
105 }
106 }
107
uploadOpAsProto(Operation & op,bool wasOpSuccessful)108 void OperationProtoHandler::uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
109 std::lock_guard<std::mutex> lock(op_upload_mutex);
110 OperationConfig operationConfig;
111 determinePurpose(op.purpose, &operationConfig);
112 checkKeyCharacteristics(op.characteristics.softwareEnforced, &operationConfig);
113 checkKeyCharacteristics(op.characteristics.hardwareEnforced, &operationConfig);
114 checkOpCharacteristics(op.params, &operationConfig);
115 operationConfig.set_was_op_successful(wasOpSuccessful);
116 // Only bother with counting an hour out when an operation entry is actually
117 // added
118 if (protoMap.empty()) {
119 start_time = std::chrono::steady_clock::now();
120 }
121 auto cur_time = std::chrono::steady_clock::now();
122
123 // Add operations to a map within the time duration of an hour. Deduplicate
124 // repeated ops by incrementing the counter of the original one stored and
125 // discarding the new one.
126 protoMap[operationConfig.SerializeAsString()]++;
127
128 if (cur_time - start_time >= kCollectionTime) {
129 // Iterate through the unordered map and dump all the operation protos
130 // accumulated over the hour into the holding list proto after setting
131 // their counts.
132 OperationConfigEvents opConfigEvents;
133 for (auto elem : protoMap) {
134 OperationConfigEvent* event = opConfigEvents.add_op_config_events();
135 event->mutable_op_config()->ParseFromString(elem.first);
136 event->set_count(elem.second);
137 }
138 android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
139 size_t size = opConfigEvents.ByteSize();
140 auto data = std::make_unique<uint8_t[]>(size);
141 opConfigEvents.SerializeWithCachedSizesToArray(data.get());
142 dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
143 protoMap.clear();
144 }
145 }
146
147 } // namespace keystore
148