• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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_bt_oob_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 #define RTD_TYPE_BT_OOB         "application/vnd.bluetooth.ep.oob"
24 #define RTD_TYPE_BLE_OOB        "application/vnd.bluetooth.le.oob"
25 
26 #define UNSIGNED_BYTE_TO_INT_MASK   0xFF
27 
28 #define CARRIER_PWR_STA_INACTIVE    0
29 #define CARRIER_PWR_STA_ACTIVE      1
30 #define CARRIER_PWR_STA_ACTIVATING  2
31 #define CARRIER_PWR_STA_UNKNOWN     3
32 
33 #define BT_OOB_TYPE_MAC                         0x1B
34 #define BT_OOB_TYPE_LE_ROLE                     0x1C
35 #define BT_OOB_TYPE_LONG_LOCAL_NAME             0x09
36 #define BT_OOB_TYPE_SHORT_LOCAL_NAME            0x08
37 #define BT_OOB_TYPE_16_BIT_UUIDS_PARTIAL        0x02
38 #define BT_OOB_TYPE_16_BIT_UUIDS_COMPLETE       0x03
39 #define BT_OOB_TYPE_32_BIT_UUIDS_PARTIAL        0x04
40 #define BT_OOB_TYPE_32_BIT_UUIDS_COMPLETE       0x05
41 #define BT_OOB_TYPE_128_BIT_UUIDS_PARTIAL       0x06
42 #define BT_OOB_TYPE_128_BIT_UUIDS_COMPLETE      0x07
43 #define BT_OOB_TYPE_CLASS_OF_DEVICE             0x0D
44 #define BT_OOB_TYPE_SEC_MGR_TK                  0x10
45 #define BT_OOB_TYPE_APPEARANCE                  0x19
46 #define BT_OOB_TYPE_LE_SC_CONFIRMATION          0x22
47 #define BT_OOB_TYPE_LE_SC_RANDOM                0x23
48 #define BT_OOB_TYPE_VENDOR                      0xFF
49 
50 #define BT_OOB_LE_ROLE_CENTRAL_ONLY             0x01
51 
52 #define SEC_MGR_TK_SIZE         16
53 #define SEC_MGR_LE_SC_C_SIZE    16
54 #define SEC_MGR_LE_SC_R_SIZE    16
55 #define CLASS_OF_DEVICE_SIZE    3
56 #define VENDOR_SERIAL_NUM_SIZE  2
57 
58 #define UUID_BYTES_16_BIT_LEN    2
59 #define UUID_BYTES_32_BIT_LEN    4
60 #define UUID_BYTES_128_BIT_LEN   16
61 
62 using namespace OHOS::NFC::KITS;
63 
NdefBtOobDataParser()64 NdefBtOobDataParser::NdefBtOobDataParser()
65 {
66 }
67 
GetBtMacFromPayload(const std::string & payload,uint32_t & offset)68 std::string NdefBtOobDataParser::GetBtMacFromPayload(const std::string& payload, uint32_t& offset)
69 {
70     uint32_t macLen = 6;
71     if (macLen * HEX_BYTE_LEN > payload.length() - (offset * HEX_BYTE_LEN)) {
72         ErrorLog("NdefBtOobDataParser::GetBtMacFromPayload, data error, "
73             "payload len %{public}lu offset.%{public}d", payload.length(), offset);
74         return "";
75     }
76     std::string mac = payload.substr(offset * HEX_BYTE_LEN, macLen * HEX_BYTE_LEN);
77     offset += macLen;
78     return mac;
79 }
80 
GetDataFromPayload(const std::string & payload,uint32_t & offset,uint32_t datalen)81 std::string NdefBtOobDataParser::GetDataFromPayload(const std::string& payload, uint32_t& offset, uint32_t datalen)
82 {
83     if (datalen * HEX_BYTE_LEN > (payload.length() - (offset * HEX_BYTE_LEN))) {
84         return "";
85     }
86     std::string data = payload.substr(offset * HEX_BYTE_LEN, datalen * HEX_BYTE_LEN);
87     offset += datalen;
88     return data;
89 }
90 
GetUuidFromPayload(const std::string & payload,uint32_t & offset,uint32_t type,uint32_t len)91 std::string NdefBtOobDataParser::GetUuidFromPayload(const std::string& payload, uint32_t& offset,
92                                                     uint32_t type, uint32_t len)
93 {
94     // uuids can have several groups, uuidsSize is the size of each group
95     uint32_t uuidSize;
96     switch (type) {
97         case BT_OOB_TYPE_16_BIT_UUIDS_PARTIAL:
98         case BT_OOB_TYPE_16_BIT_UUIDS_COMPLETE:
99             uuidSize = UUID_BYTES_16_BIT_LEN;
100             break;
101         case BT_OOB_TYPE_32_BIT_UUIDS_PARTIAL:
102         case BT_OOB_TYPE_32_BIT_UUIDS_COMPLETE:
103             uuidSize = UUID_BYTES_32_BIT_LEN;
104             break;
105         case BT_OOB_TYPE_128_BIT_UUIDS_PARTIAL:
106         case BT_OOB_TYPE_128_BIT_UUIDS_COMPLETE:
107             uuidSize = UUID_BYTES_128_BIT_LEN;
108             break;
109         default:
110             ErrorLog("NdefBtOobDataParser::GetUuidFromPayload, unknown type of UUID");
111             return "";
112     }
113     if (len == 0 || (len % uuidSize != 0) || len * HEX_BYTE_LEN > (payload.length() - (offset * HEX_BYTE_LEN))) {
114         return "";
115     }
116     std::string uuid = payload.substr(offset * HEX_BYTE_LEN, len * HEX_BYTE_LEN);
117     offset += len;
118     return uuid;
119 }
120 
121 /*
122  * BT OOB RECORD STRUCTURE
123  * BtOobLen(2 BYTEs) | MacAddr(6 BYTES, reverted) | LTV data
124  * LTV data:
125  * LEN(1 BYTE) |TYPE(1 BYTE) |VALUE(LEN -1 BYTES)
126  */
ParseBtOobRecord(const std::string & payload)127 std::shared_ptr<BtOobData> NdefBtOobDataParser::ParseBtOobRecord(const std::string& payload)
128 {
129     std::shared_ptr<BtOobData> data = std::make_shared<BtOobData>();
130     data->isValid_ = false;
131     uint32_t offset = 0; // offset is for byte parse position, payload is hex string
132                          // to compare need to * HEX_BYTE_LEN
133 
134     uint32_t btOobLen = 2;
135     offset += btOobLen;
136     std::string macAddress = GetBtMacFromPayload(payload, offset);
137     if (macAddress.empty()) {
138         ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, macAddress error, "
139             "payload .len %{public}lu offset.%{public}d", payload.length(), offset);
140         return data;
141     }
142     data->macAddress_ = macAddress;
143     data->isValid_ = true;
144 
145     while ((offset * HEX_BYTE_LEN) < payload.length()) {
146         bool isValid = false;
147         std::string name;
148         uint32_t len = NfcSdkCommon::GetByteFromHexStr(payload, offset++) & UNSIGNED_BYTE_TO_INT_MASK;
149         uint32_t type = NfcSdkCommon::GetByteFromHexStr(payload, offset++) & UNSIGNED_BYTE_TO_INT_MASK;
150         switch (type) {
151             case BT_OOB_TYPE_SHORT_LOCAL_NAME: {
152                 if (len < 1) {
153                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, invalid  local name len. ");
154                     data->isValid_ = false;
155                     return data;
156                 }
157                 name = GetDataFromPayload(payload, offset, len - 1);
158                 if (name.empty()) {
159                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, name error, "
160                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
161                     break;
162                 }
163                 data->name_ = name;
164                 isValid = true;
165                 break;
166             }
167             case BT_OOB_TYPE_LONG_LOCAL_NAME: {
168                 if (!data->name_.empty()) {
169                     offset += (len - 1);
170                     break; // already contains short name
171                 }
172                 if (len < 1) {
173                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, invalid  long local name len. ");
174                     data->isValid_ = false;
175                     return data;
176                 }
177                 name = GetDataFromPayload(payload, offset, len - 1);
178                 if (name.empty()) {
179                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, name error, "
180                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
181                     break;
182                 }
183                 data->name_ = name;
184                 isValid = true;
185                 break;
186             }
187             case BT_OOB_TYPE_16_BIT_UUIDS_PARTIAL:
188             case BT_OOB_TYPE_16_BIT_UUIDS_COMPLETE:
189             case BT_OOB_TYPE_32_BIT_UUIDS_PARTIAL:
190             case BT_OOB_TYPE_32_BIT_UUIDS_COMPLETE:
191             case BT_OOB_TYPE_128_BIT_UUIDS_PARTIAL:
192             case BT_OOB_TYPE_128_BIT_UUIDS_COMPLETE: {
193                 data->uuids_ = GetUuidFromPayload(payload, offset, type, len - 1);
194                 if (!data->uuids_.empty()) {
195                     isValid = true;
196                 }
197                 break;
198             }
199             case BT_OOB_TYPE_CLASS_OF_DEVICE: {
200                 if (len - 1 != CLASS_OF_DEVICE_SIZE) {
201                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, invalid  class of Device len");
202                     break;
203                 }
204                 offset += CLASS_OF_DEVICE_SIZE;
205                 isValid = true;
206                 break;
207             }
208             case BT_OOB_TYPE_VENDOR: {
209                 std::string vendorPayload = GetDataFromPayload(payload, offset, len - 1);
210                 if (vendorPayload.empty()) {
211                     ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, vendor error, "
212                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
213                     break;
214                 }
215                 data->vendorPayload_ = vendorPayload;
216                 isValid = true;
217                 break;
218             }
219             default: {
220                 offset += (len - 1);
221                 ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, unknown type = %{public}d", type);
222                 break;
223             }
224         }
225         if (!isValid) {
226             ErrorLog("NdefBtOobDataParser::ParseBtOobRecord, vendor error, "
227                 "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
228             data->isValid_ = false;
229             return data;
230         }
231     }
232     return data;
233 }
234 
ParseBleOobRecord(const std::string & payload)235 std::shared_ptr<BtOobData> NdefBtOobDataParser::ParseBleOobRecord(const std::string& payload)
236 {
237     std::shared_ptr<BtOobData> data = std::make_shared<BtOobData>();
238     data->isValid_ = false;
239     uint32_t offset = 0; // offset is for byte parse position, payload is hex string
240                          // to compare need to * HEX_BYTE_LEN
241 
242     std::string bdaddr = "";
243     unsigned char role = 0xF; // invalid default
244     std::string leScC = "";
245     std::string leScR = "";
246     std::string name = "";
247     std::string secMgrTK = "";
248     std::string macAddress = "";
249     while ((offset * HEX_BYTE_LEN) < payload.length()) {
250         uint32_t len = NfcSdkCommon::GetByteFromHexStr(payload, offset++) & UNSIGNED_BYTE_TO_INT_MASK;
251         uint32_t type = NfcSdkCommon::GetByteFromHexStr(payload, offset++) & UNSIGNED_BYTE_TO_INT_MASK;
252         switch (type) {
253             case BT_OOB_TYPE_MAC: {
254                 uint32_t bdaddrLen = 7; // 6 bytes for mac, 1 for address type
255                 bdaddr = GetDataFromPayload(payload, offset, bdaddrLen);
256                 if (bdaddr.empty()) {
257                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, bdaddr error, "
258                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
259                     break;
260                 }
261                 macAddress = GetBtMacFromPayload(payload, offset);
262                 if (macAddress.empty()) {
263                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, macAddress error, "
264                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
265                     break;
266                 }
267                 offset++; // advance over random byte
268                 data->isValid_ = true;
269                 break;
270             }
271             case BT_OOB_TYPE_LE_ROLE: {
272                 role = NfcSdkCommon::GetByteFromHexStr(payload, offset++) & UNSIGNED_BYTE_TO_INT_MASK;
273                 if (role == BT_OOB_LE_ROLE_CENTRAL_ONLY) {
274                     data->isValid_ = false;
275                     return data;
276                 }
277                 break;
278             }
279             case BT_OOB_TYPE_LONG_LOCAL_NAME: {
280                 name = GetDataFromPayload(payload, offset, len - 1);
281                 if (name.empty()) {
282                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, name error, "
283                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
284                     break;
285                 }
286                 data->name_ = name;
287                 break;
288             }
289             case BT_OOB_TYPE_SEC_MGR_TK: {
290                 if (len - 1 != SEC_MGR_TK_SIZE) {
291                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, SM TK len error, should be %{public}d",
292                         SEC_MGR_TK_SIZE);
293                     break;
294                 }
295                 secMgrTK = GetDataFromPayload(payload, offset, len);
296                 if (leScC.empty()) {
297                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, secMgrTK error, "
298                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
299                     break;
300                 }
301                 break;
302             }
303             case BT_OOB_TYPE_LE_SC_CONFIRMATION: {
304                 if (len - 1 != SEC_MGR_LE_SC_C_SIZE) {
305                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, LE SC Confirmation len error, "
306                         "should be %{public}d", SEC_MGR_LE_SC_C_SIZE);
307                     break;
308                 }
309                 leScC = GetDataFromPayload(payload, offset, len - 1);
310                 if (leScC.empty()) {
311                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, leScC Confirmation error, "
312                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
313                     break;
314                 }
315                 break;
316             }
317             case BT_OOB_TYPE_LE_SC_RANDOM: {
318                 if (len - 1 != SEC_MGR_LE_SC_R_SIZE) {
319                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, LE SC Random len error, should be %{public}d",
320                         SEC_MGR_LE_SC_R_SIZE);
321                     break;
322                 }
323                 leScR = GetDataFromPayload(payload, offset, len - 1);
324                 if (leScR.empty()) {
325                     ErrorLog("NdefBtOobDataParser::ParseBleOobRecord, leScC Random error, "
326                         "payload len.%{public}lu offset.%{public}d type.%{public}d", payload.length(), offset, type);
327                     break;
328                 }
329                 break;
330             }
331             default: {
332                 offset += (len - 1);
333                 break;
334             }
335         }
336     }
337     return data;
338 }
339 
CheckBtRecord(const std::string & msg)340 std::shared_ptr<BtOobData> NdefBtOobDataParser::CheckBtRecord(const std::string& msg)
341 {
342     if (msg.empty()) {
343         ErrorLog("NdefBtOobDataParser::CheckBtRecord: msg is empty");
344         return std::make_shared<BtOobData>();
345     }
346     std::shared_ptr<NdefMessage> ndef = NdefMessage::GetNdefMessage(msg);
347     if (ndef == nullptr || (ndef->GetNdefRecords().size() == 0)) {
348         ErrorLog("NdefBtOobDataParser::CheckBtRecord: ndef is null");
349         return std::make_shared<BtOobData>();
350     }
351     std::shared_ptr<NdefRecord> record = ndef->GetNdefRecords()[0];
352     if (record == nullptr) {
353         ErrorLog("NdefBtOobDataParser::CheckBtRecord: record is null");
354         return std::make_shared<BtOobData>();
355     }
356 
357     // Check BT OOB
358     if (record->tnf_ == NdefMessage::TNF_MIME_MEDIA &&
359         (record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(RTD_TYPE_BT_OOB)) == 0)) {
360         InfoLog("NdefBtOobDataParser::CheckBtRecord: is bt oob");
361         return ParseBtOobRecord(record->payload_);
362     }
363 
364     // Check BLE OOB
365     if (record->tnf_ == NdefMessage::TNF_MIME_MEDIA &&
366         (record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(RTD_TYPE_BLE_OOB)) == 0)) {
367         InfoLog("NdefBtOobDataParser::CheckBtRecord: is ble oob, currently not supported");
368         return std::make_shared<BtOobData>();
369     }
370 
371     // Check Handover Select, followed by a BT OOB record
372     if (record->tnf_ == NdefMessage::TNF_WELL_KNOWN &&
373         (record->tagRtdType_.compare(NdefMessage::GetTagRtdType(NdefMessage::RTD_HANDOVER_SELECT)) == 0)) {
374         InfoLog("NdefBtOobDataParser::CheckBtRecord: is handover select, currently not supported");
375         return std::make_shared<BtOobData>();
376     }
377     return std::make_shared<BtOobData>();
378 }
379 } // namespace NFC
380 } // namespace OHOS