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