1 /*
2 * Copyright 2020, 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 #define LOG_TAG "javacard.strongbox.keymint.operation-impl"
18
19 #include "JavacardKeyMintOperation.h"
20
21 #include <KeyMintUtils.h>
22 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
23 #include <aidl/android/hardware/security/secureclock/ISecureClock.h>
24 #include <android-base/logging.h>
25
26 #include "CborConverter.h"
27
28 namespace aidl::android::hardware::security::keymint {
29 using cppbor::Bstr;
30 using cppbor::Uint;
31 using secureclock::TimeStampToken;
32
~JavacardKeyMintOperation()33 JavacardKeyMintOperation::~JavacardKeyMintOperation() {
34 if (opHandle_ != 0) {
35 JavacardKeyMintOperation::abort();
36 }
37 }
38
updateAad(const vector<uint8_t> & input,const optional<HardwareAuthToken> & authToken,const optional<TimeStampToken> & timestampToken)39 ScopedAStatus JavacardKeyMintOperation::updateAad(const vector<uint8_t>& input,
40 const optional<HardwareAuthToken>& authToken,
41 const optional<TimeStampToken>& timestampToken) {
42 cppbor::Array request;
43 request.add(Uint(opHandle_));
44 request.add(Bstr(input));
45 cbor_.addHardwareAuthToken(request, authToken.value_or(HardwareAuthToken()));
46 cbor_.addTimeStampToken(request, timestampToken.value_or(TimeStampToken()));
47 auto [item, err] = card_->sendRequest(Instruction::INS_UPDATE_AAD_OPERATION_CMD, request);
48 if (err != KM_ERROR_OK) {
49 return km_utils::kmError2ScopedAStatus(err);
50 }
51 return ScopedAStatus::ok();
52 }
53
update(const vector<uint8_t> & input,const optional<HardwareAuthToken> & authToken,const optional<TimeStampToken> & timestampToken,vector<uint8_t> * output)54 ScopedAStatus JavacardKeyMintOperation::update(const vector<uint8_t>& input,
55 const optional<HardwareAuthToken>& authToken,
56 const optional<TimeStampToken>& timestampToken,
57 vector<uint8_t>* output) {
58 HardwareAuthToken aToken = authToken.value_or(HardwareAuthToken());
59 TimeStampToken tToken = timestampToken.value_or(TimeStampToken());
60 DataView view = {.buffer = {}, .data = input, .start = 0, .length = input.size()};
61 keymaster_error_t err = bufferData(view);
62 if (err != KM_ERROR_OK) {
63 return km_utils::kmError2ScopedAStatus(err);
64 }
65 if (!(bufferingMode_ == BufferingMode::EC_NO_DIGEST ||
66 bufferingMode_ == BufferingMode::RSA_DECRYPT_OR_NO_DIGEST)) {
67 if (view.length > MAX_CHUNK_SIZE) {
68 err = updateInChunks(view, aToken, tToken, output);
69 if (err != KM_ERROR_OK) {
70 return km_utils::kmError2ScopedAStatus(err);
71 }
72 }
73 vector<uint8_t> remaining = popNextChunk(view, view.length);
74 err = sendUpdate(remaining, aToken, tToken, *output);
75 }
76 return km_utils::kmError2ScopedAStatus(err);
77 }
78
finish(const optional<vector<uint8_t>> & input,const optional<vector<uint8_t>> & signature,const optional<HardwareAuthToken> & authToken,const optional<TimeStampToken> & timestampToken,const optional<vector<uint8_t>> & confirmationToken,vector<uint8_t> * output)79 ScopedAStatus JavacardKeyMintOperation::finish(const optional<vector<uint8_t>>& input,
80 const optional<vector<uint8_t>>& signature,
81 const optional<HardwareAuthToken>& authToken,
82 const optional<TimeStampToken>& timestampToken,
83 const optional<vector<uint8_t>>& confirmationToken,
84 vector<uint8_t>* output) {
85 HardwareAuthToken aToken = authToken.value_or(HardwareAuthToken());
86 TimeStampToken tToken = timestampToken.value_or(TimeStampToken());
87 const vector<uint8_t> confToken = confirmationToken.value_or(vector<uint8_t>());
88 const vector<uint8_t> inData = input.value_or(vector<uint8_t>());
89 DataView view = {.buffer = {}, .data = inData, .start = 0, .length = inData.size()};
90 const vector<uint8_t> sign = signature.value_or(vector<uint8_t>());
91 if (!(bufferingMode_ == BufferingMode::EC_NO_DIGEST ||
92 bufferingMode_ == BufferingMode::RSA_DECRYPT_OR_NO_DIGEST)) {
93 appendBufferedData(view);
94 if (view.length > MAX_CHUNK_SIZE) {
95 auto err = updateInChunks(view, aToken, tToken, output);
96 if (err != KM_ERROR_OK) {
97 return km_utils::kmError2ScopedAStatus(err);
98 }
99 }
100 } else {
101 keymaster_error_t err = bufferData(view);
102 if (err != KM_ERROR_OK) {
103 return km_utils::kmError2ScopedAStatus(err);
104 }
105 appendBufferedData(view);
106 }
107 vector<uint8_t> remaining = popNextChunk(view, view.length);
108 return km_utils::kmError2ScopedAStatus(
109 sendFinish(remaining, sign, aToken, tToken, confToken, *output));
110 }
111
abort()112 ScopedAStatus JavacardKeyMintOperation::abort() {
113 Array request;
114 request.add(Uint(opHandle_));
115 auto [item, err] = card_->sendRequest(Instruction::INS_ABORT_OPERATION_CMD, request);
116 opHandle_ = 0;
117 buffer_.clear();
118 return km_utils::kmError2ScopedAStatus(err);
119 }
120
blockAlign(DataView & view,uint16_t blockSize)121 void JavacardKeyMintOperation::blockAlign(DataView& view, uint16_t blockSize) {
122 appendBufferedData(view);
123 uint16_t offset = getDataViewOffset(view, blockSize);
124 if (view.buffer.empty() && !view.data.empty()) {
125 buffer_.insert(buffer_.end(), view.data.begin() + offset, view.data.end());
126 } else if (view.data.empty() && !view.buffer.empty()) {
127 buffer_.insert(buffer_.end(), view.buffer.begin() + offset, view.buffer.end());
128 } else {
129 if (offset < view.buffer.size()) {
130 buffer_.insert(buffer_.end(), view.buffer.begin() + offset, view.buffer.end());
131 buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
132 } else {
133 offset = offset - view.buffer.size();
134 buffer_.insert(buffer_.end(), view.data.begin() + offset, view.data.end());
135 }
136 }
137 // adjust the view length by removing the buffered data size from it.
138 view.length = view.length - buffer_.size();
139 }
140
getDataViewOffset(DataView & view,uint16_t blockSize)141 uint16_t JavacardKeyMintOperation::getDataViewOffset(DataView& view, uint16_t blockSize) {
142 uint16_t offset = 0;
143 uint16_t remaining = 0;
144 switch (bufferingMode_) {
145 case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED:
146 case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED:
147 offset = ((view.length / blockSize)) * blockSize;
148 remaining = (view.length % blockSize);
149 if (offset >= blockSize && remaining == 0) {
150 offset -= blockSize;
151 }
152 break;
153 case BufferingMode::BUF_DES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
154 case BufferingMode::BUF_AES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
155 offset = ((view.length / blockSize)) * blockSize;
156 break;
157 case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED:
158 if (view.length > macLength_) {
159 offset = (view.length - macLength_);
160 }
161 break;
162 default:
163 break;
164 }
165 return offset;
166 }
167
bufferData(DataView & view)168 keymaster_error_t JavacardKeyMintOperation::bufferData(DataView& view) {
169 if (view.data.empty()) return KM_ERROR_OK; // nothing to buffer
170 switch (bufferingMode_) {
171 case BufferingMode::RSA_DECRYPT_OR_NO_DIGEST:
172 buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
173 if (buffer_.size() > RSA_BUFFER_SIZE) {
174 abort();
175 return KM_ERROR_INVALID_INPUT_LENGTH;
176 }
177 view.start = 0;
178 view.length = 0;
179 break;
180 case BufferingMode::EC_NO_DIGEST:
181 if (buffer_.size() < EC_BUFFER_SIZE) {
182 buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
183 // Truncate the buffered data if greater then allowed EC buffer size.
184 if (buffer_.size() > EC_BUFFER_SIZE) {
185 buffer_.erase(buffer_.begin() + EC_BUFFER_SIZE, buffer_.end());
186 }
187 }
188 view.start = 0;
189 view.length = 0;
190 break;
191 case BufferingMode::BUF_AES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
192 case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED:
193 blockAlign(view, AES_BLOCK_SIZE);
194 break;
195 case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED:
196 blockAlign(view, macLength_);
197 break;
198 case BufferingMode::BUF_DES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
199 case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED:
200 blockAlign(view, DES_BLOCK_SIZE);
201 break;
202 case BufferingMode::NONE:
203 break;
204 }
205 return KM_ERROR_OK;
206 }
207
208 // Incrementally send the request using multiple updates.
updateInChunks(DataView & view,HardwareAuthToken & authToken,TimeStampToken & timestampToken,vector<uint8_t> * output)209 keymaster_error_t JavacardKeyMintOperation::updateInChunks(DataView& view,
210 HardwareAuthToken& authToken,
211 TimeStampToken& timestampToken,
212 vector<uint8_t>* output) {
213 keymaster_error_t sendError = KM_ERROR_UNKNOWN_ERROR;
214 while (view.length > MAX_CHUNK_SIZE) {
215 vector<uint8_t> chunk = popNextChunk(view, MAX_CHUNK_SIZE);
216 sendError = sendUpdate(chunk, authToken, timestampToken, *output);
217 if (sendError != KM_ERROR_OK) {
218 return sendError;
219 }
220 // Clear tokens
221 if (!authToken.mac.empty()) authToken = HardwareAuthToken();
222 if (!timestampToken.mac.empty()) timestampToken = TimeStampToken();
223 }
224 return KM_ERROR_OK;
225 }
226
popNextChunk(DataView & view,uint32_t chunkSize)227 vector<uint8_t> JavacardKeyMintOperation::popNextChunk(DataView& view, uint32_t chunkSize) {
228 uint32_t start = view.start;
229 uint32_t end = start + ((view.length < chunkSize) ? view.length : chunkSize);
230 vector<uint8_t> chunk;
231 if (start < view.buffer.size()) {
232 if (end < view.buffer.size()) {
233 chunk = {view.buffer.begin() + start, view.buffer.begin() + end};
234 } else {
235 end = end - view.buffer.size();
236 chunk = {view.buffer.begin() + start, view.buffer.end()};
237 chunk.insert(chunk.end(), view.data.begin(), view.data.begin() + end);
238 }
239 } else {
240 start = start - view.buffer.size();
241 end = end - view.buffer.size();
242 chunk = {view.data.begin() + start, view.data.begin() + end};
243 }
244 view.start = view.start + chunk.size();
245 view.length = view.length - chunk.size();
246 return chunk;
247 }
248
sendUpdate(const vector<uint8_t> & input,const HardwareAuthToken & authToken,const TimeStampToken & timestampToken,vector<uint8_t> & output)249 keymaster_error_t JavacardKeyMintOperation::sendUpdate(const vector<uint8_t>& input,
250 const HardwareAuthToken& authToken,
251 const TimeStampToken& timestampToken,
252 vector<uint8_t>& output) {
253 if (input.empty()) {
254 return KM_ERROR_OK;
255 }
256 cppbor::Array request;
257 request.add(Uint(opHandle_));
258 request.add(Bstr(input));
259 cbor_.addHardwareAuthToken(request, authToken);
260 cbor_.addTimeStampToken(request, timestampToken);
261 auto [item, error] = card_->sendRequest(Instruction::INS_UPDATE_OPERATION_CMD, request);
262 if (error != KM_ERROR_OK) {
263 return error;
264 }
265 auto optTemp = cbor_.getByteArrayVec(item, 1);
266 if (!optTemp) {
267 return KM_ERROR_UNKNOWN_ERROR;
268 }
269 output.insert(output.end(), optTemp.value().begin(), optTemp.value().end());
270 return KM_ERROR_OK;
271 }
272
sendFinish(const vector<uint8_t> & data,const vector<uint8_t> & sign,const HardwareAuthToken & authToken,const TimeStampToken & timestampToken,const vector<uint8_t> & confToken,vector<uint8_t> & output)273 keymaster_error_t JavacardKeyMintOperation::sendFinish(const vector<uint8_t>& data,
274 const vector<uint8_t>& sign,
275 const HardwareAuthToken& authToken,
276 const TimeStampToken& timestampToken,
277 const vector<uint8_t>& confToken,
278 vector<uint8_t>& output) {
279 cppbor::Array request;
280 request.add(Uint(opHandle_));
281 request.add(Bstr(data));
282 request.add(Bstr(sign));
283 cbor_.addHardwareAuthToken(request, authToken);
284 cbor_.addTimeStampToken(request, timestampToken);
285 request.add(Bstr(confToken));
286
287 auto [item, err] = card_->sendRequest(Instruction::INS_FINISH_OPERATION_CMD, request);
288 if (err != KM_ERROR_OK) {
289 return err;
290 }
291 auto optTemp = cbor_.getByteArrayVec(item, 1);
292 if (!optTemp) {
293 return KM_ERROR_UNKNOWN_ERROR;
294 }
295 opHandle_ = 0;
296 output.insert(output.end(), optTemp.value().begin(), optTemp.value().end());
297 return KM_ERROR_OK;
298 }
299
300 } // namespace aidl::android::hardware::security::keymint
301