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