From 2ce04b5980f329cc4cb224f64e261c7da5f4419b Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Wed, 12 Apr 2023 18:42:26 +0200 Subject: [PATCH] [Yaml] Add a test adding a new fabric from an existing fabric (#25969) * [chip-tool] Add GetCommissionerRootCertificate command [chip-tool] Add IssueNocChain command * Add src/app/tests/suites/Test_AddNewFabricFromExistingFabric.yaml test working with the chip-tool python yaml runner --------- Co-authored-by: Andrei Litvin --- examples/chip-tool/BUILD.gn | 1 + .../chip-tool/commands/common/CHIPCommand.cpp | 37 +++-- .../chip-tool/commands/common/CHIPCommand.h | 10 +- .../commands/common/RemoteDataModelLogger.cpp | 32 ++++ .../commands/common/RemoteDataModelLogger.h | 3 + .../chip-tool/commands/pairing/Commands.h | 4 + .../GetCommissionerRootCertificateCommand.h | 50 ++++++ .../commands/pairing/IssueNOCChainCommand.h | 86 ++++++++++ .../chip-tool/commands/pairing/ToTLVCert.cpp | 52 ++++++ .../chip-tool/commands/pairing/ToTLVCert.h | 25 +++ .../matter_chip_tool_adapter/encoder.py | 13 +- .../matter_yamltests/fixes.py | 6 +- .../clusters/commissioner_commands.py | 20 +++ scripts/tests/chiptest/__init__.py | 4 +- .../Test_AddNewFabricFromExistingFabric.yaml | 156 ++++++++++++++++++ 15 files changed, 483 insertions(+), 16 deletions(-) create mode 100644 examples/chip-tool/commands/pairing/GetCommissionerRootCertificateCommand.h create mode 100644 examples/chip-tool/commands/pairing/IssueNOCChainCommand.h create mode 100644 examples/chip-tool/commands/pairing/ToTLVCert.cpp create mode 100644 examples/chip-tool/commands/pairing/ToTLVCert.h create mode 100644 src/app/tests/suites/Test_AddNewFabricFromExistingFabric.yaml diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn index fc9e1e63a7d31f..85f1c56e2d8266 100644 --- a/examples/chip-tool/BUILD.gn +++ b/examples/chip-tool/BUILD.gn @@ -75,6 +75,7 @@ static_library("chip-tool-utils") { "commands/pairing/OpenCommissioningWindowCommand.cpp", "commands/pairing/OpenCommissioningWindowCommand.h", "commands/pairing/PairingCommand.cpp", + "commands/pairing/ToTLVCert.cpp", "commands/payload/AdditionalDataParseCommand.cpp", "commands/payload/SetupPayloadGenerateCommand.cpp", "commands/payload/SetupPayloadParseCommand.cpp", diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index 498c61f6123912..d64db23eb072b2 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -333,6 +333,22 @@ CHIP_ERROR CHIPCommand::GetIdentityNodeId(std::string identity, chip::NodeId * n return CHIP_NO_ERROR; } +CHIP_ERROR CHIPCommand::GetIdentityRootCertificate(std::string identity, chip::ByteSpan & span) +{ + if (identity == kIdentityNull) + { + return CHIP_ERROR_NOT_FOUND; + } + + chip::NodeId nodeId; + VerifyOrDie(GetIdentityNodeId(identity, &nodeId) == CHIP_NO_ERROR); + CommissionerIdentity lookupKey{ identity, nodeId }; + auto item = mCommissioners.find(lookupKey); + + span = chip::ByteSpan(item->first.mRCAC, item->first.mRCACLen); + return CHIP_NO_ERROR; +} + chip::FabricId CHIPCommand::CurrentCommissionerId() { chip::FabricId id; @@ -388,21 +404,13 @@ void CHIPCommand::ShutdownCommissioner(const CommissionerIdentity & key) mCommissioners[key].get()->Shutdown(); } -CHIP_ERROR CHIPCommand::InitializeCommissioner(const CommissionerIdentity & identity, chip::FabricId fabricId) +CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, chip::FabricId fabricId) { - chip::Platform::ScopedMemoryBuffer noc; - chip::Platform::ScopedMemoryBuffer icac; - chip::Platform::ScopedMemoryBuffer rcac; - std::unique_ptr commissioner = std::make_unique(); chip::Controller::SetupParams commissionerParams; ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore)); - VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(rcac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - chip::Crypto::P256Keypair ephemeralKey; if (fabricId != chip::kUndefinedFabricId) @@ -420,15 +428,20 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(const CommissionerIdentity & iden ReturnLogErrorOnFailure(mCredIssuerCmds->InitializeCredentialsIssuer(mCommissionerStorage)); - chip::MutableByteSpan nocSpan(noc.Get(), chip::Controller::kMaxCHIPDERCertLength); - chip::MutableByteSpan icacSpan(icac.Get(), chip::Controller::kMaxCHIPDERCertLength); - chip::MutableByteSpan rcacSpan(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength); + chip::MutableByteSpan nocSpan(identity.mNOC); + chip::MutableByteSpan icacSpan(identity.mICAC); + chip::MutableByteSpan rcacSpan(identity.mRCAC); ReturnLogErrorOnFailure(ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA)); ReturnLogErrorOnFailure(mCredIssuerCmds->GenerateControllerNOCChain(identity.mLocalNodeId, fabricId, mCommissionerStorage.GetCommissionerCATs(), ephemeralKey, rcacSpan, icacSpan, nocSpan)); + + identity.mRCACLen = rcacSpan.size(); + identity.mICACLen = icacSpan.size(); + identity.mNOCLen = nocSpan.size(); + commissionerParams.operationalKeypair = &ephemeralKey; commissionerParams.controllerRCAC = rcacSpan; commissionerParams.controllerICAC = icacSpan; diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index 265275416474f3..3f16ff95c4cd36 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -155,6 +155,7 @@ class CHIPCommand : public Command std::string GetIdentity(); CHIP_ERROR GetIdentityNodeId(std::string identity, chip::NodeId * nodeId); + CHIP_ERROR GetIdentityRootCertificate(std::string identity, chip::ByteSpan & span); void SetIdentity(const char * name); // This method returns the commissioner instance to be used for running the command. @@ -179,12 +180,19 @@ class CHIPCommand : public Command } std::string mName; chip::NodeId mLocalNodeId; + uint8_t mRCAC[chip::Controller::kMaxCHIPDERCertLength] = {}; + uint8_t mICAC[chip::Controller::kMaxCHIPDERCertLength] = {}; + uint8_t mNOC[chip::Controller::kMaxCHIPDERCertLength] = {}; + + size_t mRCACLen; + size_t mICACLen; + size_t mNOCLen; }; // InitializeCommissioner uses various members, so can't be static. This is // obviously a little odd, since the commissioners are then shared across // multiple commands in interactive mode... - CHIP_ERROR InitializeCommissioner(const CommissionerIdentity & identity, chip::FabricId fabricId); + CHIP_ERROR InitializeCommissioner(CommissionerIdentity & identity, chip::FabricId fabricId); void ShutdownCommissioner(const CommissionerIdentity & key); chip::FabricId CurrentCommissionerId(); diff --git a/examples/chip-tool/commands/common/RemoteDataModelLogger.cpp b/examples/chip-tool/commands/common/RemoteDataModelLogger.cpp index 821370d43b5c3c..45cd4461dae7ab 100644 --- a/examples/chip-tool/commands/common/RemoteDataModelLogger.cpp +++ b/examples/chip-tool/commands/common/RemoteDataModelLogger.cpp @@ -30,6 +30,10 @@ constexpr const char * kErrorIdKey = "error"; constexpr const char * kClusterErrorIdKey = "clusterError"; constexpr const char * kValueKey = "value"; constexpr const char * kNodeIdKey = "nodeId"; +constexpr const char * kNOCKey = "NOC"; +constexpr const char * kICACKey = "ICAC"; +constexpr const char * kRCACKey = "RCAC"; +constexpr const char * kIPKKey = "IPK"; namespace { RemoteDataModelLoggerDelegate * gDelegate; @@ -53,6 +57,7 @@ CHIP_ERROR LogError(Json::Value & value, const chip::app::StatusIB & status) auto valueStr = chip::JsonToString(value); return gDelegate->LogJSON(valueStr.c_str()); } + } // namespace namespace RemoteDataModelLogger { @@ -165,6 +170,33 @@ CHIP_ERROR LogGetCommissionerNodeId(chip::NodeId value) return gDelegate->LogJSON(valueStr.c_str()); } +CHIP_ERROR LogGetCommissionerRootCertificate(const char * value) +{ + VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR); + + Json::Value rootValue; + rootValue[kValueKey] = Json::Value(); + rootValue[kValueKey][kRCACKey] = value; + + auto valueStr = chip::JsonToString(rootValue); + return gDelegate->LogJSON(valueStr.c_str()); +} + +CHIP_ERROR LogIssueNOCChain(const char * noc, const char * icac, const char * rcac, const char * ipk) +{ + VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR); + + Json::Value rootValue; + rootValue[kValueKey] = Json::Value(); + rootValue[kValueKey][kNOCKey] = noc; + rootValue[kValueKey][kICACKey] = icac; + rootValue[kValueKey][kRCACKey] = rcac; + rootValue[kValueKey][kIPKKey] = ipk; + + auto valueStr = chip::JsonToString(rootValue); + return gDelegate->LogJSON(valueStr.c_str()); +} + CHIP_ERROR LogDiscoveredNodeData(const chip::Dnssd::DiscoveredNodeData & nodeData) { VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR); diff --git a/examples/chip-tool/commands/common/RemoteDataModelLogger.h b/examples/chip-tool/commands/common/RemoteDataModelLogger.h index 8289a69e22eff5..7c93a50aa1f191 100644 --- a/examples/chip-tool/commands/common/RemoteDataModelLogger.h +++ b/examples/chip-tool/commands/common/RemoteDataModelLogger.h @@ -22,6 +22,7 @@ #include #include #include +#include #include class RemoteDataModelLoggerDelegate @@ -40,6 +41,8 @@ CHIP_ERROR LogEventAsJSON(const chip::app::EventHeader & header, chip::TLV::TLVR CHIP_ERROR LogErrorAsJSON(const chip::app::EventHeader & header, const chip::app::StatusIB & status); CHIP_ERROR LogErrorAsJSON(const CHIP_ERROR & error); CHIP_ERROR LogGetCommissionerNodeId(chip::NodeId value); +CHIP_ERROR LogGetCommissionerRootCertificate(const char * value); +CHIP_ERROR LogIssueNOCChain(const char * noc, const char * icac, const char * rcac, const char * ipk); CHIP_ERROR LogDiscoveredNodeData(const chip::Dnssd::DiscoveredNodeData & nodeData); void SetDelegate(RemoteDataModelLoggerDelegate * delegate); }; // namespace RemoteDataModelLogger diff --git a/examples/chip-tool/commands/pairing/Commands.h b/examples/chip-tool/commands/pairing/Commands.h index a1f11855f93d26..4f4f445d929a8c 100644 --- a/examples/chip-tool/commands/pairing/Commands.h +++ b/examples/chip-tool/commands/pairing/Commands.h @@ -21,6 +21,8 @@ #include "commands/common/Commands.h" #include "commands/pairing/CloseSessionCommand.h" #include "commands/pairing/GetCommissionerNodeIdCommand.h" +#include "commands/pairing/GetCommissionerRootCertificateCommand.h" +#include "commands/pairing/IssueNOCChainCommand.h" #include "commands/pairing/OpenCommissioningWindowCommand.h" #include "commands/pairing/PairingCommand.h" @@ -241,6 +243,8 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), }; commands.Register(clusterName, clusterCommands); diff --git a/examples/chip-tool/commands/pairing/GetCommissionerRootCertificateCommand.h b/examples/chip-tool/commands/pairing/GetCommissionerRootCertificateCommand.h new file mode 100644 index 00000000000000..7a350a9ca16bb8 --- /dev/null +++ b/examples/chip-tool/commands/pairing/GetCommissionerRootCertificateCommand.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 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/CHIPCommand.h" + +#include "ToTLVCert.h" + +class GetCommissionerRootCertificateCommand : public CHIPCommand +{ +public: + GetCommissionerRootCertificateCommand(CredentialIssuerCommands * credIssuerCommands) : + CHIPCommand("get-commissioner-root-certificate", credIssuerCommands, + "Returns a base64-encoded RCAC prefixed with: 'base64:'") + {} + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override + { + chip::ByteSpan span; + ReturnErrorOnFailure(GetIdentityRootCertificate(GetIdentity(), span)); + + std::string rcac; + ReturnErrorOnFailure(ToTLVCert(span, rcac)); + ChipLogProgress(chipTool, "RCAC: %s", rcac.c_str()); + + ReturnErrorOnFailure(RemoteDataModelLogger::LogGetCommissionerRootCertificate(rcac.c_str())); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; + } + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); } +}; diff --git a/examples/chip-tool/commands/pairing/IssueNOCChainCommand.h b/examples/chip-tool/commands/pairing/IssueNOCChainCommand.h new file mode 100644 index 00000000000000..a4de2dadfc0664 --- /dev/null +++ b/examples/chip-tool/commands/pairing/IssueNOCChainCommand.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 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/CHIPCommand.h" + +#include "ToTLVCert.h" + +class IssueNOCChainCommand : public CHIPCommand +{ +public: + IssueNOCChainCommand(CredentialIssuerCommands * credIssuerCommands) : + CHIPCommand("issue-noc-chain", credIssuerCommands, + "Returns a base64-encoded NOC, ICAC, RCAC, and IPK prefixed with: 'base64:'"), + mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this) + { + AddArgument("elements", &mNOCSRElements, "NOCSRElements encoded in hexadecimal"); + AddArgument("node-id", 0, UINT64_MAX, &mNodeId, "The target node id"); + } + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override + { + auto & commissioner = CurrentCommissioner(); + ReturnErrorOnFailure(commissioner.IssueNOCChain(mNOCSRElements, mNodeId, &mDeviceNOCChainCallback)); + return CHIP_NO_ERROR; + } + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); } + + static void OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const chip::ByteSpan & noc, + const chip::ByteSpan & icac, const chip::ByteSpan & rcac, + chip::Optional ipk, + chip::Optional adminSubject) + { + auto command = static_cast(context); + + auto err = status; + VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err)); + + std::string nocStr; + err = ToTLVCert(noc, nocStr); + VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err)); + ChipLogProgress(chipTool, "NOC: %s", nocStr.c_str()); + + std::string icacStr; + err = ToTLVCert(icac, icacStr); + VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err)); + ChipLogProgress(chipTool, "ICAC: %s", icacStr.c_str()); + + std::string rcacStr; + err = ToTLVCert(rcac, rcacStr); + VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err)); + ChipLogProgress(chipTool, "RCAC: %s", rcacStr.c_str()); + + auto ipkValue = ipk.ValueOr(chip::Crypto::IdentityProtectionKeySpan()); + std::string ipkStr; + err = ToBase64(ipkValue, ipkStr); + VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err)); + ChipLogProgress(chipTool, "IPK: %s", ipkStr.c_str()); + + err = RemoteDataModelLogger::LogIssueNOCChain(nocStr.c_str(), icacStr.c_str(), rcacStr.c_str(), ipkStr.c_str()); + command->SetCommandExitStatus(err); + } + +private: + chip::Callback::Callback mDeviceNOCChainCallback; + chip::ByteSpan mNOCSRElements; + chip::NodeId mNodeId; +}; diff --git a/examples/chip-tool/commands/pairing/ToTLVCert.cpp b/examples/chip-tool/commands/pairing/ToTLVCert.cpp new file mode 100644 index 00000000000000..f17769df64efac --- /dev/null +++ b/examples/chip-tool/commands/pairing/ToTLVCert.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 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 "ToTLVCert.h" + +#include +#include + +constexpr const char kBase64Header[] = "base64:"; +constexpr size_t kBase64HeaderLen = ArraySize(kBase64Header) - 1; + +CHIP_ERROR ToBase64(const chip::ByteSpan & input, std::string & outputAsPrefixedBase64) +{ + chip::Platform::ScopedMemoryBuffer base64String; + base64String.Alloc(kBase64HeaderLen + BASE64_ENCODED_LEN(input.size()) + 1); + VerifyOrReturnError(base64String.Get() != nullptr, CHIP_ERROR_NO_MEMORY); + + auto encodedLen = chip::Base64Encode(input.data(), static_cast(input.size()), base64String.Get() + kBase64HeaderLen); + if (encodedLen) + { + memcpy(base64String.Get(), kBase64Header, kBase64HeaderLen); + encodedLen = static_cast(encodedLen + kBase64HeaderLen); + } + base64String.Get()[encodedLen] = '\0'; + outputAsPrefixedBase64 = std::string(base64String.Get(), encodedLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ToTLVCert(const chip::ByteSpan & derEncodedCertificate, std::string & tlvCertAsPrefixedBase64) +{ + uint8_t chipCertBuffer[chip::Credentials::kMaxCHIPCertLength]; + chip::MutableByteSpan chipCertBytes(chipCertBuffer); + ReturnErrorOnFailure(chip::Credentials::ConvertX509CertToChipCert(derEncodedCertificate, chipCertBytes)); + ReturnErrorOnFailure(ToBase64(chipCertBytes, tlvCertAsPrefixedBase64)); + return CHIP_NO_ERROR; +} diff --git a/examples/chip-tool/commands/pairing/ToTLVCert.h b/examples/chip-tool/commands/pairing/ToTLVCert.h new file mode 100644 index 00000000000000..bcac763f429f8b --- /dev/null +++ b/examples/chip-tool/commands/pairing/ToTLVCert.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 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 +#include + +CHIP_ERROR ToBase64(const chip::ByteSpan & input, std::string & outputAsPrefixedBase64); +CHIP_ERROR ToTLVCert(const chip::ByteSpan & derEncodedCertificate, std::string & tlvCertAsPrefixedBase64); diff --git a/examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py b/examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py index ffba568adb644b..0dbca4a359a2e9 100644 --- a/examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py +++ b/examples/chip-tool/py_matter_chip_tool_adapter/matter_chip_tool_adapter/encoder.py @@ -32,7 +32,18 @@ 'GetCommissionerNodeId': { 'has_destination': False, 'has_endpoint': False, - } + }, + 'GetCommissionerRootCertificate': { + 'has_destination': False, + 'has_endpoint': False, + }, + 'IssueNocChain': { + 'arguments': { + 'nodeId': 'node-id', + }, + 'has_destination': False, + 'has_endpoint': False, + }, } }, diff --git a/scripts/py_matter_yamltests/matter_yamltests/fixes.py b/scripts/py_matter_yamltests/matter_yamltests/fixes.py index 0223c2e1a486f1..5ddfd97e9c1e6f 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/fixes.py +++ b/scripts/py_matter_yamltests/matter_yamltests/fixes.py @@ -85,7 +85,11 @@ def convert_yaml_octet_string_to_bytes(s: str) -> bytes: if s.startswith('hex:'): return binascii.unhexlify(s[4:]) - # Step 2: convert non-hex-prefixed to bytes + # Step 2: handle explicit "base64:" prefix + if s.startswith('base64:'): + return binascii.a2b_base64(s[7:]) + + # Step 3: convert non-hex-prefixed to bytes # TODO(#23669): This does not properly support utf8 octet strings. We mimic # javascript codegen behavior. Behavior of javascript is: # * Octet string character >= u+0200 errors out. diff --git a/scripts/py_matter_yamltests/matter_yamltests/pseudo_clusters/clusters/commissioner_commands.py b/scripts/py_matter_yamltests/matter_yamltests/pseudo_clusters/clusters/commissioner_commands.py index 08e22da1bb62b6..d3cc92b7aa10b9 100644 --- a/scripts/py_matter_yamltests/matter_yamltests/pseudo_clusters/clusters/commissioner_commands.py +++ b/scripts/py_matter_yamltests/matter_yamltests/pseudo_clusters/clusters/commissioner_commands.py @@ -37,6 +37,26 @@ + + + + + + + + + + + + + + + + + + + + ''' diff --git a/scripts/tests/chiptest/__init__.py b/scripts/tests/chiptest/__init__.py index 7692ac08e8074f..9ddbc0ef8f2d21 100644 --- a/scripts/tests/chiptest/__init__.py +++ b/scripts/tests/chiptest/__init__.py @@ -133,7 +133,9 @@ def _GetInDevelopmentTests() -> Set[str]: Currently this is empty and returns an empty set, but this is kept around in case there are tests that are a work in progress. """ - return set() + return { + "Test_AddNewFabricFromExistingFabric.yaml", # chip-repl does not support GetCommissionerRootCertificate and IssueNocChain command + } def _AllYamlTests(): diff --git a/src/app/tests/suites/Test_AddNewFabricFromExistingFabric.yaml b/src/app/tests/suites/Test_AddNewFabricFromExistingFabric.yaml new file mode 100644 index 00000000000000..9890afb851586c --- /dev/null +++ b/src/app/tests/suites/Test_AddNewFabricFromExistingFabric.yaml @@ -0,0 +1,156 @@ +# Copyright (c) 2023 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. + +name: Test + +config: + nodeId: 0x12344321 + endpoint: 0 + +tests: + - label: "Wait for the alpha device to be retrieved " + cluster: "DelayCommands" + command: "WaitForCommissionee" + arguments: + values: + - name: "nodeId" + value: nodeId + + - label: "Read the fabrics list from alpha" + command: "readAttribute" + cluster: "Operational Credentials" + attribute: "Fabrics" + response: + value: [{ Label: "", NodeID: nodeId }] + constraints: + type: list + + - label: + "Send ArmFailSafe command to target device with ExpiryLengthSeconds 60 + seconds" + cluster: "General Commissioning" + command: "ArmFailSafe" + arguments: + values: + - name: "ExpiryLengthSeconds" + value: 60 + - name: "Breadcrumb" + value: 0 + + - label: "Send CSRRequest command from alpha" + command: "CSRRequest" + cluster: "Operational Credentials" + arguments: + values: + - name: CSRNonce + value: "\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07" + response: + values: + - name: "NOCSRElements" + saveAs: NOCSRElements + - name: "AttestationSignature" + saveAs: attestationSignature + + - label: "Read the commissioner node ID from the beta fabric" + identity: "beta" + cluster: "CommissionerCommands" + command: "GetCommissionerNodeId" + response: + values: + - name: "nodeId" + saveAs: commissionerNodeIdBeta + + - label: "Read the commissioner root certificate from the beta fabric" + identity: "beta" + cluster: "CommissionerCommands" + command: "GetCommissionerRootCertificate" + response: + values: + - name: "RCAC" + saveAs: commissionerRCACBeta + + - label: + "Create a NOC chain for commissioner beta with the results of the + CSRRequest from alpha" + identity: "beta" + cluster: "CommissionerCommands" + command: "IssueNocChain" + arguments: + values: + - name: "Elements" + value: NOCSRElements + - name: "nodeId" + value: 0x43211234 + response: + values: + - name: "NOC" + saveAs: noc + - name: "ICAC" + saveAs: icac + - name: "IPK" + saveAs: ipk + + - label: "Send AddTrustedRootCertificate command from alpha" + command: "AddTrustedRootCertificate" + cluster: "Operational Credentials" + arguments: + values: + - name: "RootCACertificate" + value: commissionerRCACBeta + + - label: "Send AddNOC command from alpha" + command: "AddNOC" + cluster: "Operational Credentials" + arguments: + values: + - name: "NOCValue" + value: noc + - name: "ICACValue" + value: icac + - name: "IPKValue" + value: ipk + - name: "CaseAdminSubject" + value: commissionerNodeIdBeta + - name: "AdminVendorId" + value: 0xFFF1 + response: + values: + - name: "StatusCode" + value: 0 + + - label: "Send Commissioning Complete command from beta" + nodeId: 0x43211234 + identity: "beta" + cluster: "General Commissioning" + command: "CommissioningComplete" + + - label: "Read the fabrics list again from alpha" + command: "readAttribute" + cluster: "Operational Credentials" + attribute: "Fabrics" + response: + value: [{ Label: "", NodeID: nodeId }] + constraints: + type: list + + - label: "Read the fabrics list from beta this time" + identity: "beta" + nodeId: 0x43211234 + command: "readAttribute" + cluster: "Operational Credentials" + attribute: "Fabrics" + response: + value: [{ Label: "", NodeID: 0x43211234 }] + constraints: + type: list