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