Skip to content

Commit d32e8e2

Browse files
samadDotDevbzbarsky-appleandy31415
authored
Add OCW verifier, pass params between fabric bridge & admin (#34209)
* Add verifier arg to `CommissioningWindowOpener` * Update RPC, pass OCW params between fabric bridge and admin * Separate out OCW with passcode and verifier, bring back stable API Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Use `CHIP_ERROR_BUFFER_TOO_SMALL`, Avoid SuccessOrExit, args for example Co-authored-by: Andrei Litvin <andy314@gmail.com> * Use fluent builder pattern for OCW params, and some fixes Co-authored-by: Andrei Litvin <andy314@gmail.com> * Add arg tests for new methods in `CommissioningWindowOpener` * Move callback to params Co-authored-by: Andrei Litvin <andy314@gmail.com> * Enforce param values, Add mDiscriminator, Update docs Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Use `HasDiscriminator()`/`HasNodeId()`, return `ERROR_INVALID_ARGUMENT` --------- Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> Co-authored-by: Andrei Litvin <andy314@gmail.com>
1 parent e7380a1 commit d32e8e2

19 files changed

+679
-85
lines changed

examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ CHIP_ERROR OpenCommissioningWindowCommand::RunCommand()
3434
if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN)
3535
{
3636
SetupPayload ignored;
37-
return mWindowOpener->OpenCommissioningWindow(mNodeId, System::Clock::Seconds16(mCommissioningWindowTimeout), mIteration,
38-
mDiscriminator, NullOptional, NullOptional,
39-
&mOnOpenCommissioningWindowCallback, ignored,
40-
/* readVIDPIDAttributes */ true);
37+
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowPasscodeParams()
38+
.SetNodeId(mNodeId)
39+
.SetTimeout(mCommissioningWindowTimeout)
40+
.SetIteration(mIteration)
41+
.SetDiscriminator(mDiscriminator)
42+
.SetReadVIDPIDAttributes(true)
43+
.SetCallback(&mOnOpenCommissioningWindowCallback),
44+
ignored);
4145
}
4246

4347
ChipLogError(chipTool, "Unknown commissioning window option: %d", to_underlying(mCommissioningWindowOption));

examples/common/pigweed/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pw_proto_library("button_service") {
8282

8383
pw_proto_library("fabric_admin_service") {
8484
sources = [ "protos/fabric_admin_service.proto" ]
85+
inputs = [ "protos/fabric_admin_service.options" ]
8586
deps = [ "$dir_pw_protobuf:common_protos" ]
8687
strip_prefix = "protos"
8788
prefix = "fabric_admin_service"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
chip.rpc.DeviceCommissioningWindowInfo.verifier max_size:97 // kSpake2p_VerifierSerialized_Length
2+
chip.rpc.DeviceCommissioningWindowInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length

examples/common/pigweed/protos/fabric_admin_service.proto

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import 'pw_protobuf_protos/common.proto';
55
package chip.rpc;
66

77
// Define the message for a synchronized end device with necessary fields
8-
message DeviceInfo {
8+
message DeviceCommissioningWindowInfo {
99
uint64 node_id = 1;
10+
uint32 commissioning_timeout = 2;
11+
uint32 discriminator = 3;
12+
uint32 iterations = 4;
13+
bytes salt = 5;
14+
bytes verifier = 6;
1015
}
1116

1217
// Define the response message to convey the status of the operation
@@ -15,6 +20,5 @@ message OperationStatus {
1520
}
1621

1722
service FabricAdmin {
18-
rpc OpenCommissioningWindow(DeviceInfo) returns (OperationStatus){}
23+
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
1924
}
20-

examples/common/pigweed/rpc_services/FabricAdmin.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
3434
public:
3535
virtual ~FabricAdmin() = default;
3636

37-
virtual pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response)
37+
virtual pw::Status OpenCommissioningWindow(const chip_rpc_DeviceCommissioningWindowInfo & request,
38+
chip_rpc_OperationStatus & response)
3839
{
3940
return pw::Status::Unimplemented();
4041
}

examples/fabric-admin/commands/pairing/OpenCommissioningWindowCommand.cpp

+30-5
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,31 @@ CHIP_ERROR OpenCommissioningWindowCommand::RunCommand()
3333

3434
if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN)
3535
{
36-
SetupPayload ignored;
37-
return mWindowOpener->OpenCommissioningWindow(mNodeId, System::Clock::Seconds16(mCommissioningWindowTimeout), mIteration,
38-
mDiscriminator, NullOptional, NullOptional,
39-
&mOnOpenCommissioningWindowCallback, ignored,
40-
/* readVIDPIDAttributes */ true);
36+
if (mVerifier.HasValue())
37+
{
38+
VerifyOrReturnError(mSalt.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
39+
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowVerifierParams()
40+
.SetNodeId(mNodeId)
41+
.SetTimeout(mCommissioningWindowTimeout)
42+
.SetIteration(mIteration)
43+
.SetDiscriminator(mDiscriminator)
44+
.SetVerifier(mVerifier.Value())
45+
.SetSalt(mSalt.Value())
46+
.SetCallback(&mOnOpenCommissioningWindowVerifierCallback));
47+
}
48+
else
49+
{
50+
SetupPayload ignored;
51+
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowPasscodeParams()
52+
.SetNodeId(mNodeId)
53+
.SetTimeout(mCommissioningWindowTimeout)
54+
.SetIteration(mIteration)
55+
.SetDiscriminator(mDiscriminator)
56+
.SetSalt(mSalt)
57+
.SetReadVIDPIDAttributes(true)
58+
.SetCallback(&mOnOpenCommissioningWindowCallback),
59+
ignored);
60+
}
4161
}
4262

4363
ChipLogError(NotSpecified, "Unknown commissioning window option: %d", to_underlying(mCommissioningWindowOption));
@@ -58,6 +78,11 @@ void OpenCommissioningWindowCommand::OnOpenCommissioningWindowResponse(void * co
5878
OnOpenBasicCommissioningWindowResponse(context, remoteId, err);
5979
}
6080

81+
void OpenCommissioningWindowCommand::OnOpenCommissioningWindowVerifierResponse(void * context, NodeId remoteId, CHIP_ERROR err)
82+
{
83+
OnOpenBasicCommissioningWindowResponse(context, remoteId, err);
84+
}
85+
6186
void OpenCommissioningWindowCommand::OnOpenBasicCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err)
6287
{
6388
LogErrorOnFailure(err);

examples/fabric-admin/commands/pairing/OpenCommissioningWindowCommand.h

+11
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class OpenCommissioningWindowCommand : public CHIPCommand
3535
OpenCommissioningWindowCommand(CredentialIssuerCommands * credIssuerCommands) :
3636
CHIPCommand("open-commissioning-window", credIssuerCommands),
3737
mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this),
38+
mOnOpenCommissioningWindowVerifierCallback(OnOpenCommissioningWindowVerifierResponse, this),
3839
mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this)
3940
{
4041
AddArgument("node-id", 0, UINT64_MAX, &mNodeId, "Node to send command to.");
@@ -47,6 +48,12 @@ class OpenCommissioningWindowCommand : public CHIPCommand
4748
&mIteration, "Number of PBKDF iterations to use to derive the verifier. Ignored if 'option' is 0.");
4849
AddArgument("discriminator", 0, 4096, &mDiscriminator, "Discriminator to use for advertising. Ignored if 'option' is 0.");
4950
AddArgument("timeout", 0, UINT16_MAX, &mTimeout, "Time, in seconds, before this command is considered to have timed out.");
51+
AddArgument("salt", &mSalt,
52+
"Salt payload encoded in hexadecimal. Random salt will be generated if absent. "
53+
"This needs to be present if verifier is provided, corresponding to salt used for generating verifier");
54+
AddArgument("verifier", &mVerifier,
55+
"PAKE Passcode verifier encoded in hexadecimal format. Will be generated from random setup pin and other "
56+
"params if absent");
5057
}
5158

5259
void RegisterDelegate(CommissioningWindowDelegate * delegate) { mDelegate = delegate; }
@@ -69,12 +76,16 @@ class OpenCommissioningWindowCommand : public CHIPCommand
6976
uint16_t mDiscriminator;
7077

7178
chip::Optional<uint16_t> mTimeout;
79+
chip::Optional<chip::ByteSpan> mSalt;
80+
chip::Optional<chip::ByteSpan> mVerifier;
7281

7382
chip::Platform::UniquePtr<chip::Controller::CommissioningWindowOpener> mWindowOpener;
7483

7584
static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload);
85+
static void OnOpenCommissioningWindowVerifierResponse(void * context, NodeId deviceId, CHIP_ERROR status);
7686
static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status);
7787

7888
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindow> mOnOpenCommissioningWindowCallback;
89+
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindowWithVerifier> mOnOpenCommissioningWindowVerifierCallback;
7990
chip::Callback::Callback<chip::Controller::OnOpenBasicCommissioningWindow> mOnOpenBasicCommissioningWindowCallback;
8091
};

examples/fabric-admin/rpc/RpcServer.cpp

+18-5
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,27 @@ namespace {
3737
class FabricAdmin final : public rpc::FabricAdmin
3838
{
3939
public:
40-
pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override
40+
pw::Status OpenCommissioningWindow(const chip_rpc_DeviceCommissioningWindowInfo & request,
41+
chip_rpc_OperationStatus & response) override
4142
{
42-
NodeId nodeId = request.node_id;
43+
NodeId nodeId = request.node_id;
44+
uint32_t commissioningTimeout = request.commissioning_timeout;
45+
uint32_t iterations = request.iterations;
46+
uint32_t discriminator = request.discriminator;
47+
48+
char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
49+
Encoding::BytesToHex(request.salt.bytes, request.salt.size, saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);
50+
51+
char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1];
52+
Encoding::BytesToHex(request.verifier.bytes, request.verifier.size, verifierHex, sizeof(verifierHex),
53+
Encoding::HexFlags::kNullTerminate);
54+
4355
ChipLogProgress(NotSpecified, "Received OpenCommissioningWindow request: 0x%lx", nodeId);
4456

45-
char command[64];
46-
snprintf(command, sizeof(command), "pairing open-commissioning-window %ld %d %d %d %d %d", nodeId, kRootEndpointId,
47-
kEnhancedCommissioningMethod, kWindowTimeout, kIteration, kDiscriminator);
57+
char command[512];
58+
snprintf(command, sizeof(command), "pairing open-commissioning-window %ld %d %d %d %d %d --salt hex:%s --verifier hex:%s",
59+
nodeId, kRootEndpointId, kEnhancedCommissioningMethod, commissioningTimeout, iterations, discriminator, saltHex,
60+
verifierHex);
4861

4962
PushCommand(command);
5063

examples/fabric-bridge-app/linux/RpcClient.cpp

+34-5
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,9 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
9595
return rpc::client::StartPacketProcessing();
9696
}
9797

98-
CHIP_ERROR OpenCommissioningWindow(NodeId nodeId)
98+
CHIP_ERROR OpenCommissioningWindow(chip_rpc_DeviceCommissioningWindowInfo device)
9999
{
100-
ChipLogProgress(NotSpecified, "OpenCommissioningWindow with Node Id 0x:" ChipLogFormatX64, ChipLogValueX64(nodeId));
101-
102-
chip_rpc_DeviceInfo device;
103-
device.node_id = nodeId;
100+
ChipLogProgress(NotSpecified, "OpenCommissioningWindow with Node Id 0x" ChipLogFormatX64, ChipLogValueX64(device.node_id));
104101

105102
// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
106103
// function and the call will complete.
@@ -114,3 +111,35 @@ CHIP_ERROR OpenCommissioningWindow(NodeId nodeId)
114111

115112
return WaitForResponse(call);
116113
}
114+
115+
CHIP_ERROR
116+
OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams params)
117+
{
118+
chip_rpc_DeviceCommissioningWindowInfo device;
119+
device.node_id = params.GetNodeId();
120+
device.commissioning_timeout = params.GetTimeout().count();
121+
device.discriminator = params.GetDiscriminator();
122+
device.iterations = params.GetIteration();
123+
124+
return OpenCommissioningWindow(device);
125+
}
126+
127+
CHIP_ERROR
128+
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params)
129+
{
130+
chip_rpc_DeviceCommissioningWindowInfo device;
131+
device.node_id = params.GetNodeId();
132+
device.commissioning_timeout = params.GetTimeout().count();
133+
device.discriminator = params.GetDiscriminator();
134+
device.iterations = params.GetIteration();
135+
136+
VerifyOrReturnError(params.GetSalt().size() <= sizeof(device.salt.bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
137+
memcpy(device.salt.bytes, params.GetSalt().data(), params.GetSalt().size());
138+
device.salt.size = static_cast<size_t>(params.GetSalt().size());
139+
140+
VerifyOrReturnError(params.GetVerifier().size() <= sizeof(device.verifier.bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
141+
memcpy(device.verifier.bytes, params.GetVerifier().data(), params.GetVerifier().size());
142+
device.verifier.size = static_cast<size_t>(params.GetVerifier().size());
143+
144+
return OpenCommissioningWindow(device);
145+
}

examples/fabric-bridge-app/linux/include/RpcClient.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#pragma once
2020

21+
#include <controller/CommissioningWindowParams.h>
2122
#include <platform/CHIPDeviceLayer.h>
2223

2324
constexpr uint16_t kFabricAdminServerPort = 33001;
@@ -33,12 +34,25 @@ constexpr uint16_t kFabricAdminServerPort = 33001;
3334
CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
3435

3536
/**
36-
* Opens a commissioning window for a specified node.
37+
* Opens a commissioning window for a specified node using setup PIN (passcode).
3738
*
38-
* @param nodeId The identifier of the node for which the commissioning window should be opened.
39+
* @param params Params for opening the commissioning window using passcode.
3940
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
4041
* - CHIP_NO_ERROR: The RPC command was successfully processed.
4142
* - CHIP_ERROR_BUSY: Another commissioning window is currently in progress.
4243
* - CHIP_ERROR_INTERNAL: An internal error occurred.
4344
*/
44-
CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId);
45+
CHIP_ERROR
46+
OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams params);
47+
48+
/**
49+
* Opens a commissioning window for a specified node using pre-computed PAKE passcode verifier.
50+
*
51+
* @param params Params for opening the commissioning window using verifier.
52+
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
53+
* - CHIP_NO_ERROR: The RPC command was successfully sent.
54+
* - CHIP_ERROR_BUSY: Another commissioning window is currently in progress.
55+
* - CHIP_ERROR_INTERNAL: An internal error occurred.
56+
*/
57+
CHIP_ERROR
58+
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params);

examples/fabric-bridge-app/linux/main.cpp

+24-6
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ void BridgePollingThread()
6969
#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
7070
else if (ch == 'o')
7171
{
72-
CHIP_ERROR err = OpenCommissioningWindow(0x1234);
72+
CHIP_ERROR err = OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams()
73+
.SetNodeId(0x1234)
74+
.SetTimeout(300)
75+
.SetDiscriminator(3840)
76+
.SetIteration(1000));
7377
if (err != CHIP_NO_ERROR)
7478
{
7579
ChipLogError(NotSpecified, "Failed to call OpenCommissioningWindow RPC: %" CHIP_ERROR_FORMAT, err.Format());
@@ -115,7 +119,7 @@ void AdministratorCommissioningCommandHandler::InvokeCommand(HandlerContext & ha
115119
using Protocols::InteractionModel::Status;
116120

117121
EndpointId endpointId = handlerContext.mRequestPath.mEndpointId;
118-
ChipLogProgress(NotSpecified, "Received command to open commissioning window on Endpoind: %d", endpointId);
122+
ChipLogProgress(NotSpecified, "Received command to open commissioning window on Endpoint: %d", endpointId);
119123

120124
if (handlerContext.mRequestPath.mCommandId != Commands::OpenCommissioningWindow::Id || endpointId == kRootEndpointId)
121125
{
@@ -124,23 +128,37 @@ void AdministratorCommissioningCommandHandler::InvokeCommand(HandlerContext & ha
124128
}
125129

126130
handlerContext.SetCommandHandled();
127-
Status status = Status::Success;
131+
132+
Commands::OpenCommissioningWindow::DecodableType commandData;
133+
if (DataModel::Decode(handlerContext.mPayload, commandData) != CHIP_NO_ERROR)
134+
{
135+
handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::InvalidCommand);
136+
return;
137+
}
138+
139+
Status status = Status::Failure;
128140

129141
#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
130142
Device * device = DeviceMgr().GetDevice(endpointId);
131143

132144
// TODO: issues:#33784, need to make OpenCommissioningWindow synchronous
133-
if (device != nullptr && OpenCommissioningWindow(device->GetNodeId()) == CHIP_NO_ERROR)
145+
if (device != nullptr &&
146+
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams()
147+
.SetNodeId(device->GetNodeId())
148+
.SetTimeout(commandData.commissioningTimeout)
149+
.SetDiscriminator(commandData.discriminator)
150+
.SetIteration(commandData.iterations)
151+
.SetSalt(commandData.salt)
152+
.SetVerifier(commandData.PAKEPasscodeVerifier)) == CHIP_NO_ERROR)
134153
{
135154
ChipLogProgress(NotSpecified, "Commissioning window is now open");
155+
status = Status::Success;
136156
}
137157
else
138158
{
139-
status = Status::Failure;
140159
ChipLogProgress(NotSpecified, "Commissioning window is failed to open");
141160
}
142161
#else
143-
status = Status::Failure;
144162
ChipLogProgress(NotSpecified, "Commissioning window failed to open: PW_RPC_FABRIC_BRIDGE_SERVICE not defined");
145163
#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
146164

src/controller/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ static_library("controller") {
7474
"CommandSenderAllocator.h",
7575
"CommissioneeDeviceProxy.h",
7676
"CommissioningDelegate.h",
77+
"CommissioningWindowParams.h",
7778
"DeviceDiscoveryDelegate.h",
7879
"DevicePairingDelegate.h",
7980
"InvokeInteraction.h",

src/controller/CHIPDeviceController.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,10 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController
243243
* An error return from this function means that neither callback has been
244244
* called yet, and neither callback will be called in the future.
245245
*/
246-
CHIP_ERROR GetConnectedDevice(NodeId peerNodeId, Callback::Callback<OnDeviceConnected> * onConnection,
247-
chip::Callback::Callback<OnDeviceConnectionFailure> * onFailure,
248-
TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload)
246+
virtual CHIP_ERROR
247+
GetConnectedDevice(NodeId peerNodeId, Callback::Callback<OnDeviceConnected> * onConnection,
248+
Callback::Callback<OnDeviceConnectionFailure> * onFailure,
249+
TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload)
249250
{
250251
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
251252
mSystemState->CASESessionMgr()->FindOrEstablishSession(ScopedNodeId(peerNodeId, GetFabricIndex()), onConnection, onFailure,

0 commit comments

Comments
 (0)