Coverage Report

Created: 2025-08-28 06:31

/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