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