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