1 /*
2 * Copyright 2021, 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
17 #include <trusty_keymaster/TrustyKeyMintOperation.h>
18
19 #define TAG TrustyKeyMintOperation
20 #include <android-base/logging.h>
21
22 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
23 #include <aidl/android/hardware/security/secureclock/ISecureClock.h>
24
25 #include <KeyMintUtils.h>
26 #include <keymaster/android_keymaster.h>
27 #include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
28
29 namespace aidl::android::hardware::security::keymint {
30
31 using ::keymaster::AbortOperationRequest;
32 using ::keymaster::AbortOperationResponse;
33 using ::keymaster::FinishOperationRequest;
34 using ::keymaster::FinishOperationResponse;
35 using ::keymaster::TAG_ASSOCIATED_DATA;
36 using ::keymaster::TAG_AUTH_TOKEN;
37 using ::keymaster::TAG_CONFIRMATION_TOKEN;
38 using ::keymaster::UpdateOperationRequest;
39 using ::keymaster::UpdateOperationResponse;
40 using km_utils::authToken2AidlVec;
41 using km_utils::kmError2ScopedAStatus;
42 using secureclock::TimeStampToken;
43
TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,keymaster_operation_handle_t opHandle)44 TrustyKeyMintOperation::TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,
45 keymaster_operation_handle_t opHandle)
46 : impl_(std::move(implementation)), opHandle_(opHandle) {}
47
~TrustyKeyMintOperation()48 TrustyKeyMintOperation::~TrustyKeyMintOperation() {
49 if (opHandle_ != 0) {
50 abort();
51 }
52 }
53
updateAad(const vector<uint8_t> & input,const optional<HardwareAuthToken> &,const optional<TimeStampToken> &)54 ScopedAStatus TrustyKeyMintOperation::updateAad(
55 const vector<uint8_t>& input, const optional<HardwareAuthToken>& /* authToken */,
56 const optional<TimeStampToken>& /* timestampToken */) {
57 UpdateOperationRequest request(impl_->message_version());
58 request.op_handle = opHandle_;
59 request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
60
61 UpdateOperationResponse response(impl_->message_version());
62 impl_->UpdateOperation(request, &response);
63
64 return kmError2ScopedAStatus(response.error);
65 }
66
update(const vector<uint8_t> & input,const optional<HardwareAuthToken> & authToken,const optional<TimeStampToken> &,vector<uint8_t> * output)67 ScopedAStatus TrustyKeyMintOperation::update(const vector<uint8_t>& input,
68 const optional<HardwareAuthToken>& authToken,
69 const optional<TimeStampToken>& /* timestampToken */,
70 vector<uint8_t>* output) {
71 if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
72
73 UpdateOperationRequest request(impl_->message_version());
74 request.op_handle = opHandle_;
75 if (authToken) {
76 auto tokenAsVec(authToken2AidlVec(*authToken));
77 request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
78 }
79
80 size_t serialized_size = request.SerializedSize();
81 if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
82 return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
83 }
84
85 const uint8_t* input_pos = input.data();
86 const uint8_t* input_end = input.data() + input.size();
87 const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
88 output->clear();
89
90 while (input_pos < input_end) {
91 size_t to_send = std::min(max_chunk_size, static_cast<size_t>(input_end - input_pos));
92 LOG(DEBUG) << "update: Sending " << to_send << " of " << (input_end - input_pos)
93 << " bytes";
94 request.input.Reinitialize(input_pos, to_send);
95
96 UpdateOperationResponse response(impl_->message_version());
97 impl_->UpdateOperation(request, &response);
98 if (response.error != KM_ERROR_OK) {
99 opHandle_ = 0; // Operation has ended, the handle is invalid. This saves an abort().
100 return kmError2ScopedAStatus(response.error);
101 }
102
103 input_pos += response.input_consumed;
104 output->insert(output->end(), response.output.begin(), response.output.end());
105 }
106
107 return ScopedAStatus::ok();
108 }
109
finish(const optional<vector<uint8_t>> & input,const optional<vector<uint8_t>> & signature,const optional<HardwareAuthToken> & authToken,const optional<TimeStampToken> &,const optional<vector<uint8_t>> & confirmationToken,vector<uint8_t> * output)110 ScopedAStatus TrustyKeyMintOperation::finish(const optional<vector<uint8_t>>& input, //
111 const optional<vector<uint8_t>>& signature, //
112 const optional<HardwareAuthToken>& authToken,
113 const optional<TimeStampToken>& /* timestampToken */,
114 const optional<vector<uint8_t>>& confirmationToken,
115 vector<uint8_t>* output) {
116 if (!output) {
117 return ScopedAStatus(AStatus_fromServiceSpecificError(
118 static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
119 }
120 output->clear();
121
122 FinishOperationRequest request(impl_->message_version());
123
124 if (authToken) {
125 auto tokenAsVec(authToken2AidlVec(*authToken));
126 request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
127 }
128 if (confirmationToken) {
129 request.additional_params.push_back(TAG_CONFIRMATION_TOKEN, confirmationToken->data(),
130 confirmationToken->size());
131 }
132
133 request.op_handle = opHandle_;
134 if (signature) request.signature.Reinitialize(signature->data(), signature->size());
135 size_t serialized_size = request.SerializedSize();
136 if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
137 return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
138 }
139
140 if (input) {
141 const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
142
143 if (input->size() > max_chunk_size) {
144 LOG(DEBUG) << "Sending an update to process finish() data";
145 // Use update to process all but the last max_chunk_size bytes.
146 auto result = update({input->begin(), input->end() - max_chunk_size}, authToken,
147 std::nullopt /* timestampToken */, output);
148 if (!result.isOk()) return result;
149
150 // Process the last max_chunk_size with finish.
151 request.input.Reinitialize(input->data() + (input->size() - max_chunk_size),
152 max_chunk_size);
153 } else {
154 request.input.Reinitialize(input->data(), input->size());
155 }
156 }
157
158 FinishOperationResponse response(impl_->message_version());
159 impl_->FinishOperation(request, &response);
160 opHandle_ = 0;
161
162 if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
163
164 *output = {response.output.begin(), response.output.end()};
165 return ScopedAStatus::ok();
166 }
167
abort()168 ScopedAStatus TrustyKeyMintOperation::abort() {
169 AbortOperationRequest request(impl_->message_version());
170 request.op_handle = opHandle_;
171
172 AbortOperationResponse response(impl_->message_version());
173 impl_->AbortOperation(request, &response);
174 opHandle_ = 0;
175
176 return kmError2ScopedAStatus(response.error);
177 }
178
179 } // namespace aidl::android::hardware::security::keymint
180