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