/* * * 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 #include #include #include #include #include #include #include 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; 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 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 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 optionalVendorData; std::map 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 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