From 6c692ab3b452475d704abc1ba68dccf073002270 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Thu, 31 Mar 2022 01:16:00 +0200 Subject: [PATCH] [chip-tool] Add commands to generate/update onboarding payloads (#16704) * [Payload] Add SetAllowInvalidPayload and SetForceShortCode methods to QRCodeSetupPayloadGenerator and ManualSetupPayloadGenerator * [chip-tool] Add a command to generate/update a qrcode and a command to generate/update a manual code --- examples/chip-tool/BUILD.gn | 1 + .../chip-tool/commands/payload/Commands.h | 11 +- .../payload/SetupPayloadGenerateCommand.cpp | 107 ++++++++++++++++++ .../payload/SetupPayloadGenerateCommand.h | 76 +++++++++++++ .../ManualSetupPayloadGenerator.cpp | 4 +- .../ManualSetupPayloadGenerator.h | 19 ++++ .../QRCodeSetupPayloadGenerator.cpp | 2 +- .../QRCodeSetupPayloadGenerator.h | 9 ++ 8 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.cpp create mode 100644 examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.h diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn index 2ee00a016ce0c2..c3178d0d457565 100644 --- a/examples/chip-tool/BUILD.gn +++ b/examples/chip-tool/BUILD.gn @@ -69,6 +69,7 @@ static_library("chip-tool-utils") { "commands/pairing/OpenCommissioningWindowCommand.h", "commands/pairing/PairingCommand.cpp", "commands/payload/AdditionalDataParseCommand.cpp", + "commands/payload/SetupPayloadGenerateCommand.cpp", "commands/payload/SetupPayloadParseCommand.cpp", "commands/payload/SetupPayloadVerhoeff.cpp", "commands/tests/TestCommand.cpp", diff --git a/examples/chip-tool/commands/payload/Commands.h b/examples/chip-tool/commands/payload/Commands.h index 7d72b97e702905..1b5eb2c7c5c62a 100644 --- a/examples/chip-tool/commands/payload/Commands.h +++ b/examples/chip-tool/commands/payload/Commands.h @@ -19,6 +19,7 @@ #pragma once #include "AdditionalDataParseCommand.h" +#include "SetupPayloadGenerateCommand.h" #include "SetupPayloadParseCommand.h" #include "SetupPayloadVerhoeff.h" @@ -26,10 +27,12 @@ void registerCommandsPayload(Commands & commands) { const char * clusterName = "Payload"; commands_list clusterCommands = { - make_unique(), - make_unique(), - make_unique(), - make_unique(), + make_unique(), // + make_unique(), // + make_unique(), // + make_unique(), // + make_unique(), // + make_unique(), // }; commands.Register(clusterName, clusterCommands); diff --git a/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.cpp b/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.cpp new file mode 100644 index 00000000000000..a9f18be49cd1e6 --- /dev/null +++ b/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + */ + +#include "SetupPayloadGenerateCommand.h" +#include +#include +#include +#include +#include + +using namespace ::chip; + +void SetupPayloadGenerateCommand::ConfigurePayload(SetupPayload & payload) +{ + if (mDiscriminator.HasValue()) + { + payload.discriminator = mDiscriminator.Value(); + } + + if (mSetUpPINCode.HasValue()) + { + payload.setUpPINCode = mSetUpPINCode.Value(); + } + + if (mVersion.HasValue()) + { + payload.version = mVersion.Value(); + } + + if (mVendorId.HasValue()) + { + payload.vendorID = mVendorId.Value(); + } + + if (mProductId.HasValue()) + { + payload.productID = mProductId.Value(); + } + + if (mCommissioningMode.HasValue()) + { + payload.commissioningFlow = static_cast(mCommissioningMode.Value()); + } +} + +CHIP_ERROR SetupPayloadGenerateQRCodeCommand::Run() +{ + SetupPayload payload; + + if (mPayload.HasValue()) + { + QRCodeSetupPayloadParser(mPayload.Value()).populatePayload(payload); + } + + ConfigurePayload(payload); + + if (mRendezvous.HasValue()) + { + payload.rendezvousInformation.SetRaw(mRendezvous.Value()); + } + + QRCodeSetupPayloadGenerator generator(payload); + generator.SetAllowInvalidPayload(mAllowInvalidPayload.ValueOr(false)); + + std::string code; + ReturnErrorOnFailure(generator.payloadBase38Representation(code)); + ChipLogProgress(chipTool, "QR Code: %s", code.c_str()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR SetupPayloadGenerateManualCodeCommand::Run() +{ + SetupPayload payload; + + if (mPayload.HasValue()) + { + ManualSetupPayloadParser(mPayload.Value()).populatePayload(payload); + } + + ConfigurePayload(payload); + + ManualSetupPayloadGenerator generator(payload); + generator.SetAllowInvalidPayload(mAllowInvalidPayload.ValueOr(false)); + generator.SetForceShortCode(mForceShortCode.ValueOr(false)); + + std::string code; + ReturnErrorOnFailure(generator.payloadDecimalStringRepresentation(code)); + ChipLogProgress(chipTool, "Manual Code: %s", code.c_str()); + + return CHIP_NO_ERROR; +} diff --git a/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.h b/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.h new file mode 100644 index 00000000000000..9e0d13c7cef3b2 --- /dev/null +++ b/examples/chip-tool/commands/payload/SetupPayloadGenerateCommand.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + */ + +#pragma once + +#include "../common/Command.h" +#include + +class SetupPayloadGenerateCommand : public Command +{ +public: + SetupPayloadGenerateCommand(const char * name) : Command(name) + { + AddArgument("payload", &mPayload); + AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator); + AddArgument("setup-pin-code", 0, UINT32_MAX, &mSetUpPINCode); + AddArgument("version", 0, UINT8_MAX, &mVersion); + AddArgument("vendor-id", 0, UINT16_MAX, &mVendorId); + AddArgument("product-id", 0, UINT16_MAX, &mProductId); + AddArgument("commissioning-mode", 0, UINT8_MAX, &mCommissioningMode); + AddArgument("allow-invalid-payload", 0, 1, &mAllowInvalidPayload); + } + +protected: + void ConfigurePayload(chip::SetupPayload & payload); + + chip::Optional mDiscriminator; + chip::Optional mSetUpPINCode; + chip::Optional mVersion; + chip::Optional mVendorId; + chip::Optional mProductId; + chip::Optional mPayload; + chip::Optional mCommissioningMode; + chip::Optional mAllowInvalidPayload; +}; + +class SetupPayloadGenerateQRCodeCommand : public SetupPayloadGenerateCommand +{ +public: + SetupPayloadGenerateQRCodeCommand() : SetupPayloadGenerateCommand("generate-qrcode") + { + AddArgument("rendezvous", 0, UINT8_MAX, &mRendezvous); + } + CHIP_ERROR Run() override; + +private: + chip::Optional mRendezvous; +}; + +class SetupPayloadGenerateManualCodeCommand : public SetupPayloadGenerateCommand +{ +public: + SetupPayloadGenerateManualCodeCommand() : SetupPayloadGenerateCommand("generate-manualcode") + { + AddArgument("force-short-code", 0, 1, &mForceShortCode); + } + CHIP_ERROR Run() override; + +private: + chip::Optional mForceShortCode; +}; diff --git a/src/setup_payload/ManualSetupPayloadGenerator.cpp b/src/setup_payload/ManualSetupPayloadGenerator.cpp index e8d7a6289c91a4..a1e26dbcb93073 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.cpp +++ b/src/setup_payload/ManualSetupPayloadGenerator.cpp @@ -109,13 +109,13 @@ CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(Mutab static_assert(kManualSetupChunk2PINCodeLsbitsLength + kManualSetupChunk3PINCodeMsbitsLength == kSetupPINCodeFieldLengthInBits, "PIN code won't fit"); - if (!mPayloadContents.isValidManualCode()) + if (!mAllowInvalidPayload && !mPayloadContents.isValidManualCode()) { ChipLogError(SetupPayload, "Failed encoding invalid payload"); return CHIP_ERROR_INVALID_ARGUMENT; } - bool useLongCode = (mPayloadContents.commissioningFlow != CommissioningFlow::kStandard); + bool useLongCode = (mPayloadContents.commissioningFlow != CommissioningFlow::kStandard) && !mForceShortCode; // Add two for the check digit and null terminator. if ((useLongCode && outBuffer.size() < kManualSetupLongCodeCharLength + 2) || diff --git a/src/setup_payload/ManualSetupPayloadGenerator.h b/src/setup_payload/ManualSetupPayloadGenerator.h index 2d85e903035b49..bb04735f1b3d1c 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.h +++ b/src/setup_payload/ManualSetupPayloadGenerator.h @@ -70,6 +70,25 @@ class ManualSetupPayloadGenerator // Populates decimal string representation of the payload into outDecimalString. // Wrapper for using std::string. CHIP_ERROR payloadDecimalStringRepresentation(std::string & outDecimalString); + + /** + * This function disables internal checks about the validity of the generated payload. + * It allows using the generator to generate invalid payloads. + * Default is false. + */ + void SetAllowInvalidPayload(bool allow) { mAllowInvalidPayload = allow; } + + /** + * This function allow forcing the generation of a short code when the commissioning + * flow is not standard by ignoring the vendor id and product id informations but with + * the VID/PID present flag set. + * Default is false. + */ + void SetForceShortCode(bool useShort) { mForceShortCode = useShort; } + +private: + bool mAllowInvalidPayload = false; + bool mForceShortCode = false; }; } // namespace chip diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp index 86c8d44d605166..c8e7dc7fc1b2ad 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp @@ -213,7 +213,7 @@ CHIP_ERROR QRCodeSetupPayloadGenerator::payloadBase38Representation(std::string { size_t tlvDataLengthInBytes = 0; - VerifyOrReturnError(mPayload.isValidQRCodePayload(), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(mAllowInvalidPayload || mPayload.isValidQRCodePayload(), CHIP_ERROR_INVALID_ARGUMENT); ReturnErrorOnFailure(generateTLVFromOptionalData(mPayload, tlvDataStart, tlvDataStartSize, tlvDataLengthInBytes)); std::vector bits(kTotalPayloadDataSizeInBytes + tlvDataLengthInBytes); diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.h b/src/setup_payload/QRCodeSetupPayloadGenerator.h index 091b6df5b459d8..c82aaa6ac71f77 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.h +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.h @@ -82,9 +82,18 @@ class QRCodeSetupPayloadGenerator */ CHIP_ERROR payloadBase38Representation(std::string & base38Representation, uint8_t * tlvDataStart, uint32_t tlvDataStartSize); + /** + * This function disable internal checks about the validity of the generated payload. + * It allows using the generator to generates invalid payloads. + * Defaults is false. + */ + void SetAllowInvalidPayload(bool allow) { mAllowInvalidPayload = allow; } + private: CHIP_ERROR generateTLVFromOptionalData(SetupPayload & outPayload, uint8_t * tlvDataStart, uint32_t maxLen, size_t & tlvDataLengthInBytes); + + bool mAllowInvalidPayload = false; }; /**