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