Line data Source code
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 : inline constexpr const char * kQRCodePrefix = "MT:";
96 : inline constexpr char kPayloadDelimiter = '*';
97 :
98 : /// The rendezvous type this device supports.
99 : enum class RendezvousInformationFlag : uint8_t
100 : {
101 : kNone = 0, ///< Device does not support any method for rendezvous
102 : kSoftAP = 1 << 0, ///< Device supports Wi-Fi softAP
103 : kBLE = 1 << 1, ///< Device supports BLE
104 : kOnNetwork = 1 << 2, ///< Device supports Setup on network
105 : kWiFiPAF = 1 << 3, ///< Device supports Wi-Fi Public Action Frame for discovery
106 : kNFC = 1 << 4, ///< Device supports NFC-based Commissioning
107 : kThread = 1 << 5, ///< Device supports Thread
108 : };
109 : using RendezvousInformationFlags = chip::BitFlags<RendezvousInformationFlag, uint8_t>;
110 :
111 : enum class CommissioningFlow : uint8_t
112 : {
113 : kStandard = 0, ///< Device automatically enters pairing mode upon power-up
114 : kUserActionRequired, ///< Device requires a user interaction to enter pairing mode
115 : kCustom, ///< Commissioning steps should be retrieved from the distributed compliance ledger
116 : };
117 :
118 : /**
119 : * A parent struct to hold onboarding payload contents without optional info,
120 : * for compatibility with devices that don't support std::string or STL.
121 : */
122 : struct PayloadContents
123 : {
124 : uint8_t version = 0;
125 : uint16_t vendorID = 0;
126 : uint16_t productID = 0;
127 : CommissioningFlow commissioningFlow = CommissioningFlow::kStandard;
128 : // rendezvousInformation is Optional, because a payload parsed from a manual
129 : // numeric code would not have any rendezvousInformation available. A
130 : // payload parsed from a QR code would always have a value for
131 : // rendezvousInformation.
132 : Optional<RendezvousInformationFlags> rendezvousInformation;
133 : SetupDiscriminator discriminator{};
134 : uint32_t setUpPINCode = 0;
135 :
136 : enum class ValidationMode : uint8_t
137 : {
138 : kProduce, ///< Only flags or values allowed by the current spec version are allowed.
139 : /// Producers of a Setup Payload should use this mode to ensure the
140 : // payload is valid according to the current spec version.
141 : kConsume, ///< Flags or values that are reserved for future use, or were allowed in
142 : /// a previous spec version may be present. Consumers of a Setup Payload
143 : /// should use this mode to ensure they are forward and backwards
144 : /// compatible with payloads from older or newer Matter devices.
145 : };
146 :
147 : bool isValidQRCodePayload(ValidationMode mode = ValidationMode::kProduce) const;
148 : bool isValidManualCode(ValidationMode mode = ValidationMode::kProduce) const;
149 :
150 : bool operator==(const PayloadContents & input) const;
151 :
152 : static bool IsValidSetupPIN(uint32_t setupPIN);
153 :
154 : private:
155 : bool CheckPayloadCommonConstraints() const;
156 : };
157 :
158 : enum optionalQRCodeInfoType
159 : {
160 : optionalQRCodeInfoTypeUnknown,
161 : optionalQRCodeInfoTypeString,
162 : optionalQRCodeInfoTypeInt32,
163 : optionalQRCodeInfoTypeInt64,
164 : optionalQRCodeInfoTypeUInt32,
165 : optionalQRCodeInfoTypeUInt64
166 : };
167 :
168 : /**
169 : * A structure to hold optional QR Code info
170 : */
171 : struct OptionalQRCodeInfo
172 : {
173 : /*@{*/
174 : uint8_t tag; /**< the tag number of the optional info */
175 : enum optionalQRCodeInfoType type; /**< the type (String or Int) of the optional info */
176 : std::string data; /**< the string value if type is optionalQRCodeInfoTypeString, otherwise should not be set */
177 : int32_t int32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt32, otherwise should not be set */
178 : /*@}*/
179 : };
180 :
181 : struct OptionalQRCodeInfoExtension : OptionalQRCodeInfo
182 : {
183 : int64_t int64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt64, otherwise should not be set */
184 : uint64_t uint32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt32, otherwise should not be set */
185 : uint64_t uint64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt64, otherwise should not be set */
186 : };
187 :
188 : class SetupPayload : public PayloadContents
189 : {
190 :
191 : friend class QRCodeSetupPayloadGenerator;
192 : friend class QRCodeSetupPayloadParser;
193 :
194 : public:
195 : /** @brief A function to add an optional vendor data
196 : * @param tag tag number in the [0x80-0xFF] range
197 : * @param data String representation of data to add
198 : * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
199 : **/
200 : CHIP_ERROR addOptionalVendorData(uint8_t tag, std::string data);
201 :
202 : /** @brief A function to add an optional vendor data
203 : * @param tag tag number in the [0x80-0xFF] range
204 : * @param data Integer representation of data to add
205 : * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
206 : **/
207 : CHIP_ERROR addOptionalVendorData(uint8_t tag, int32_t data);
208 :
209 : /** @brief A function to remove an optional vendor data
210 : * @param tag tag number in the [0x80-0xFF] range
211 : * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
212 : **/
213 : CHIP_ERROR removeOptionalVendorData(uint8_t tag);
214 :
215 : /** @brief A function to retrieve an optional QR Code info vendor object
216 : * @param tag tag number in the [0x80-0xFF] range
217 : * @param info retrieved OptionalQRCodeInfo object
218 : * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
219 : **/
220 : CHIP_ERROR getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const;
221 :
222 : /**
223 : * @brief A function to retrieve the vector of OptionalQRCodeInfo infos
224 : * @return Returns a vector of optionalQRCodeInfos
225 : **/
226 : std::vector<OptionalQRCodeInfo> getAllOptionalVendorData() const;
227 :
228 : /** @brief A function to add a string serial number
229 : * @param serialNumber string serial number
230 : * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
231 : **/
232 : CHIP_ERROR addSerialNumber(std::string serialNumber);
233 :
234 : /** @brief A function to add a uint32_t serial number
235 : * @param serialNumber uint32_t serial number
236 : * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
237 : **/
238 : CHIP_ERROR addSerialNumber(uint32_t serialNumber);
239 :
240 : /** @brief A function to retrieve serial number as a string
241 : * @param outSerialNumber retrieved string serial number
242 : * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
243 : **/
244 : CHIP_ERROR getSerialNumber(std::string & outSerialNumber) const;
245 :
246 : /** @brief A function to remove the serial number from the payload
247 : * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
248 : **/
249 : CHIP_ERROR removeSerialNumber();
250 :
251 : bool operator==(const SetupPayload & input) const;
252 :
253 : /** @brief Checks if the tag is CHIP Common type
254 : * @param tag Tag to be checked
255 : * @return Returns True if the tag is of Common type
256 : **/
257 43 : static bool IsCommonTag(uint8_t tag) { return tag < 0x80; }
258 :
259 : /** @brief Checks if the tag is vendor-specific
260 : * @param tag Tag to be checked
261 : * @return Returns True if the tag is Vendor-specific
262 : **/
263 24 : static bool IsVendorTag(uint8_t tag) { return !IsCommonTag(tag); }
264 :
265 : /** @brief Generate a Random Setup Pin Code (Passcode)
266 : *
267 : * This function generates a random passcode within the defined limits (00000001 to 99999998)
268 : * It also checks that the generated passcode is not equal to any invalid passcode values as defined in 5.1.7.1.
269 : *
270 : * @param[out] setupPINCode The generated random setup PIN code.
271 : * @return Returns a CHIP_ERROR_INTERNAL if unable to generate a valid passcode within a reasonable number of attempts,
272 : * CHIP_NO_ERROR otherwise
273 : **/
274 : static CHIP_ERROR generateRandomSetupPin(uint32_t & setupPINCode);
275 :
276 : /**
277 : * @brief Get a list of setup payloads from a string representation.
278 : *
279 : * @param[in] stringRepresentation The string representing the payloads.
280 :
281 : * @param[out] outPayloads On success, the contents of this vector will be
282 : * replaces with the list of parsed payloads. The
283 : * result may have only one entry, or multiple
284 : * entries if concatenated QR codes are used.
285 : *
286 : * On failure, the value of the out param should not
287 : * be relied on to be anything in particular.
288 : */
289 : static CHIP_ERROR FromStringRepresentation(std::string stringRepresentation, std::vector<SetupPayload> & outPayloads);
290 :
291 : private:
292 : std::map<uint8_t, OptionalQRCodeInfo> optionalVendorData;
293 : std::map<uint8_t, OptionalQRCodeInfoExtension> optionalExtensionData;
294 :
295 : /** @brief A function to add an optional QR Code info vendor object
296 : * @param info Optional QR code info object to add
297 : * @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise
298 : **/
299 : CHIP_ERROR addOptionalVendorData(const OptionalQRCodeInfo & info);
300 :
301 : /** @brief A function to add an optional QR Code info CHIP object
302 : * @param info Optional QR code info object to add
303 : * @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise
304 : **/
305 : CHIP_ERROR addOptionalExtensionData(const OptionalQRCodeInfoExtension & info);
306 :
307 : /**
308 : * @brief A function to retrieve the vector of CHIPQRCodeInfo infos
309 : * @return Returns a vector of CHIPQRCodeInfos
310 : **/
311 : std::vector<OptionalQRCodeInfoExtension> getAllOptionalExtensionData() const;
312 :
313 : /** @brief A function to retrieve an optional QR Code info extended object
314 : * @param tag 8 bit [128-255] tag number
315 : * @param info retrieved OptionalQRCodeInfoExtension object
316 : * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
317 : **/
318 : CHIP_ERROR getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const;
319 :
320 : /** @brief A function to retrieve the associated expected numeric value for a tag
321 : * @param tag 8 bit [0-255] tag number
322 : * @return Returns an optionalQRCodeInfoType value
323 : **/
324 : optionalQRCodeInfoType getNumericTypeFor(uint8_t tag) const;
325 : };
326 :
327 : } // namespace chip
|