• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "isodep_card_handler.h"
17 
18 #include "cJSON.h"
19 #include "file_ex.h"
20 #include "loghelper.h"
21 #include "nfc_sdk_common.h"
22 
23 namespace OHOS {
24 namespace NFC {
25 namespace TAG {
IsodepCardHandler(std::weak_ptr<NCI::INciTagInterface> nciTagProxy)26 IsodepCardHandler::IsodepCardHandler(std::weak_ptr<NCI::INciTagInterface> nciTagProxy)
27     : nciTagProxy_(nciTagProxy)
28 {
29     InfoLog("IsodepCardHandler constructor enter.");
30 }
31 
~IsodepCardHandler()32 IsodepCardHandler::~IsodepCardHandler()
33 {
34     InfoLog("IsodepCardHandler destructor enter.");
35 }
36 
InitTransportCardInfo()37 void IsodepCardHandler::InitTransportCardInfo()
38 {
39     if (isInitialized_) {
40         DebugLog("already initialized.");
41         return;
42     }
43     cardInfoVec_.clear();
44     if (DoJsonRead()) {
45         InfoLog("transport card info initialized.");
46         isInitialized_ = true;
47     }
48 }
49 
GetCheckApduFromJson(cJSON * json,cJSON * cardInfoEach,TransportCardInfo * cardInfoList,int index)50 static bool GetCheckApduFromJson(cJSON *json, cJSON *cardInfoEach, TransportCardInfo *cardInfoList, int index)
51 {
52     cJSON *checkApdus = cJSON_GetObjectItemCaseSensitive(cardInfoEach, KEY_APDU_CHECK_APDUS.c_str());
53     if (checkApdus == nullptr || !cJSON_IsArray(checkApdus)) {
54         ErrorLog("json param not array, or has no field \"checkApdus\", index = %{public}d", index);
55         return false;
56     }
57     int checkApduArraySize = cJSON_GetArraySize(checkApdus);
58     if (checkApduArraySize == 0 || checkApduArraySize > MAX_APDU_ARRAY_SIZE) {
59         ErrorLog("illegal array size [%{public}d]", checkApduArraySize);
60         return false;
61     }
62     for (int i = 0; i < checkApduArraySize; ++i) {
63         cJSON *value = cJSON_GetArrayItem(checkApdus, i);
64         if (value == nullptr || !cJSON_IsString(value)) {
65             ErrorLog("json param not string");
66             return false;
67         }
68         cardInfoList[index].checkApdus.push_back(value->valuestring);
69     }
70     return true;
71 }
72 
GetBalanceApduFromJson(cJSON * json,cJSON * cardInfoEach,TransportCardInfo * cardInfoList,int index)73 static bool GetBalanceApduFromJson(cJSON *json, cJSON *cardInfoEach, TransportCardInfo *cardInfoList, int index)
74 {
75     cJSON *balanceApdus = cJSON_GetObjectItemCaseSensitive(cardInfoEach, KEY_APDU_BALANCE_APDUS.c_str());
76     if (balanceApdus == nullptr || !cJSON_IsArray(balanceApdus)) {
77         WarnLog("json param not array, or has no field \"balanceApdus\", index = %{public}d", index);
78     } else {
79         int balanceApduArraySize = cJSON_GetArraySize(balanceApdus);
80         if (balanceApduArraySize == 0 || balanceApduArraySize > MAX_APDU_ARRAY_SIZE) {
81             ErrorLog("illegal array size [%{public}d]", balanceApduArraySize);
82             return false;
83         }
84         for (int i = 0; i < balanceApduArraySize; ++i) {
85             cJSON *value = cJSON_GetArrayItem(balanceApdus, i);
86             if (value == nullptr || !cJSON_IsString(value)) {
87                 ErrorLog("json param not string");
88                 return false;
89             }
90             cardInfoList[index].balanceApdus.push_back(value->valuestring);
91         }
92     }
93     return true;
94 }
95 
GetEachCardInfoFromJson(cJSON * json,cJSON * cardInfo,TransportCardInfo * cardInfoList,size_t cardInfoListLen)96 static bool GetEachCardInfoFromJson(cJSON *json, cJSON *cardInfo,
97                                     TransportCardInfo *cardInfoList, size_t cardInfoListLen)
98 {
99     cJSON *cardInfoEach = nullptr;
100     int index = 0;
101     cJSON_ArrayForEach(cardInfoEach, cardInfo) {
102         if (index >= MAX_CARD_INFO_VEC_LEN) {
103             ErrorLog("index exceeds");
104             return false;
105         }
106         cJSON *name = cJSON_GetObjectItemCaseSensitive(cardInfoEach, KEY_APDU_NAME.c_str());
107         if (name == nullptr || !cJSON_IsString(name)) {
108             ErrorLog("json param not string, or has no field \"name\", index = %{public}d", index);
109             return false;
110         }
111         cardInfoList[index].name = name->valuestring;
112 
113         cJSON *aid = cJSON_GetObjectItemCaseSensitive(cardInfoEach, KEY_APDU_AID.c_str());
114         if (aid == nullptr || !cJSON_IsString(aid)) {
115             WarnLog("json param not string, or has no field \"aid\", index = %{public}d", index);
116         } else {
117             cardInfoList[index].aid = aid->valuestring;
118         }
119 
120         if (!GetCheckApduFromJson(json, cardInfoEach, cardInfoList, index)) {
121             ErrorLog("fail to get check apdu array from json.");
122             return false;
123         }
124 
125         if (!GetBalanceApduFromJson(json, cardInfoEach, cardInfoList, index)) {
126             ErrorLog("fail to get balance apdu array from json.");
127             return false;
128         }
129 
130         cJSON *rspContains = cJSON_GetObjectItemCaseSensitive(cardInfoEach, KEY_APDU_RSP_CONTAINS.c_str());
131         if (rspContains == nullptr || !cJSON_IsString(rspContains)) {
132             WarnLog("json param not string, or has no fild \"rspContain\", index = %{public}d", index);
133         } else {
134             cardInfoList[index].rspContain = rspContains->valuestring;
135         }
136 
137         index++;
138     }
139     return true;
140 }
141 
DoJsonRead()142 bool IsodepCardHandler::DoJsonRead()
143 {
144     InfoLog("Reading apdu from json config.");
145     TransportCardInfo cardInfoList[MAX_CARD_INFO_VEC_LEN];
146     std::string content;
147     LoadStringFromFile(NFC_CARD_APDU_JSON_FILEPATH, content);
148     cJSON *json = cJSON_Parse(content.c_str());
149     if (json == nullptr) {
150         ErrorLog("json nullptr.");
151         return false;
152     }
153 
154     cJSON *cardInfo = cJSON_GetObjectItemCaseSensitive(json, KEY_CARD_INFO.c_str());
155     if (cardInfo == nullptr || cJSON_GetArraySize(cardInfo) != MAX_CARD_INFO_VEC_LEN) {
156         ErrorLog("fail to parse cardinfo");
157         cJSON_Delete(json);
158         return false;
159     }
160 
161     if (!GetEachCardInfoFromJson(json, cardInfo, cardInfoList, sizeof(cardInfoList) / sizeof(cardInfoList[0]))) {
162         ErrorLog("fail to get each cardinfo from json");
163         cJSON_Delete(json);
164         return false;
165     }
166 
167     for (uint8_t i = 0; i < MAX_CARD_INFO_VEC_LEN; ++i) {
168         cardInfoVec_.push_back(cardInfoList[i]);
169     }
170     cJSON_Delete(json);
171     return true;
172 }
173 
IsSupportedTransportCard(uint32_t rfDiscId,uint8_t & cardIndex)174 bool IsodepCardHandler::IsSupportedTransportCard(uint32_t rfDiscId, uint8_t &cardIndex)
175 {
176     InfoLog("IsSupportedTransportCard, cardInfoVec_ size = [%{public}lu]", cardInfoVec_.size());
177     if (nciTagProxy_.expired()) {
178         WarnLog("nciTagProxy_ expired.");
179         return false;
180     }
181     nciTagProxy_.lock()->Connect(rfDiscId, static_cast<int>(KITS::TagTechnology::NFC_ISODEP_TECH));
182     for (uint8_t index = 0; index < cardInfoVec_.size(); ++index) {
183         if (MatchCity(rfDiscId, index)) {
184             InfoLog("card match \"%{public}s\"", cardInfoVec_[index].name.c_str());
185             cardIndex = index;
186             return true;
187         }
188     }
189     InfoLog("no matching city, ignore.");
190     return false;
191 }
192 
MatchCity(uint32_t rfDiscId,uint8_t cardIndex)193 bool IsodepCardHandler::MatchCity(uint32_t rfDiscId, uint8_t cardIndex)
194 {
195     if (static_cast<size_t>(cardIndex) >= cardInfoVec_.size()) {
196         ErrorLog("invalid input cardIndex[%{public}u]", cardIndex);
197         return false;
198     }
199     InfoLog("trying to match card type = \"%{public}s\"", cardInfoVec_[cardIndex].name.c_str());
200     std::string checkCmdApdu = "";
201     std::string rspApdu = "";
202     for (uint8_t i = 0; i < cardInfoVec_[cardIndex].checkApdus.size(); ++i) {
203         checkCmdApdu = cardInfoVec_[cardIndex].checkApdus[i];
204         if (nciTagProxy_.expired()) {
205             WarnLog("nciTagProxy_ expired.");
206             return false;
207         }
208         nciTagProxy_.lock()->Transceive(rfDiscId, checkCmdApdu, rspApdu);
209         InfoLog("rspApdu = %{public}s", rspApdu.c_str());
210         if (!CheckApduResponse(rspApdu, cardIndex)) {
211             InfoLog("check result false");
212             return false;
213         }
214     }
215     InfoLog("check result true");
216     return true;
217 }
218 
CheckApduResponse(const std::string & response,uint8_t cardIndex)219 bool IsodepCardHandler::CheckApduResponse(const std::string &response, uint8_t cardIndex)
220 {
221     if (static_cast<size_t>(cardIndex) >= cardInfoVec_.size()) {
222         ErrorLog("invalid input cardIndex[%{public}u]", cardIndex);
223         return false;
224     }
225     if (response.length() < APDU_RSP_OK_STR_LEN) {
226         ErrorLog("invalid response length");
227         return false;
228     }
229     if (cardInfoVec_[cardIndex].rspContain == "") {
230         return CheckApduResponse(response);
231     }
232     if (response.find(APDU_RSP_PREFIX) != std::string::npos &&
233         response.find(cardInfoVec_[cardIndex].rspContain) != std::string::npos) {
234         return true;
235     }
236     return false;
237 }
238 
CheckApduResponse(const std::string & response)239 bool IsodepCardHandler::CheckApduResponse(const std::string &response)
240 {
241     if (response.length() < APDU_RSP_OK_STR_LEN) {
242         ErrorLog("invalid response length");
243         return false;
244     }
245 
246     std::string rspStr = response.substr(response.length() - APDU_RSP_OK_STR_LEN, APDU_RSP_OK_STR_LEN);
247     if (rspStr == APDU_RSP_OK) {
248         return true;
249     }
250     return false;
251 }
252 
GetBalance(uint32_t rfDiscId,uint8_t cardIndex,int & balance)253 void IsodepCardHandler::GetBalance(uint32_t rfDiscId, uint8_t cardIndex, int &balance)
254 {
255     if (static_cast<size_t>(cardIndex) >= cardInfoVec_.size()) {
256         ErrorLog("invalid input cardIndex[%{public}u]", cardIndex);
257         return;
258     }
259     InfoLog("start to get balance, card type = \"%{public}s\"", cardInfoVec_[cardIndex].name.c_str());
260     std::string getBalanceCmdApdu = "";
261     std::string rspApdu = "";
262     uint8_t apduNum = cardInfoVec_[cardIndex].balanceApdus.size();
263     for (uint8_t i = 0; i < apduNum; ++i) {
264         getBalanceCmdApdu = cardInfoVec_[cardIndex].balanceApdus[i];
265         if (nciTagProxy_.expired()) {
266             WarnLog("nciTagProxy_ expired.");
267             return;
268         }
269         nciTagProxy_.lock()->Transceive(rfDiscId, getBalanceCmdApdu, rspApdu);
270         InfoLog("rspApdu = %{public}s", rspApdu.c_str());
271         if (CheckApduResponse(rspApdu)) {
272             if (i != apduNum - 1) {
273                 continue;
274             }
275             std::string balanceStr = rspApdu.substr(0, APDU_RSP_BALANCE_STR_LEN);
276             DebugLog("balanceStr = %{public}s", balanceStr.c_str());
277             GetBalanceValue(balanceStr, balance);
278             return;
279         }
280     }
281     ErrorLog("fail to get balance infomation from traffic card.");
282 }
283 
GetBalanceValue(const std::string & balanceStr,int & balanceValue)284 void IsodepCardHandler::GetBalanceValue(const std::string &balanceStr, int &balanceValue)
285 {
286     if (balanceStr.length() != APDU_RSP_BALANCE_STR_LEN) {
287         ErrorLog("illegal balance string input.");
288         return;
289     }
290     std::vector<unsigned char> bytes;
291     KITS::NfcSdkCommon::HexStringToBytes(balanceStr, bytes);
292     if (bytes.size() != APDU_RSP_BALANCE_BYTES_LEN) {
293         ErrorLog("bytes size error.");
294         return;
295     }
296     balanceValue = ((bytes[BYTE_ONE] & 0xFF) << TWO_BYTES_SHIFT)
297                 + ((bytes[BYTE_TWO] & 0xFF) << ONE_BYTES_SHIFT)
298                 + (bytes[BYTE_THREE] & 0xFF); // ignore BYTE_ZERO, in case of large balance
299 }
300 
GetCardName(uint8_t cardIndex,std::string & cardName)301 void IsodepCardHandler::GetCardName(uint8_t cardIndex, std::string &cardName)
302 {
303     if (static_cast<size_t>(cardIndex) >= cardInfoVec_.size()) {
304         ErrorLog("invalid input cardIndex[%{public}u]", cardIndex);
305         return;
306     }
307     cardName = cardInfoVec_[cardIndex].name;
308 }
309 }  // namespace TAG
310 }  // namespace NFC
311 }  // namespace OHOS
312