/src/connectedhomeip/src/setup_payload/SetupPayload.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2020 Project CHIP Authors |
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 | | * @file |
20 | | * This file describes a QRCode Setup Payload class to hold |
21 | | * data enumerated from a byte stream |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <cstdint> |
27 | | #include <map> |
28 | | #include <string> |
29 | | #include <vector> |
30 | | |
31 | | #include <lib/core/CHIPError.h> |
32 | | #include <lib/core/Optional.h> |
33 | | #include <lib/support/BitFlags.h> |
34 | | #include <lib/support/SetupDiscriminator.h> |
35 | | |
36 | | namespace chip { |
37 | | |
38 | | // See section 5.1.2. QR Code in the Matter specification |
39 | | const int kVersionFieldLengthInBits = 3; |
40 | | const int kVendorIDFieldLengthInBits = 16; |
41 | | const int kProductIDFieldLengthInBits = 16; |
42 | | const int kCommissioningFlowFieldLengthInBits = 2; |
43 | | const int kRendezvousInfoFieldLengthInBits = 8; |
44 | | const int kPayloadDiscriminatorFieldLengthInBits = SetupDiscriminator::kLongBits; |
45 | | const int kSetupPINCodeFieldLengthInBits = 27; |
46 | | const int kPaddingFieldLengthInBits = 4; |
47 | | const int kRawVendorTagLengthInBits = 7; |
48 | | |
49 | | // See section 5.1.3. Manual Pairing Code in the Matter specification |
50 | | const int kManualSetupDiscriminatorFieldLengthInBits = SetupDiscriminator::kShortBits; |
51 | | const int kManualSetupChunk1DiscriminatorMsbitsPos = 0; |
52 | | const int kManualSetupChunk1DiscriminatorMsbitsLength = 2; |
53 | | const int kManualSetupChunk1VidPidPresentBitPos = |
54 | | (kManualSetupChunk1DiscriminatorMsbitsPos + kManualSetupChunk1DiscriminatorMsbitsLength); |
55 | | const int kManualSetupChunk2PINCodeLsbitsPos = 0; |
56 | | const int kManualSetupChunk2PINCodeLsbitsLength = 14; |
57 | | const int kManualSetupChunk2DiscriminatorLsbitsPos = (kManualSetupChunk2PINCodeLsbitsPos + kManualSetupChunk2PINCodeLsbitsLength); |
58 | | const int kManualSetupChunk2DiscriminatorLsbitsLength = 2; |
59 | | const int kManualSetupChunk3PINCodeMsbitsPos = 0; |
60 | | const int kManualSetupChunk3PINCodeMsbitsLength = 13; |
61 | | |
62 | | const int kManualSetupShortCodeCharLength = 10; |
63 | | const int kManualSetupLongCodeCharLength = 20; |
64 | | const int kManualSetupCodeChunk1CharLength = 1; |
65 | | const int kManualSetupCodeChunk2CharLength = 5; |
66 | | const int kManualSetupCodeChunk3CharLength = 4; |
67 | | const int kManualSetupVendorIdCharLength = 5; |
68 | | const int kManualSetupProductIdCharLength = 5; |
69 | | |
70 | | // Spec 5.1.4.2 CHIP-Common Reserved Tags |
71 | | inline constexpr uint8_t kSerialNumberTag = 0x00; |
72 | | inline constexpr uint8_t kPBKDFIterationsTag = 0x01; |
73 | | inline constexpr uint8_t kBPKFSaltTag = 0x02; |
74 | | inline constexpr uint8_t kNumberOFDevicesTag = 0x03; |
75 | | inline constexpr uint8_t kCommissioningTimeoutTag = 0x04; |
76 | | |
77 | | inline constexpr uint32_t kSetupPINCodeMaximumValue = 99999998; |
78 | | inline constexpr uint32_t kSetupPINCodeUndefinedValue = 0; |
79 | | static_assert(kSetupPINCodeMaximumValue < (1 << kSetupPINCodeFieldLengthInBits)); |
80 | | |
81 | | // clang-format off |
82 | | const int kTotalPayloadDataSizeInBits = |
83 | | kVersionFieldLengthInBits + |
84 | | kVendorIDFieldLengthInBits + |
85 | | kProductIDFieldLengthInBits + |
86 | | kCommissioningFlowFieldLengthInBits + |
87 | | kRendezvousInfoFieldLengthInBits + |
88 | | kPayloadDiscriminatorFieldLengthInBits + |
89 | | kSetupPINCodeFieldLengthInBits + |
90 | | kPaddingFieldLengthInBits; |
91 | | // clang-format on |
92 | | |
93 | | const int kTotalPayloadDataSizeInBytes = kTotalPayloadDataSizeInBits / 8; |
94 | | |
95 | | const char * const kQRCodePrefix = "MT:"; |
96 | | |
97 | | /// The rendezvous type this device supports. |
98 | | enum class RendezvousInformationFlag : uint8_t |
99 | | { |
100 | | kNone = 0, ///< Device does not support any method for rendezvous |
101 | | kSoftAP = 1 << 0, ///< Device supports Wi-Fi softAP |
102 | | kBLE = 1 << 1, ///< Device supports BLE |
103 | | kOnNetwork = 1 << 2, ///< Device supports Setup on network |
104 | | kWiFiPAF = 1 << 3, ///< Device supports Wi-Fi Public Action Frame for discovery |
105 | | kNFC = 1 << 4, ///< Device supports NFC-based Commissioning |
106 | | }; |
107 | | using RendezvousInformationFlags = chip::BitFlags<RendezvousInformationFlag, uint8_t>; |
108 | | |
109 | | enum class CommissioningFlow : uint8_t |
110 | | { |
111 | | kStandard = 0, ///< Device automatically enters pairing mode upon power-up |
112 | | kUserActionRequired, ///< Device requires a user interaction to enter pairing mode |
113 | | kCustom, ///< Commissioning steps should be retrieved from the distributed compliance ledger |
114 | | }; |
115 | | |
116 | | /** |
117 | | * A parent struct to hold onboarding payload contents without optional info, |
118 | | * for compatibility with devices that don't support std::string or STL. |
119 | | */ |
120 | | struct PayloadContents |
121 | | { |
122 | | uint8_t version = 0; |
123 | | uint16_t vendorID = 0; |
124 | | uint16_t productID = 0; |
125 | | CommissioningFlow commissioningFlow = CommissioningFlow::kStandard; |
126 | | // rendezvousInformation is Optional, because a payload parsed from a manual |
127 | | // numeric code would not have any rendezvousInformation available. A |
128 | | // payload parsed from a QR code would always have a value for |
129 | | // rendezvousInformation. |
130 | | Optional<RendezvousInformationFlags> rendezvousInformation; |
131 | | SetupDiscriminator discriminator{}; |
132 | | uint32_t setUpPINCode = 0; |
133 | | |
134 | | enum class ValidationMode : uint8_t |
135 | | { |
136 | | kProduce, ///< Only flags or values allowed by the current spec version are allowed. |
137 | | /// Producers of a Setup Payload should use this mode to ensure the |
138 | | // payload is valid according to the current spec version. |
139 | | kConsume, ///< Flags or values that are reserved for future use, or were allowed in |
140 | | /// a previous spec version may be present. Consumers of a Setup Payload |
141 | | /// should use this mode to ensure they are forward and backwards |
142 | | /// compatible with payloads from older or newer Matter devices. |
143 | | }; |
144 | | |
145 | | bool isValidQRCodePayload(ValidationMode mode = ValidationMode::kProduce) const; |
146 | | bool isValidManualCode(ValidationMode mode = ValidationMode::kProduce) const; |
147 | | |
148 | | bool operator==(const PayloadContents & input) const; |
149 | | |
150 | | static bool IsValidSetupPIN(uint32_t setupPIN); |
151 | | |
152 | | private: |
153 | | bool CheckPayloadCommonConstraints() const; |
154 | | }; |
155 | | |
156 | | enum optionalQRCodeInfoType |
157 | | { |
158 | | optionalQRCodeInfoTypeUnknown, |
159 | | optionalQRCodeInfoTypeString, |
160 | | optionalQRCodeInfoTypeInt32, |
161 | | optionalQRCodeInfoTypeInt64, |
162 | | optionalQRCodeInfoTypeUInt32, |
163 | | optionalQRCodeInfoTypeUInt64 |
164 | | }; |
165 | | |
166 | | /** |
167 | | * A structure to hold optional QR Code info |
168 | | */ |
169 | | struct OptionalQRCodeInfo |
170 | | { |
171 | | /*@{*/ |
172 | | uint8_t tag; /**< the tag number of the optional info */ |
173 | | enum optionalQRCodeInfoType type; /**< the type (String or Int) of the optional info */ |
174 | | std::string data; /**< the string value if type is optionalQRCodeInfoTypeString, otherwise should not be set */ |
175 | | int32_t int32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt32, otherwise should not be set */ |
176 | | /*@}*/ |
177 | | }; |
178 | | |
179 | | struct OptionalQRCodeInfoExtension : OptionalQRCodeInfo |
180 | | { |
181 | | int64_t int64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt64, otherwise should not be set */ |
182 | | uint64_t uint32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt32, otherwise should not be set */ |
183 | | uint64_t uint64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt64, otherwise should not be set */ |
184 | | }; |
185 | | |
186 | | class SetupPayload : public PayloadContents |
187 | | { |
188 | | |
189 | | friend class QRCodeSetupPayloadGenerator; |
190 | | friend class QRCodeSetupPayloadParser; |
191 | | |
192 | | public: |
193 | | /** @brief A function to add an optional vendor data |
194 | | * @param tag tag number in the [0x80-0xFF] range |
195 | | * @param data String representation of data to add |
196 | | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
197 | | **/ |
198 | | CHIP_ERROR addOptionalVendorData(uint8_t tag, std::string data); |
199 | | |
200 | | /** @brief A function to add an optional vendor data |
201 | | * @param tag tag number in the [0x80-0xFF] range |
202 | | * @param data Integer representation of data to add |
203 | | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
204 | | **/ |
205 | | CHIP_ERROR addOptionalVendorData(uint8_t tag, int32_t data); |
206 | | |
207 | | /** @brief A function to remove an optional vendor data |
208 | | * @param tag tag number in the [0x80-0xFF] range |
209 | | * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise |
210 | | **/ |
211 | | CHIP_ERROR removeOptionalVendorData(uint8_t tag); |
212 | | |
213 | | /** @brief A function to retrieve an optional QR Code info vendor object |
214 | | * @param tag tag number in the [0x80-0xFF] range |
215 | | * @param info retrieved OptionalQRCodeInfo object |
216 | | * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise |
217 | | **/ |
218 | | CHIP_ERROR getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const; |
219 | | |
220 | | /** |
221 | | * @brief A function to retrieve the vector of OptionalQRCodeInfo infos |
222 | | * @return Returns a vector of optionalQRCodeInfos |
223 | | **/ |
224 | | std::vector<OptionalQRCodeInfo> getAllOptionalVendorData() const; |
225 | | |
226 | | /** @brief A function to add a string serial number |
227 | | * @param serialNumber string serial number |
228 | | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
229 | | **/ |
230 | | CHIP_ERROR addSerialNumber(std::string serialNumber); |
231 | | |
232 | | /** @brief A function to add a uint32_t serial number |
233 | | * @param serialNumber uint32_t serial number |
234 | | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
235 | | **/ |
236 | | CHIP_ERROR addSerialNumber(uint32_t serialNumber); |
237 | | |
238 | | /** @brief A function to retrieve serial number as a string |
239 | | * @param outSerialNumber retrieved string serial number |
240 | | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
241 | | **/ |
242 | | CHIP_ERROR getSerialNumber(std::string & outSerialNumber) const; |
243 | | |
244 | | /** @brief A function to remove the serial number from the payload |
245 | | * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise |
246 | | **/ |
247 | | CHIP_ERROR removeSerialNumber(); |
248 | | |
249 | | bool operator==(const SetupPayload & input) const; |
250 | | |
251 | | /** @brief Checks if the tag is CHIP Common type |
252 | | * @param tag Tag to be checked |
253 | | * @return Returns True if the tag is of Common type |
254 | | **/ |
255 | 0 | static bool IsCommonTag(uint8_t tag) { return tag < 0x80; } |
256 | | |
257 | | /** @brief Checks if the tag is vendor-specific |
258 | | * @param tag Tag to be checked |
259 | | * @return Returns True if the tag is Vendor-specific |
260 | | **/ |
261 | 0 | static bool IsVendorTag(uint8_t tag) { return !IsCommonTag(tag); } |
262 | | |
263 | | /** @brief Generate a Random Setup Pin Code (Passcode) |
264 | | * |
265 | | * This function generates a random passcode within the defined limits (00000001 to 99999998) |
266 | | * It also checks that the generated passcode is not equal to any invalid passcode values as defined in 5.1.7.1. |
267 | | * |
268 | | * @param[out] setupPINCode The generated random setup PIN code. |
269 | | * @return Returns a CHIP_ERROR_INTERNAL if unable to generate a valid passcode within a reasonable number of attempts, |
270 | | * CHIP_NO_ERROR otherwise |
271 | | **/ |
272 | | static CHIP_ERROR generateRandomSetupPin(uint32_t & setupPINCode); |
273 | | |
274 | | /** |
275 | | * @brief Get a list of setup payloads from a string representation. |
276 | | * |
277 | | * @param[in] stringRepresentation The string representing the payloads. |
278 | | |
279 | | * @param[out] outPayloads On success, the contents of this vector will be |
280 | | * replaces with the list of parsed payloads. The |
281 | | * result may have only one entry, or multiple |
282 | | * entries if concatenated QR codes are used. |
283 | | * |
284 | | * On failure, the value of the out param should not |
285 | | * be relied on to be anything in particular. |
286 | | */ |
287 | | static CHIP_ERROR FromStringRepresentation(std::string stringRepresentation, std::vector<SetupPayload> & outPayloads); |
288 | | |
289 | | private: |
290 | | std::map<uint8_t, OptionalQRCodeInfo> optionalVendorData; |
291 | | std::map<uint8_t, OptionalQRCodeInfoExtension> optionalExtensionData; |
292 | | |
293 | | /** @brief A function to add an optional QR Code info vendor object |
294 | | * @param info Optional QR code info object to add |
295 | | * @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise |
296 | | **/ |
297 | | CHIP_ERROR addOptionalVendorData(const OptionalQRCodeInfo & info); |
298 | | |
299 | | /** @brief A function to add an optional QR Code info CHIP object |
300 | | * @param info Optional QR code info object to add |
301 | | * @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise |
302 | | **/ |
303 | | CHIP_ERROR addOptionalExtensionData(const OptionalQRCodeInfoExtension & info); |
304 | | |
305 | | /** |
306 | | * @brief A function to retrieve the vector of CHIPQRCodeInfo infos |
307 | | * @return Returns a vector of CHIPQRCodeInfos |
308 | | **/ |
309 | | std::vector<OptionalQRCodeInfoExtension> getAllOptionalExtensionData() const; |
310 | | |
311 | | /** @brief A function to retrieve an optional QR Code info extended object |
312 | | * @param tag 8 bit [128-255] tag number |
313 | | * @param info retrieved OptionalQRCodeInfoExtension object |
314 | | * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise |
315 | | **/ |
316 | | CHIP_ERROR getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const; |
317 | | |
318 | | /** @brief A function to retrieve the associated expected numeric value for a tag |
319 | | * @param tag 8 bit [0-255] tag number |
320 | | * @return Returns an optionalQRCodeInfoType value |
321 | | **/ |
322 | | optionalQRCodeInfoType getNumericTypeFor(uint8_t tag) const; |
323 | | }; |
324 | | |
325 | | } // namespace chip |