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 #include "ndef_wifi_data_parser.h"
16 
17 #include "loghelper.h"
18 #include "ndef_message.h"
19 #include "nfc_sdk_common.h"
20 
21 namespace OHOS {
22 namespace NFC {
23 namespace TAG {
24 #define RTD_TYPE_WIFI               "application/vnd.wfa.wsc"
25 
26 #define UNSIGNED_BYTE_TO_INT_MASK   0xFF
27 #define WIFI_TYPE_LEN               2
28 #define WIFI_TYPE_TO_INT_MASK       0xFFFF
29 
30 #define CREDENTIAL_FIELD_TYPE       0x100E
31 #define WIFI_SSID_TYPE              0x1045
32 #define WIFI_NETWORK_KEY_TYPE       0x1027
33 #define WIFI_AUTH_TYPE_TYPE         0x1003
34 #define WIFI_VENDOR_EXT_TYPE        0x1049
35 
36 #define AUTH_TYPE_OPEN              0x0001
37 #define AUTH_TYPE_WPA_PSK           0x0002
38 #define AUTH_TYPE_WPA_EAP           0x0008
39 #define AUTH_TYPE_WPA2_EAP          0x0010
40 #define AUTH_TYPE_WPA2_PSK          0x0020
41 #define AUTH_TYPE_WPA_AND_WPA2_PSK  0x0022
42 
43 #define RECORDS_MAX_SIZE            2000
44 #define NETWORK_KEY_MAX_SIZE        64
45 #define AUTH_TYPE_SIZE              2
46 #define MAX_VALUE_LENGTH            2000
47 #define MAX_PARSE_TIMES             16
48 
49 using namespace OHOS::NFC::KITS;
50 
NdefWifiDataParser()51 NdefWifiDataParser::NdefWifiDataParser()
52 {
53 }
54 
GetTypeFromPayload(const std::string & src,uint32_t & offset)55 uint16_t NdefWifiDataParser::GetTypeFromPayload(const std::string& src, uint32_t &offset)
56 {
57     if (src.length() == 0 || (src.length() < (offset + WIFI_TYPE_LEN) * HEX_BYTE_LEN)) {
58         return 0;
59     }
60     unsigned char firstByte = KITS::NfcSdkCommon::GetByteFromHexStr(src, offset);
61     offset++;
62     unsigned char secondByte = KITS::NfcSdkCommon::GetByteFromHexStr(src, offset);
63     offset++;
64     uint8_t shift = 8; // 8 bits for one byte
65     return ((firstByte << shift) +  secondByte) & WIFI_TYPE_TO_INT_MASK;
66 }
67 
GetValueFromPayload(const std::string & payload,uint32_t & offset,uint16_t dataLen)68 std::string NdefWifiDataParser::GetValueFromPayload(const std::string& payload, uint32_t& offset, uint16_t dataLen)
69 {
70     if (dataLen > MAX_VALUE_LENGTH) {
71         return "";
72     }
73     if (dataLen * HEX_BYTE_LEN > (payload.length() - (offset * HEX_BYTE_LEN))) {
74         return "";
75     }
76     std::string data = payload.substr(offset * HEX_BYTE_LEN, dataLen * HEX_BYTE_LEN);
77     offset += dataLen;
78     return data;
79 }
80 
SetKeyMgmt(std::string & keyMgmt,uint16_t authType)81 void NdefWifiDataParser::SetKeyMgmt(std::string& keyMgmt, uint16_t authType)
82 {
83     switch (authType) {
84         case AUTH_TYPE_OPEN:
85             keyMgmt = Wifi::KEY_MGMT_NONE;
86             break;
87         case AUTH_TYPE_WPA_PSK:
88             // fall-through
89         case AUTH_TYPE_WPA2_PSK:
90             // fall-through
91         case AUTH_TYPE_WPA_AND_WPA2_PSK:
92             keyMgmt = Wifi::KEY_MGMT_WPA_PSK;
93             break;
94         case AUTH_TYPE_WPA_EAP:
95             // fall-through
96         case AUTH_TYPE_WPA2_EAP:
97             keyMgmt = Wifi::KEY_MGMT_EAP;
98             break;
99         default:
100             break;
101     }
102 }
103 
104 /*
105  * WIFI RECORD STRUCTURE
106  * Credential Type(2 BYTES) | Length(2 BYTES) | TLV data
107  * LTV data:
108  * TYPE(2 BYTES) | LEN(2 BYTES) | VALUE(LEN BYTES)
109  */
ParseWiFiPayload(const std::string & payload)110 std::shared_ptr<WifiData> NdefWifiDataParser::ParseWiFiPayload(const std::string& payload)
111 {
112     DebugLog("ParseWiFiPayload");
113     std::shared_ptr<WifiData> data = std::make_shared<WifiData>();
114     uint32_t offset = 0;
115     uint16_t type = GetTypeFromPayload(payload, offset);
116     uint16_t len = GetTypeFromPayload(payload, offset);
117     InfoLog("NdefWifiDataParser::ParseWiFiPayload, type: 0x%{public}X, len: %{public}d", type, len);
118     for (int i = 0; i < MAX_PARSE_TIMES && len > 0 && (offset * HEX_BYTE_LEN) < payload.length()
119         && type != CREDENTIAL_FIELD_TYPE; i++) {
120         offset += len;
121         type = GetTypeFromPayload(payload, offset);
122         len = GetTypeFromPayload(payload, offset);
123         InfoLog("NdefWifiDataParser::ParseWiFiPayload, type: 0x%{public}X, len: %{public}d", type, len);
124     }
125     if (len == 0) {
126         return data;
127     }
128     data->isValid_ = true;
129     if (!data->config_) {
130         data->config_ = new Wifi::WifiDeviceConfig();
131     }
132     while ((offset * HEX_BYTE_LEN) < payload.length()) {
133         type = GetTypeFromPayload(payload, offset);
134         len = GetTypeFromPayload(payload, offset);
135         InfoLog("NdefWifiDataParser::ParseWiFiPayload, type: 0x%{public}X, len: %{public}d", type, len);
136         switch (type) {
137             case WIFI_SSID_TYPE: {
138                 std::string ssid = GetValueFromPayload(payload, offset, len);
139                 if (ssid.empty()) {
140                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, SSID error, "
141                         "payload len.%{public}lu offset.%{public}d type.0x%{public}X", payload.length(), offset, type);
142                     data->isValid_ = false;
143                     return data;
144                 }
145                 data->config_->ssid = KITS::NfcSdkCommon::HexArrayToStringWithoutChecking(ssid);
146                 InfoLog("NdefWifiDataParser::ParseWiFiPayload, SSID: %{private}s", data->config_->ssid.c_str());
147                 break;
148             }
149             case WIFI_NETWORK_KEY_TYPE: {
150                 if (len > NETWORK_KEY_MAX_SIZE) {
151                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, invalid network key length: %{public}d", len);
152                     data->isValid_ = false;
153                     return data;
154                 }
155                 std::string key = GetValueFromPayload(payload, offset, len);
156                 if (key.empty()) {
157                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, name error, "
158                         "payload len.%{public}lu offset.%{public}d type.0x%{public}X", payload.length(), offset, type);
159                     data->isValid_ = false;
160                     return data;
161                 }
162                 data->config_->preSharedKey = KITS::NfcSdkCommon::HexStringToAsciiString(key);
163                 break;
164             }
165             case WIFI_AUTH_TYPE_TYPE: {
166                 if (len != AUTH_TYPE_SIZE) {
167                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, invalid auth type len");
168                     data->isValid_ = false;
169                     return data;
170                 }
171                 uint16_t authType = GetTypeFromPayload(payload, offset);
172                 if (authType == 0) {
173                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, invalid auth type value");
174                     data->isValid_ = false;
175                     return data;
176                 }
177                 SetKeyMgmt(data->config_->keyMgmt, authType);
178                 InfoLog("NdefWifiDataParser::ParseWiFiPayload, keyMgmt: %{public}s, authType: %{public}d",
179                     data->config_->keyMgmt.c_str(), authType);
180                 break;
181             }
182             case WIFI_VENDOR_EXT_TYPE: {
183                 std::string vendorPayload = GetValueFromPayload(payload, offset, len);
184                 if (vendorPayload.empty()) {
185                     ErrorLog("NdefWifiDataParser::ParseWiFiPayload, vendor error, "
186                         "payload len.%{public}lu offset.%{public}d type.0x%{public}X", payload.length(), offset, type);
187                     data->isValid_ = false;
188                     return data;
189                 }
190                 data->vendorPayload_ = vendorPayload;
191                 break;
192             }
193             default: {
194                 offset += len;
195                 InfoLog("NdefWifiDataParser::ParseWiFiPayload, unknown type = 0x%{public}X", type);
196                 break;
197             }
198         }
199     }
200     if (!data->config_->ssid.empty()) {
201         if (data->config_->keyMgmt == Wifi::KEY_MGMT_NONE) {
202             WarnLog("key should be null when keyMgmt is NONE");
203             data->config_->preSharedKey = "";
204         } else if (data->config_->preSharedKey.empty()) {
205             ErrorLog("key should not be null when keyMgmt is not NONE");
206             data->isValid_ = false;
207         }
208     }
209     if (!data->isValid_ && data->config_) {
210         delete data->config_;
211         data->config_ = nullptr;
212     }
213     InfoLog("parse end, valid: %{public}d", data->isValid_);
214     return data;
215 }
216 
CheckWifiRecord(const std::string & msg)217 std::shared_ptr<WifiData> NdefWifiDataParser::CheckWifiRecord(const std::string& msg)
218 {
219     if (msg.empty()) {
220         ErrorLog("NdefWifiDataParser::CheckWifiRecord: msg is empty");
221         return std::make_shared<WifiData>();
222     }
223     std::shared_ptr<NdefMessage> ndef = NdefMessage::GetNdefMessage(msg);
224     if (ndef == nullptr || (ndef->GetNdefRecords().size() == 0)) {
225         ErrorLog("NdefWifiDataParser::CheckWifiRecord: ndef is null");
226         return std::make_shared<WifiData>();
227     }
228     std::vector<std::shared_ptr<NdefRecord>> records = ndef->GetNdefRecords();
229     if (records.size() > RECORDS_MAX_SIZE) {
230         ErrorLog("NdefWifiDataParser::CheckWifiRecord: invalid records size");
231         return std::make_shared<WifiData>();
232     }
233     for (std::shared_ptr<NdefRecord> record : records) {
234         if (!record) {
235             ErrorLog("NdefWifiDataParser::CheckWifiRecord: record is null");
236             return std::make_shared<WifiData>();
237         }
238         if (record->tagRtdType_.compare(KITS::NfcSdkCommon::StringToHexString(RTD_TYPE_WIFI)) == 0) {
239             return ParseWiFiPayload(record->payload_);
240         }
241     }
242     return std::make_shared<WifiData>();
243 }
244 } // namespace TAG
245 } // namespace NFC
246 } // namespace OHOS