• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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