1 /******************************************************************************
2  *
3  *  Copyright 2020-2023 NXP
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 #define LOG_TAG "weaver-transport-impl"
20 #include <TransportFactory.h>
21 #include <vector>
22 #include <weaver_transport-impl.h>
23 #include <weaver_utils.h>
24 
25 #define MAX_RETRY_COUNT 12
26 #define RETRY_DELAY_INTERVAL_SEC 1
27 #define IS_APPLET_SELECTION_FAILED(resp)                                       \
28   (!resp.empty() && resp[0] == APP_NOT_FOUND_SW1 &&                            \
29    resp[1] == APP_NOT_FOUND_SW2)
30 
31 WeaverTransportImpl *WeaverTransportImpl::s_instance = NULL;
32 std::once_flag WeaverTransportImpl::s_instanceFlag;
33 
34 /* Applet ID to be use for communication */
35 std::vector<std::vector<uint8_t>> kAppletId;
36 
37 /* Interface instance of libese-transport library */
38 static std::unique_ptr<se_transport::TransportFactory> pTransportFactory =
39     nullptr;
40 
41 /**
42  * \brief static inline function to get lib-ese-transport interface instance
43  */
44 static inline std::unique_ptr<se_transport::TransportFactory> &
getTransportFactoryInstance()45 getTransportFactoryInstance() {
46   if (pTransportFactory == nullptr) {
47     pTransportFactory = std::unique_ptr<se_transport::TransportFactory>(
48         new se_transport::TransportFactory(false, kAppletId[0]));
49     pTransportFactory->openConnection();
50   }
51   return pTransportFactory;
52 }
53 
54 /**
55  * \brief static function to get the singleton instance of WeaverTransportImpl
56  * class
57  *
58  * \retval instance of WeaverTransportImpl.
59  */
getInstance()60 WeaverTransportImpl *WeaverTransportImpl::getInstance() {
61   /* call_once c++11 api which executes the passed function ptr exactly once,
62    * even if called concurrently, from several threads
63    */
64   std::call_once(s_instanceFlag, &WeaverTransportImpl::createInstance);
65   return s_instance;
66 }
67 
68 /* Private function to create the instance of self class
69  * Same will be used for std::call_once
70  */
createInstance()71 void WeaverTransportImpl::createInstance() {
72   LOG_D(TAG, "Entry");
73   s_instance = new WeaverTransportImpl;
74   LOG_D(TAG, "Exit");
75 }
76 
77 /**
78  * \brief Function to initialize Weaver Transport Interface
79  *
80  * \param[in]    aid -  applet id to be set to transport interface
81  *
82  * \retval This function return true in case of success
83  *         In case of failure returns false.
84  */
Init(std::vector<std::vector<uint8_t>> aid)85 bool WeaverTransportImpl::Init(std::vector<std::vector<uint8_t>> aid) {
86   LOG_D(TAG, "Entry");
87   kAppletId = std::move(aid);
88   LOG_D(TAG, "Exit");
89   return true;
90 }
91 
92 /**
93  * \brief Function to open applet connection
94  *
95  * \param[in]    data -         command for open applet
96  * \param[out]   resp -         response from applet
97  *
98  * \retval This function return true in case of success
99  *         In case of failure returns false.
100  */
OpenApplet(std::vector<uint8_t> data,std::vector<uint8_t> & resp)101 bool WeaverTransportImpl::OpenApplet(std::vector<uint8_t> data,
102                                      std::vector<uint8_t> &resp) {
103   LOG_D(TAG, "Entry");
104   bool status = true;
105   UNUSED(data);
106   UNUSED(resp);
107   // Since libese_transport opens channel as part of send only so open applet is
108   // not required
109   LOG_D(TAG, "Exit");
110   return status;
111 }
112 
113 /**
114  * \brief Function to close applet connection
115  *
116  * \retval This function return true in case of success
117  *         In case of failure returns false.
118  */
CloseApplet()119 bool WeaverTransportImpl::CloseApplet() {
120   LOG_D(TAG, "Entry");
121   // Close the Applet Channel if opened
122   bool status = getTransportFactoryInstance()->closeConnection();
123   LOG_D(TAG, "Exit");
124   return status;
125 }
126 
127 /**
128  * \brief Private wrapper function to send apdu.
129  * It will try with alternate aids if sending is failed.
130  *
131  * \param[in]    data -         command to be send to applet
132  * \param[out]   resp -         response from applet
133  *
134  * \retval This function return true in case of success
135  *         In case of failure returns false.
136  */
sendInternal(std::vector<uint8_t> data,std::vector<uint8_t> & resp)137 bool WeaverTransportImpl::sendInternal(std::vector<uint8_t> data,
138                                        std::vector<uint8_t> &resp) {
139   bool status = false;
140   status =
141       getTransportFactoryInstance()->sendData(data.data(), data.size(), resp);
142   if (!status && IS_APPLET_SELECTION_FAILED(resp)) {
143     LOG_E(TAG, ": send Failed, trying with alternateAids");
144     // If Applet selection failed, try with alternate Aids
145     for (int i = 1; i < kAppletId.size(); i++) {
146       getTransportFactoryInstance()->setAppletAid(kAppletId[i]);
147       status = getTransportFactoryInstance()->sendData(data.data(), data.size(),
148                                                        resp);
149       if (status) {
150         return status;
151       }
152     }
153     if (!status) {
154       // None of alternate Aids success, Revert back to primary AID
155       getTransportFactoryInstance()->setAppletAid(kAppletId[0]);
156     }
157   }
158   return status;
159 }
160 
161 /**
162  * \brief Function to send commands to applet
163  *
164  * \param[in]    data -         command to be send to applet
165  * \param[out]   resp -         response from applet
166  *
167  * \retval This function return true in case of success
168  *         In case of failure returns false.
169  */
Send(std::vector<uint8_t> data,std::vector<uint8_t> & resp)170 bool WeaverTransportImpl::Send(std::vector<uint8_t> data,
171                                std::vector<uint8_t> &resp) {
172   LOG_D(TAG, "Entry");
173   int retry = 1;
174   bool status = false;
175   // Opens the channel with aid and transmit the data
176   do {
177     status = sendInternal(data, resp);
178     if (!status) {
179       if (retry > MAX_RETRY_COUNT) {
180         LOG_E(TAG, ": completed max retries exit failure");
181       } else {
182         sleep(RETRY_DELAY_INTERVAL_SEC);
183         LOG_E(TAG, ": retry  %d/%d", retry, MAX_RETRY_COUNT);
184       }
185     }
186   } while ((!status) && (retry++ <= MAX_RETRY_COUNT));
187   LOG_D(TAG, "Exit");
188   return status;
189 }
190 
191 /**
192  * \brief Function to de-initialize Weaver Transport Interface
193  *
194  * \retval This function return true in case of success
195  *         In case of failure returns false.
196  */
DeInit()197 bool WeaverTransportImpl::DeInit() {
198   LOG_D(TAG, "Entry");
199   bool status = CloseApplet();
200   LOG_D(TAG, "Exit");
201   return status;
202 }
203