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