Skip to content

Commit 2027330

Browse files
vivien-appleandy31415
authored andcommitted
[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 <andy314@gmail.com>
1 parent 75818dd commit 2027330

File tree

15 files changed

+483
-16
lines changed

15 files changed

+483
-16
lines changed

examples/chip-tool/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ static_library("chip-tool-utils") {
7575
"commands/pairing/OpenCommissioningWindowCommand.cpp",
7676
"commands/pairing/OpenCommissioningWindowCommand.h",
7777
"commands/pairing/PairingCommand.cpp",
78+
"commands/pairing/ToTLVCert.cpp",
7879
"commands/payload/AdditionalDataParseCommand.cpp",
7980
"commands/payload/SetupPayloadGenerateCommand.cpp",
8081
"commands/payload/SetupPayloadParseCommand.cpp",

examples/chip-tool/commands/common/CHIPCommand.cpp

+25-12
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,22 @@ CHIP_ERROR CHIPCommand::GetIdentityNodeId(std::string identity, chip::NodeId * n
333333
return CHIP_NO_ERROR;
334334
}
335335

336+
CHIP_ERROR CHIPCommand::GetIdentityRootCertificate(std::string identity, chip::ByteSpan & span)
337+
{
338+
if (identity == kIdentityNull)
339+
{
340+
return CHIP_ERROR_NOT_FOUND;
341+
}
342+
343+
chip::NodeId nodeId;
344+
VerifyOrDie(GetIdentityNodeId(identity, &nodeId) == CHIP_NO_ERROR);
345+
CommissionerIdentity lookupKey{ identity, nodeId };
346+
auto item = mCommissioners.find(lookupKey);
347+
348+
span = chip::ByteSpan(item->first.mRCAC, item->first.mRCACLen);
349+
return CHIP_NO_ERROR;
350+
}
351+
336352
chip::FabricId CHIPCommand::CurrentCommissionerId()
337353
{
338354
chip::FabricId id;
@@ -388,21 +404,13 @@ void CHIPCommand::ShutdownCommissioner(const CommissionerIdentity & key)
388404
mCommissioners[key].get()->Shutdown();
389405
}
390406

391-
CHIP_ERROR CHIPCommand::InitializeCommissioner(const CommissionerIdentity & identity, chip::FabricId fabricId)
407+
CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity, chip::FabricId fabricId)
392408
{
393-
chip::Platform::ScopedMemoryBuffer<uint8_t> noc;
394-
chip::Platform::ScopedMemoryBuffer<uint8_t> icac;
395-
chip::Platform::ScopedMemoryBuffer<uint8_t> rcac;
396-
397409
std::unique_ptr<ChipDeviceCommissioner> commissioner = std::make_unique<ChipDeviceCommissioner>();
398410
chip::Controller::SetupParams commissionerParams;
399411

400412
ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sTrustStore));
401413

402-
VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
403-
VerifyOrReturnError(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
404-
VerifyOrReturnError(rcac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
405-
406414
chip::Crypto::P256Keypair ephemeralKey;
407415

408416
if (fabricId != chip::kUndefinedFabricId)
@@ -420,15 +428,20 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(const CommissionerIdentity & iden
420428

421429
ReturnLogErrorOnFailure(mCredIssuerCmds->InitializeCredentialsIssuer(mCommissionerStorage));
422430

423-
chip::MutableByteSpan nocSpan(noc.Get(), chip::Controller::kMaxCHIPDERCertLength);
424-
chip::MutableByteSpan icacSpan(icac.Get(), chip::Controller::kMaxCHIPDERCertLength);
425-
chip::MutableByteSpan rcacSpan(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength);
431+
chip::MutableByteSpan nocSpan(identity.mNOC);
432+
chip::MutableByteSpan icacSpan(identity.mICAC);
433+
chip::MutableByteSpan rcacSpan(identity.mRCAC);
426434

427435
ReturnLogErrorOnFailure(ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA));
428436

429437
ReturnLogErrorOnFailure(mCredIssuerCmds->GenerateControllerNOCChain(identity.mLocalNodeId, fabricId,
430438
mCommissionerStorage.GetCommissionerCATs(),
431439
ephemeralKey, rcacSpan, icacSpan, nocSpan));
440+
441+
identity.mRCACLen = rcacSpan.size();
442+
identity.mICACLen = icacSpan.size();
443+
identity.mNOCLen = nocSpan.size();
444+
432445
commissionerParams.operationalKeypair = &ephemeralKey;
433446
commissionerParams.controllerRCAC = rcacSpan;
434447
commissionerParams.controllerICAC = icacSpan;

examples/chip-tool/commands/common/CHIPCommand.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class CHIPCommand : public Command
155155

156156
std::string GetIdentity();
157157
CHIP_ERROR GetIdentityNodeId(std::string identity, chip::NodeId * nodeId);
158+
CHIP_ERROR GetIdentityRootCertificate(std::string identity, chip::ByteSpan & span);
158159
void SetIdentity(const char * name);
159160

160161
// This method returns the commissioner instance to be used for running the command.
@@ -179,12 +180,19 @@ class CHIPCommand : public Command
179180
}
180181
std::string mName;
181182
chip::NodeId mLocalNodeId;
183+
uint8_t mRCAC[chip::Controller::kMaxCHIPDERCertLength] = {};
184+
uint8_t mICAC[chip::Controller::kMaxCHIPDERCertLength] = {};
185+
uint8_t mNOC[chip::Controller::kMaxCHIPDERCertLength] = {};
186+
187+
size_t mRCACLen;
188+
size_t mICACLen;
189+
size_t mNOCLen;
182190
};
183191

184192
// InitializeCommissioner uses various members, so can't be static. This is
185193
// obviously a little odd, since the commissioners are then shared across
186194
// multiple commands in interactive mode...
187-
CHIP_ERROR InitializeCommissioner(const CommissionerIdentity & identity, chip::FabricId fabricId);
195+
CHIP_ERROR InitializeCommissioner(CommissionerIdentity & identity, chip::FabricId fabricId);
188196
void ShutdownCommissioner(const CommissionerIdentity & key);
189197
chip::FabricId CurrentCommissionerId();
190198

examples/chip-tool/commands/common/RemoteDataModelLogger.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ constexpr const char * kErrorIdKey = "error";
3030
constexpr const char * kClusterErrorIdKey = "clusterError";
3131
constexpr const char * kValueKey = "value";
3232
constexpr const char * kNodeIdKey = "nodeId";
33+
constexpr const char * kNOCKey = "NOC";
34+
constexpr const char * kICACKey = "ICAC";
35+
constexpr const char * kRCACKey = "RCAC";
36+
constexpr const char * kIPKKey = "IPK";
3337

3438
namespace {
3539
RemoteDataModelLoggerDelegate * gDelegate;
@@ -53,6 +57,7 @@ CHIP_ERROR LogError(Json::Value & value, const chip::app::StatusIB & status)
5357
auto valueStr = chip::JsonToString(value);
5458
return gDelegate->LogJSON(valueStr.c_str());
5559
}
60+
5661
} // namespace
5762

5863
namespace RemoteDataModelLogger {
@@ -165,6 +170,33 @@ CHIP_ERROR LogGetCommissionerNodeId(chip::NodeId value)
165170
return gDelegate->LogJSON(valueStr.c_str());
166171
}
167172

173+
CHIP_ERROR LogGetCommissionerRootCertificate(const char * value)
174+
{
175+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
176+
177+
Json::Value rootValue;
178+
rootValue[kValueKey] = Json::Value();
179+
rootValue[kValueKey][kRCACKey] = value;
180+
181+
auto valueStr = chip::JsonToString(rootValue);
182+
return gDelegate->LogJSON(valueStr.c_str());
183+
}
184+
185+
CHIP_ERROR LogIssueNOCChain(const char * noc, const char * icac, const char * rcac, const char * ipk)
186+
{
187+
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);
188+
189+
Json::Value rootValue;
190+
rootValue[kValueKey] = Json::Value();
191+
rootValue[kValueKey][kNOCKey] = noc;
192+
rootValue[kValueKey][kICACKey] = icac;
193+
rootValue[kValueKey][kRCACKey] = rcac;
194+
rootValue[kValueKey][kIPKKey] = ipk;
195+
196+
auto valueStr = chip::JsonToString(rootValue);
197+
return gDelegate->LogJSON(valueStr.c_str());
198+
}
199+
168200
CHIP_ERROR LogDiscoveredNodeData(const chip::Dnssd::DiscoveredNodeData & nodeData)
169201
{
170202
VerifyOrReturnError(gDelegate != nullptr, CHIP_NO_ERROR);

examples/chip-tool/commands/common/RemoteDataModelLogger.h

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <app/ConcreteCommandPath.h>
2323
#include <app/EventHeader.h>
2424
#include <app/MessageDef/StatusIB.h>
25+
#include <crypto/CHIPCryptoPAL.h>
2526
#include <lib/dnssd/Resolver.h>
2627

2728
class RemoteDataModelLoggerDelegate
@@ -40,6 +41,8 @@ CHIP_ERROR LogEventAsJSON(const chip::app::EventHeader & header, chip::TLV::TLVR
4041
CHIP_ERROR LogErrorAsJSON(const chip::app::EventHeader & header, const chip::app::StatusIB & status);
4142
CHIP_ERROR LogErrorAsJSON(const CHIP_ERROR & error);
4243
CHIP_ERROR LogGetCommissionerNodeId(chip::NodeId value);
44+
CHIP_ERROR LogGetCommissionerRootCertificate(const char * value);
45+
CHIP_ERROR LogIssueNOCChain(const char * noc, const char * icac, const char * rcac, const char * ipk);
4346
CHIP_ERROR LogDiscoveredNodeData(const chip::Dnssd::DiscoveredNodeData & nodeData);
4447
void SetDelegate(RemoteDataModelLoggerDelegate * delegate);
4548
}; // namespace RemoteDataModelLogger

examples/chip-tool/commands/pairing/Commands.h

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "commands/common/Commands.h"
2222
#include "commands/pairing/CloseSessionCommand.h"
2323
#include "commands/pairing/GetCommissionerNodeIdCommand.h"
24+
#include "commands/pairing/GetCommissionerRootCertificateCommand.h"
25+
#include "commands/pairing/IssueNOCChainCommand.h"
2426
#include "commands/pairing/OpenCommissioningWindowCommand.h"
2527
#include "commands/pairing/PairingCommand.h"
2628

@@ -241,6 +243,8 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre
241243
make_unique<OpenCommissioningWindowCommand>(credsIssuerConfig),
242244
make_unique<CloseSessionCommand>(credsIssuerConfig),
243245
make_unique<GetCommissionerNodeIdCommand>(credsIssuerConfig),
246+
make_unique<GetCommissionerRootCertificateCommand>(credsIssuerConfig),
247+
make_unique<IssueNOCChainCommand>(credsIssuerConfig),
244248
};
245249

246250
commands.Register(clusterName, clusterCommands);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
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+
#pragma once
20+
21+
#include "../common/CHIPCommand.h"
22+
23+
#include "ToTLVCert.h"
24+
25+
class GetCommissionerRootCertificateCommand : public CHIPCommand
26+
{
27+
public:
28+
GetCommissionerRootCertificateCommand(CredentialIssuerCommands * credIssuerCommands) :
29+
CHIPCommand("get-commissioner-root-certificate", credIssuerCommands,
30+
"Returns a base64-encoded RCAC prefixed with: 'base64:'")
31+
{}
32+
33+
/////////// CHIPCommand Interface /////////
34+
CHIP_ERROR RunCommand() override
35+
{
36+
chip::ByteSpan span;
37+
ReturnErrorOnFailure(GetIdentityRootCertificate(GetIdentity(), span));
38+
39+
std::string rcac;
40+
ReturnErrorOnFailure(ToTLVCert(span, rcac));
41+
ChipLogProgress(chipTool, "RCAC: %s", rcac.c_str());
42+
43+
ReturnErrorOnFailure(RemoteDataModelLogger::LogGetCommissionerRootCertificate(rcac.c_str()));
44+
45+
SetCommandExitStatus(CHIP_NO_ERROR);
46+
return CHIP_NO_ERROR;
47+
}
48+
49+
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }
50+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
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+
#pragma once
20+
21+
#include "../common/CHIPCommand.h"
22+
23+
#include "ToTLVCert.h"
24+
25+
class IssueNOCChainCommand : public CHIPCommand
26+
{
27+
public:
28+
IssueNOCChainCommand(CredentialIssuerCommands * credIssuerCommands) :
29+
CHIPCommand("issue-noc-chain", credIssuerCommands,
30+
"Returns a base64-encoded NOC, ICAC, RCAC, and IPK prefixed with: 'base64:'"),
31+
mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this)
32+
{
33+
AddArgument("elements", &mNOCSRElements, "NOCSRElements encoded in hexadecimal");
34+
AddArgument("node-id", 0, UINT64_MAX, &mNodeId, "The target node id");
35+
}
36+
37+
/////////// CHIPCommand Interface /////////
38+
CHIP_ERROR RunCommand() override
39+
{
40+
auto & commissioner = CurrentCommissioner();
41+
ReturnErrorOnFailure(commissioner.IssueNOCChain(mNOCSRElements, mNodeId, &mDeviceNOCChainCallback));
42+
return CHIP_NO_ERROR;
43+
}
44+
45+
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }
46+
47+
static void OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const chip::ByteSpan & noc,
48+
const chip::ByteSpan & icac, const chip::ByteSpan & rcac,
49+
chip::Optional<chip::IdentityProtectionKeySpan> ipk,
50+
chip::Optional<chip::NodeId> adminSubject)
51+
{
52+
auto command = static_cast<IssueNOCChainCommand *>(context);
53+
54+
auto err = status;
55+
VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err));
56+
57+
std::string nocStr;
58+
err = ToTLVCert(noc, nocStr);
59+
VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err));
60+
ChipLogProgress(chipTool, "NOC: %s", nocStr.c_str());
61+
62+
std::string icacStr;
63+
err = ToTLVCert(icac, icacStr);
64+
VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err));
65+
ChipLogProgress(chipTool, "ICAC: %s", icacStr.c_str());
66+
67+
std::string rcacStr;
68+
err = ToTLVCert(rcac, rcacStr);
69+
VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err));
70+
ChipLogProgress(chipTool, "RCAC: %s", rcacStr.c_str());
71+
72+
auto ipkValue = ipk.ValueOr(chip::Crypto::IdentityProtectionKeySpan());
73+
std::string ipkStr;
74+
err = ToBase64(ipkValue, ipkStr);
75+
VerifyOrReturn(CHIP_NO_ERROR == err, command->SetCommandExitStatus(err));
76+
ChipLogProgress(chipTool, "IPK: %s", ipkStr.c_str());
77+
78+
err = RemoteDataModelLogger::LogIssueNOCChain(nocStr.c_str(), icacStr.c_str(), rcacStr.c_str(), ipkStr.c_str());
79+
command->SetCommandExitStatus(err);
80+
}
81+
82+
private:
83+
chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> mDeviceNOCChainCallback;
84+
chip::ByteSpan mNOCSRElements;
85+
chip::NodeId mNodeId;
86+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
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+
#include "ToTLVCert.h"
20+
21+
#include <credentials/CHIPCert.h>
22+
#include <lib/support/Base64.h>
23+
24+
constexpr const char kBase64Header[] = "base64:";
25+
constexpr size_t kBase64HeaderLen = ArraySize(kBase64Header) - 1;
26+
27+
CHIP_ERROR ToBase64(const chip::ByteSpan & input, std::string & outputAsPrefixedBase64)
28+
{
29+
chip::Platform::ScopedMemoryBuffer<char> base64String;
30+
base64String.Alloc(kBase64HeaderLen + BASE64_ENCODED_LEN(input.size()) + 1);
31+
VerifyOrReturnError(base64String.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
32+
33+
auto encodedLen = chip::Base64Encode(input.data(), static_cast<uint16_t>(input.size()), base64String.Get() + kBase64HeaderLen);
34+
if (encodedLen)
35+
{
36+
memcpy(base64String.Get(), kBase64Header, kBase64HeaderLen);
37+
encodedLen = static_cast<uint16_t>(encodedLen + kBase64HeaderLen);
38+
}
39+
base64String.Get()[encodedLen] = '\0';
40+
outputAsPrefixedBase64 = std::string(base64String.Get(), encodedLen);
41+
42+
return CHIP_NO_ERROR;
43+
}
44+
45+
CHIP_ERROR ToTLVCert(const chip::ByteSpan & derEncodedCertificate, std::string & tlvCertAsPrefixedBase64)
46+
{
47+
uint8_t chipCertBuffer[chip::Credentials::kMaxCHIPCertLength];
48+
chip::MutableByteSpan chipCertBytes(chipCertBuffer);
49+
ReturnErrorOnFailure(chip::Credentials::ConvertX509CertToChipCert(derEncodedCertificate, chipCertBytes));
50+
ReturnErrorOnFailure(ToBase64(chipCertBytes, tlvCertAsPrefixedBase64));
51+
return CHIP_NO_ERROR;
52+
}

0 commit comments

Comments
 (0)