blob: 829af128bf76276a364ee3f40fb6ae313a3d319c [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file describes a QRCode Setup Payload class to hold
* data enumerated from a byte stream
*/
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include <lib/core/CHIPError.h>
#include <lib/core/Optional.h>
#include <lib/support/BitFlags.h>
#include <lib/support/SetupDiscriminator.h>
namespace chip {
// See section 5.1.2. QR Code in the Matter specification
const int kVersionFieldLengthInBits = 3;
const int kVendorIDFieldLengthInBits = 16;
const int kProductIDFieldLengthInBits = 16;
const int kCommissioningFlowFieldLengthInBits = 2;
const int kRendezvousInfoFieldLengthInBits = 8;
const int kPayloadDiscriminatorFieldLengthInBits = SetupDiscriminator::kLongBits;
const int kSetupPINCodeFieldLengthInBits = 27;
const int kPaddingFieldLengthInBits = 4;
const int kRawVendorTagLengthInBits = 7;
// See section 5.1.3. Manual Pairing Code in the Matter specification
const int kManualSetupDiscriminatorFieldLengthInBits = SetupDiscriminator::kShortBits;
const int kManualSetupChunk1DiscriminatorMsbitsPos = 0;
const int kManualSetupChunk1DiscriminatorMsbitsLength = 2;
const int kManualSetupChunk1VidPidPresentBitPos =
(kManualSetupChunk1DiscriminatorMsbitsPos + kManualSetupChunk1DiscriminatorMsbitsLength);
const int kManualSetupChunk2PINCodeLsbitsPos = 0;
const int kManualSetupChunk2PINCodeLsbitsLength = 14;
const int kManualSetupChunk2DiscriminatorLsbitsPos = (kManualSetupChunk2PINCodeLsbitsPos + kManualSetupChunk2PINCodeLsbitsLength);
const int kManualSetupChunk2DiscriminatorLsbitsLength = 2;
const int kManualSetupChunk3PINCodeMsbitsPos = 0;
const int kManualSetupChunk3PINCodeMsbitsLength = 13;
const int kManualSetupShortCodeCharLength = 10;
const int kManualSetupLongCodeCharLength = 20;
const int kManualSetupCodeChunk1CharLength = 1;
const int kManualSetupCodeChunk2CharLength = 5;
const int kManualSetupCodeChunk3CharLength = 4;
const int kManualSetupVendorIdCharLength = 5;
const int kManualSetupProductIdCharLength = 5;
// Spec 5.1.4.2 CHIP-Common Reserved Tags
inline constexpr uint8_t kSerialNumberTag = 0x00;
inline constexpr uint8_t kPBKDFIterationsTag = 0x01;
inline constexpr uint8_t kBPKFSaltTag = 0x02;
inline constexpr uint8_t kNumberOFDevicesTag = 0x03;
inline constexpr uint8_t kCommissioningTimeoutTag = 0x04;
inline constexpr uint32_t kSetupPINCodeMaximumValue = 99999998;
inline constexpr uint32_t kSetupPINCodeUndefinedValue = 0;
static_assert(kSetupPINCodeMaximumValue < (1 << kSetupPINCodeFieldLengthInBits));
// clang-format off
const int kTotalPayloadDataSizeInBits =
kVersionFieldLengthInBits +
kVendorIDFieldLengthInBits +
kProductIDFieldLengthInBits +
kCommissioningFlowFieldLengthInBits +
kRendezvousInfoFieldLengthInBits +
kPayloadDiscriminatorFieldLengthInBits +
kSetupPINCodeFieldLengthInBits +
kPaddingFieldLengthInBits;
// clang-format on
const int kTotalPayloadDataSizeInBytes = kTotalPayloadDataSizeInBits / 8;
const char * const kQRCodePrefix = "MT:";
/// The rendezvous type this device supports.
enum class RendezvousInformationFlag : uint8_t
{
kNone = 0, ///< Device does not support any method for rendezvous
kSoftAP = 1 << 0, ///< Device supports Wi-Fi softAP
kBLE = 1 << 1, ///< Device supports BLE
kOnNetwork = 1 << 2, ///< Device supports Setup on network
kWiFiPAF = 1 << 3, ///< Device supports Wi-Fi Public Action Frame for discovery
};
using RendezvousInformationFlags = chip::BitFlags<RendezvousInformationFlag, uint8_t>;
enum class CommissioningFlow : uint8_t
{
kStandard = 0, ///< Device automatically enters pairing mode upon power-up
kUserActionRequired, ///< Device requires a user interaction to enter pairing mode
kCustom, ///< Commissioning steps should be retrieved from the distributed compliance ledger
};
/**
* A parent struct to hold onboarding payload contents without optional info,
* for compatibility with devices that don't support std::string or STL.
*/
struct PayloadContents
{
uint8_t version = 0;
uint16_t vendorID = 0;
uint16_t productID = 0;
CommissioningFlow commissioningFlow = CommissioningFlow::kStandard;
// rendezvousInformation is Optional, because a payload parsed from a manual
// numeric code would not have any rendezvousInformation available. A
// payload parsed from a QR code would always have a value for
// rendezvousInformation.
Optional<RendezvousInformationFlags> rendezvousInformation;
SetupDiscriminator discriminator{};
uint32_t setUpPINCode = 0;
enum class ValidationMode : uint8_t
{
kProduce, ///< Only flags or values allowed by the current spec version are allowed.
/// Producers of a Setup Payload should use this mode to ensure the
// payload is valid according to the current spec version.
kConsume, ///< Flags or values that are reserved for future use, or were allowed in
/// a previous spec version may be present. Consumers of a Setup Payload
/// should use this mode to ensure they are forward and backwards
/// compatible with payloads from older or newer Matter devices.
};
bool isValidQRCodePayload(ValidationMode mode = ValidationMode::kProduce) const;
bool isValidManualCode(ValidationMode mode = ValidationMode::kProduce) const;
bool operator==(const PayloadContents & input) const;
static bool IsValidSetupPIN(uint32_t setupPIN);
private:
bool CheckPayloadCommonConstraints() const;
};
enum optionalQRCodeInfoType
{
optionalQRCodeInfoTypeUnknown,
optionalQRCodeInfoTypeString,
optionalQRCodeInfoTypeInt32,
optionalQRCodeInfoTypeInt64,
optionalQRCodeInfoTypeUInt32,
optionalQRCodeInfoTypeUInt64
};
/**
* A structure to hold optional QR Code info
*/
struct OptionalQRCodeInfo
{
/*@{*/
uint8_t tag; /**< the tag number of the optional info */
enum optionalQRCodeInfoType type; /**< the type (String or Int) of the optional info */
std::string data; /**< the string value if type is optionalQRCodeInfoTypeString, otherwise should not be set */
int32_t int32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt32, otherwise should not be set */
/*@}*/
};
struct OptionalQRCodeInfoExtension : OptionalQRCodeInfo
{
int64_t int64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt64, otherwise should not be set */
uint64_t uint32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt32, otherwise should not be set */
uint64_t uint64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt64, otherwise should not be set */
};
class SetupPayload : public PayloadContents
{
friend class QRCodeSetupPayloadGenerator;
friend class QRCodeSetupPayloadParser;
public:
/** @brief A function to add an optional vendor data
* @param tag tag number in the [0x80-0xFF] range
* @param data String representation of data to add
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addOptionalVendorData(uint8_t tag, std::string data);
/** @brief A function to add an optional vendor data
* @param tag tag number in the [0x80-0xFF] range
* @param data Integer representation of data to add
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addOptionalVendorData(uint8_t tag, int32_t data);
/** @brief A function to remove an optional vendor data
* @param tag tag number in the [0x80-0xFF] range
* @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR removeOptionalVendorData(uint8_t tag);
/** @brief A function to retrieve an optional QR Code info vendor object
* @param tag tag number in the [0x80-0xFF] range
* @param info retrieved OptionalQRCodeInfo object
* @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const;
/**
* @brief A function to retrieve the vector of OptionalQRCodeInfo infos
* @return Returns a vector of optionalQRCodeInfos
**/
std::vector<OptionalQRCodeInfo> getAllOptionalVendorData() const;
/** @brief A function to add a string serial number
* @param serialNumber string serial number
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addSerialNumber(std::string serialNumber);
/** @brief A function to add a uint32_t serial number
* @param serialNumber uint32_t serial number
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addSerialNumber(uint32_t serialNumber);
/** @brief A function to retrieve serial number as a string
* @param outSerialNumber retrieved string serial number
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR getSerialNumber(std::string & outSerialNumber) const;
/** @brief A function to remove the serial number from the payload
* @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR removeSerialNumber();
bool operator==(const SetupPayload & input) const;
/** @brief Checks if the tag is CHIP Common type
* @param tag Tag to be checked
* @return Returns True if the tag is of Common type
**/
static bool IsCommonTag(uint8_t tag) { return tag < 0x80; }
/** @brief Checks if the tag is vendor-specific
* @param tag Tag to be checked
* @return Returns True if the tag is Vendor-specific
**/
static bool IsVendorTag(uint8_t tag) { return !IsCommonTag(tag); }
/** @brief Generate a Random Setup Pin Code (Passcode)
*
* This function generates a random passcode within the defined limits (00000001 to 99999998)
* It also checks that the generated passcode is not equal to any invalid passcode values as defined in 5.1.7.1.
*
* @param[out] setupPINCode The generated random setup PIN code.
* @return Returns a CHIP_ERROR_INTERNAL if unable to generate a valid passcode within a reasonable number of attempts,
* CHIP_NO_ERROR otherwise
**/
static CHIP_ERROR generateRandomSetupPin(uint32_t & setupPINCode);
private:
std::map<uint8_t, OptionalQRCodeInfo> optionalVendorData;
std::map<uint8_t, OptionalQRCodeInfoExtension> optionalExtensionData;
/** @brief A function to add an optional QR Code info vendor object
* @param info Optional QR code info object to add
* @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addOptionalVendorData(const OptionalQRCodeInfo & info);
/** @brief A function to add an optional QR Code info CHIP object
* @param info Optional QR code info object to add
* @return Returns a CHIP_ERROR_INVALID_ARGUMENT on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR addOptionalExtensionData(const OptionalQRCodeInfoExtension & info);
/**
* @brief A function to retrieve the vector of CHIPQRCodeInfo infos
* @return Returns a vector of CHIPQRCodeInfos
**/
std::vector<OptionalQRCodeInfoExtension> getAllOptionalExtensionData() const;
/** @brief A function to retrieve an optional QR Code info extended object
* @param tag 8 bit [128-255] tag number
* @param info retrieved OptionalQRCodeInfoExtension object
* @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const;
/** @brief A function to retrieve the associated expected numeric value for a tag
* @param tag 8 bit [0-255] tag number
* @return Returns an optionalQRCodeInfoType value
**/
optionalQRCodeInfoType getNumericTypeFor(uint8_t tag) const;
};
} // namespace chip