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