1 /*
2 **
3 ** Copyright 2020, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 /******************************************************************************
18 **
19 ** The original Work has been changed by NXP.
20 **
21 ** Licensed under the Apache License, Version 2.0 (the "License");
22 ** you may not use this file except in compliance with the License.
23 ** You may obtain a copy of the License at
24 **
25 ** http://www.apache.org/licenses/LICENSE-2.0
26 **
27 ** Unless required by applicable law or agreed to in writing, software
28 ** distributed under the License is distributed on an "AS IS" BASIS,
29 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 ** See the License for the specific language governing permissions and
31 ** limitations under the License.
32 **
33 ** Copyright 2022-2023 NXP
34 **
35 *********************************************************************************/
36 #define LOG_TAG "OmapiTransport"
37 #if defined OMAPI_TRANSPORT
38 #include "OmapiTransport.h"
39
40 #include <arpa/inet.h>
41 #include <iomanip>
42 #include <map>
43 #include <stdio.h>
44 #include <string.h>
45 #include <sys/socket.h>
46 #include <unistd.h>
47 #include <vector>
48
49 #include <android-base/logging.h>
50 #include <android-base/stringprintf.h>
51 #include <hardware_legacy/power.h>
52
53 #include <EseTransportUtils.h>
54 #include <IntervalTimer.h>
55
56 #define UNUSED_V(a) a=a
57 #define RESP_CHANNEL_NOT_AVAILABLE 0x6881
58 #ifdef NXP_EXTNS
59 #define DEFAULT_SESSION_TIMEOUT_MSEC 1000
60 #endif
61
62 using android::base::StringPrintf;
63
64 namespace keymint::javacard {
65
66 std::string const ESE_READER_PREFIX = "eSE";
67 constexpr const char omapiServiceName[] = "android.se.omapi.ISecureElementService/default";
68 constexpr const char kChannelWakelockName[] = "nxp_keymint_channel";
69
70 class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
71
72 #ifdef NXP_EXTNS
73
74 static std::mutex sCookiesMutex;
75 static uintptr_t sCookiesKeyCounter = 0;
76 static std::map<uintptr_t, std::weak_ptr<OmapiTransport>> sCookies;
77
omapiSessionTimerFunc(union sigval arg)78 void omapiSessionTimerFunc(union sigval arg){
79 LOG(INFO) << "Session Timer expired !!";
80 OmapiTransport *obj = (OmapiTransport*)arg.sival_ptr;
81 if(obj != nullptr)
82 obj->closeChannel();
83 }
84
BinderDiedCallback(void * cookie)85 void OmapiTransport::BinderDiedCallback(void *cookie) {
86 std::shared_ptr<OmapiTransport> transport = nullptr;
87 {
88 std::lock_guard lock(sCookiesMutex);
89 if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie));
90 it != sCookies.end()) {
91 LOG(ERROR)
92 << "Received binder died with cookie: " << cookie
93 << ". OMAPI Service died, closing connection";
94 transport = it->second.lock();
95 } else {
96 LOG(ERROR)
97 << "Received binder died with cookie: " << cookie
98 << ". OMAPI Service died, but no OmapiTransport.";
99 }
100 }
101 if (transport) {
102 transport->closeConnection();
103 }
104 }
105 #endif
106
~OmapiTransport()107 OmapiTransport::~OmapiTransport() {
108 #ifdef NXP_EXTNS
109 std::lock_guard sLock(sCookiesMutex);
110 std::lock_guard mLock(mCookieKeysMutex);
111 for (auto cookie : mCookieKeys) {
112 LOG(INFO) << "OmapiTransport destructor cleaning up death recipient cookie("
113 << cookie << ") as we no longer need to listen for service death.";
114 sCookies.erase(cookie);
115 }
116 #endif
117 }
118
initialize()119 bool OmapiTransport::initialize() {
120 LOG(DEBUG) << "Initialize the secure element connection";
121
122 // Get OMAPI vendor stable service handler
123 #ifdef NXP_EXTNS
124 ::ndk::SpAIBinder ks2Binder(AServiceManager_checkService(omapiServiceName));
125 omapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
126 #else
127 ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(omapiServiceName));
128 omapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
129 #endif
130
131 if (omapiSeService == nullptr) {
132 LOG(ERROR) << "Failed to start omapiSeService null";
133 return false;
134 }
135
136 #ifdef NXP_EXTNS
137 {
138 std::lock_guard sLock(sCookiesMutex);
139 uintptr_t cookieKey = sCookiesKeyCounter++;
140 std::lock_guard mLock(mCookieKeysMutex);
141 mCookieKeys.push_back(cookieKey);
142 sCookies[cookieKey] = shared_from_this();
143 LOG(INFO) << "linkToDeath on OMAPI service with cookie: " << cookieKey;
144 AIBinder_linkToDeath(omapiSeService->asBinder().get(),
145 mDeathRecipient.get(),
146 reinterpret_cast<void *>(cookieKey));
147 }
148 #endif
149
150 // reset readers, clear readers if already existing
151 if (mVSReaders.size() > 0) {
152 closeConnection();
153 }
154
155 std::vector<std::string> readers = {};
156 // Get available readers
157 auto status = omapiSeService->getReaders(&readers);
158 if (!status.isOk()) {
159 LOG(ERROR) << "getReaders failed to get available readers: " << status.getMessage();
160 return false;
161 }
162
163 // Get SE readers handlers
164 for (auto & readerName : readers) {
165 std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
166 status = omapiSeService->getReader(readerName, &reader);
167 if (!status.isOk()) {
168 LOG(ERROR) << "getReader for " << readerName.c_str() << " Failed: "
169 << status.getMessage();
170 return false;
171 }
172
173 mVSReaders[readerName] = std::move(reader);
174 }
175
176 // Find eSE reader, as of now assumption is only eSE available on device
177 LOG(DEBUG) << "Finding eSE reader";
178 eSEReader = nullptr;
179 if (mVSReaders.size() > 0) {
180 for (const auto& [name, reader] : mVSReaders) {
181 if (name.find(ESE_READER_PREFIX, 0) != std::string::npos) {
182 LOG(DEBUG) << "eSE reader found: " << name;
183 eSEReader = reader;
184 #ifdef NXP_EXTNS
185 std::string prefTerminalName = "eSE1";
186 if (name.compare(prefTerminalName) == 0x00 ) {
187 LOG(DEBUG) << "Found reader "<< prefTerminalName << " breaking.";
188 break;
189 }
190 #endif
191 }
192 }
193 }
194
195 if (eSEReader == nullptr) {
196 LOG(ERROR) << "secure element reader " << ESE_READER_PREFIX << " not found";
197 return false;
198 }
199
200 return true;
201 }
202
internalTransmitApdu(std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,std::vector<uint8_t> apdu,std::vector<uint8_t> & transmitResponse)203 bool OmapiTransport::internalTransmitApdu(
204 std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
205 std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
206 auto mSEListener = ndk::SharedRefBase::make<SEListener>();
207 LOG(DEBUG) << "internalTransmitApdu: trasmitting data to secure element";
208
209 if (reader == nullptr) {
210 LOG(ERROR) << "eSE reader is null";
211 return false;
212 }
213
214 bool status = false;
215 auto res = reader->isSecureElementPresent(&status);
216 if (!res.isOk()) {
217 LOG(ERROR) << "isSecureElementPresent error: " << res.getMessage();
218 return false;
219 }
220 if (!status) {
221 LOG(ERROR) << "secure element not found";
222 return false;
223 }
224
225 res = reader->openSession(&session);
226 if (!res.isOk()) {
227 LOG(ERROR) << "openSession error: " << res.getMessage();
228 return false;
229 }
230 if (session == nullptr) {
231 LOG(ERROR) << "Could not open session null";
232 return false;
233 }
234
235 res = session->openLogicalChannel(mSelectableAid, 0x00, mSEListener, &channel);
236 if (!res.isOk()) {
237 LOG(ERROR) << "openLogicalChannel error: " << res.getMessage();
238 return false;
239 }
240 if (channel == nullptr) {
241 LOG(ERROR) << "Could not open channel null";
242 return false;
243 }
244
245 std::vector<uint8_t> selectResponse = {};
246 res = channel->getSelectResponse(&selectResponse);
247 if (!res.isOk()) {
248 LOG(ERROR) << "getSelectResponse error: " << res.getMessage();
249 return false;
250 }
251
252 if ((selectResponse.size() < 2) ||
253 ((selectResponse[selectResponse.size() -1] & 0xFF) != 0x00) ||
254 ((selectResponse[selectResponse.size() -2] & 0xFF) != 0x90)) {
255 LOG(ERROR) << "Failed to select the Applet.";
256 return false;
257 }
258
259 res = channel->transmit(apdu, &transmitResponse);
260 if (channel != nullptr) channel->close();
261 if (session != nullptr) session->close();
262
263 LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode() << " Message: "
264 << res.getMessage();
265 if (!res.isOk()) {
266 LOG(ERROR) << "transmit error: " << res.getMessage();
267 return false;
268 }
269
270 return true;
271 }
272
openConnection()273 bool OmapiTransport::openConnection() {
274 // if already conection setup done, no need to initialise it again.
275 if (isConnected()) {
276 return true;
277 }
278
279 return initialize();
280 }
281
sendData(const vector<uint8_t> & inData,vector<uint8_t> & output)282 bool OmapiTransport::sendData(const vector<uint8_t>& inData, vector<uint8_t>& output) {
283 std::vector<uint8_t> apdu(inData);
284 #ifdef INTERVAL_TIMER
285 LOGD_OMAPI("stop the timer");
286 mTimer.kill();
287 #endif
288 if (!isConnected()) {
289 // Try to initialize connection to eSE
290 LOG(INFO) << "Failed to send data, try to initialize connection SE connection";
291 if (!initialize()) {
292 LOG(ERROR) << "Failed to send data, initialization not completed";
293 closeConnection();
294 return false;
295 }
296 }
297
298 if (inData.size() == 0x00) {
299 LOG(ERROR) << "Failed to send data, APDU is null";
300 return false;
301 }
302
303 if (eSEReader != nullptr) {
304 LOG(DEBUG) << "Sending apdu data to secure element: " << ESE_READER_PREFIX;
305 acquire_wake_lock(PARTIAL_WAKE_LOCK, kChannelWakelockName);
306 #ifdef NXP_EXTNS
307 bool status = internalProtectedTransmitApdu(eSEReader, std::move(apdu), output);
308 #else
309 bool status = internalTransmitApdu(eSEReader, apdu, output);
310 #endif
311 release_wake_lock(kChannelWakelockName);
312 return status;
313 } else {
314 LOG(ERROR) << "secure element reader " << ESE_READER_PREFIX << " not found";
315 return false;
316 }
317 }
318
closeConnection()319 bool OmapiTransport::closeConnection() {
320 LOG(DEBUG) << "Closing all connections";
321 if (omapiSeService != nullptr) {
322 if (mVSReaders.size() > 0) {
323 for (const auto& [name, reader] : mVSReaders) {
324 reader->closeSessions();
325 }
326 mVSReaders.clear();
327 }
328 }
329 #ifdef NXP_EXTNS
330 if (omapiSeService != nullptr) {
331 std::lock_guard sLock(sCookiesMutex);
332 std::lock_guard mLock(mCookieKeysMutex);
333 for (auto cookie : mCookieKeys) {
334 LOG(INFO) << "unlinkToDeath on OMAPI service with cookie: " << cookie;
335 AIBinder_unlinkToDeath(omapiSeService->asBinder().get(),
336 mDeathRecipient.get(),
337 reinterpret_cast<void *>(cookie));
338 sCookies.erase(cookie);
339 }
340 mCookieKeys.clear();
341 omapiSeService = nullptr;
342 }
343 session = nullptr;
344 channel = nullptr;
345 #endif
346 return true;
347 }
348
isConnected()349 bool OmapiTransport::isConnected() {
350 // Check already initialization completed or not
351 if (omapiSeService != nullptr && eSEReader != nullptr) {
352 LOG(DEBUG) << "Connection initialization already completed";
353 return true;
354 }
355
356 LOG(DEBUG) << "Connection initialization not completed";
357 return false;
358 }
359
360 #ifdef NXP_EXTNS
361
setDefaultTimeout(int timeout)362 void OmapiTransport::setDefaultTimeout(int timeout) {
363 if (mTimeout != timeout) {
364 mTimeout = timeout;
365 }
366 }
367
internalProtectedTransmitApdu(std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,std::vector<uint8_t> apdu,std::vector<uint8_t> & transmitResponse)368 bool OmapiTransport::internalProtectedTransmitApdu(
369 std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
370 std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
371 //auto mSEListener = std::make_shared<SEListener>();
372 std::vector<uint8_t> selectResponse = {};
373 const std::vector<uint8_t> sbAppletAID = {0xA0, 0x00, 0x00, 0x00, 0x62};
374
375 if (reader == nullptr) {
376 LOG(ERROR) << "eSE reader is null";
377 return false;
378 }
379
380 bool status = false;
381 auto res = reader->isSecureElementPresent(&status);
382 if (!res.isOk()) {
383 LOG(ERROR) << "isSecureElementPresent error: " << res.getMessage();
384 return false;
385 }
386 if (!status) {
387 LOG(ERROR) << "secure element not found";
388 return false;
389 }
390
391 if (session == nullptr || ((session->isClosed(&status).isOk() && status))) {
392 res = reader->openSession(&session);
393 if (!res.isOk()) {
394 LOG(ERROR) << "openSession error: " << res.getMessage();
395 return false;
396 }
397 if (session == nullptr) {
398 LOG(ERROR) << "Could not open session null";
399 return false;
400 }
401 }
402
403 if ((channel == nullptr || (channel->isClosed(&status).isOk() && status))) {
404 if (!mSBAccessController.isOperationAllowed(apdu[APDU_INS_OFFSET])) {
405 LOG(ERROR) << "Select / Command INS not allowed";
406 prepareErrorRepsponse(transmitResponse);
407 return false;
408 }
409
410 if (!openChannelToApplet()) {
411 LOG(ERROR) << "openLogicalChannel error: " << res.getMessage();
412 // Assume Applet selection Fail
413 transmitResponse.push_back(APP_NOT_FOUND_SW1);
414 transmitResponse.push_back(APP_NOT_FOUND_SW2);
415 return false;
416 }
417 if (channel == nullptr) {
418 LOG(ERROR) << "Could not open channel null";
419 return false;
420 }
421
422 res = channel->getSelectResponse(&selectResponse);
423 if (!res.isOk()) {
424 LOG(ERROR) << "getSelectResponse error: " << res.getMessage();
425 return false;
426 }
427 if ((selectResponse.size() < 2)
428 || ((selectResponse[selectResponse.size() -1] & 0xFF) != 0x00)
429 || ((selectResponse[selectResponse.size() -2] & 0xFF) != 0x90))
430 {
431 LOG(ERROR) << "Failed to select the Applet.";
432 return false;
433 }
434 if (sbAppletAID == mSelectableAid) {
435 mSBAccessController.parseResponse(selectResponse);
436 }
437 }
438
439 status = false;
440 if (mSBAccessController.isOperationAllowed(apdu[APDU_INS_OFFSET])) {
441 #ifdef ENABLE_DEBUG_LOG
442 LOGD_OMAPI("constructed apdu: " << apdu);
443 #endif
444 res = channel->transmit(apdu, &transmitResponse);
445 status = true;
446 } else {
447 LOG(ERROR) << "command Ins:" << apdu[APDU_INS_OFFSET] << " not allowed";
448 prepareErrorRepsponse(transmitResponse);
449 }
450 #ifdef INTERVAL_TIMER
451 int timeout = 0x00;
452 if (mTimeout) {
453 timeout = mTimeout;
454 } else {
455 timeout = ((kWeaverAID == mSelectableAid)
456 ? DEFAULT_SESSION_TIMEOUT_MSEC
457 : mSBAccessController.getSessionTimeout());
458 }
459
460 if (timeout == 0 || !res.isOk() ||
461 ((transmitResponse.size() >= 2) &&
462 (getApduStatus(transmitResponse) == RESP_CHANNEL_NOT_AVAILABLE))) {
463 closeChannel(); // close immediately
464 } else {
465 LOGD_OMAPI("Set the timer with timeout " << timeout << " ms");
466 if (!mTimer.set(timeout, this, omapiSessionTimerFunc)) {
467 LOG(ERROR) << "Set Timer Failed !!!";
468 closeChannel();
469 }
470 }
471 #else
472 closeChannel();
473 #endif
474
475 LOGD_OMAPI("STATUS OF TRNSMIT: " << res.getExceptionCode() << " Message: "
476 << res.getMessage());
477 if (!res.isOk()) {
478 LOG(ERROR) << "transmit error: " << res.getMessage();
479 return false;
480 }
481 return status;
482 }
483
prepareErrorRepsponse(std::vector<uint8_t> & resp)484 void OmapiTransport::prepareErrorRepsponse(std::vector<uint8_t>& resp){
485 resp.clear();
486 resp.push_back(0xFF);
487 resp.push_back(0xFF);
488 }
489
closeChannel()490 void OmapiTransport::closeChannel() {
491 if (channel != nullptr)
492 channel->close();
493 LOGD_OMAPI("Channel closed");
494 }
495
openChannelToApplet()496 bool OmapiTransport::openChannelToApplet() {
497 auto mSEListener = ndk::SharedRefBase::make<SEListener>();
498 const std::vector<uint8_t> sbAppletAID = {0xA0, 0x00, 0x00, 0x00, 0x62};
499 uint8_t retry = 0;
500 do {
501 auto res = session->openLogicalChannel(mSelectableAid, 0x00, mSEListener,
502 &channel);
503
504 if ((mSelectableAid == sbAppletAID) &&
505 (!res.isOk() || (channel == nullptr))) {
506 res = session->openLogicalChannel(mSelectableAid, 0x02, mSEListener,
507 &channel);
508 if (!res.isOk() || (channel == nullptr)) {
509 LOG(INFO) << " retry openLogicalChannel after 2 secs";
510 usleep(2 * ONE_SEC);
511 continue;
512 }
513 }
514 return res.isOk();
515 } while (++retry < MAX_RETRY_COUNT);
516
517 return false;
518 }
519
520 #endif
521
522 } // namespace keymint::javacard
523 #endif // OMAPI_TRANSPORT
524