Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OCW verifier, pass params between fabric bridge & admin #34209

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ CHIP_ERROR OpenCommissioningWindowCommand::RunCommand()
if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN)
{
SetupPayload ignored;
return mWindowOpener->OpenCommissioningWindow(mNodeId, System::Clock::Seconds16(mCommissioningWindowTimeout), mIteration,
mDiscriminator, NullOptional, NullOptional,
&mOnOpenCommissioningWindowCallback, ignored,
/* readVIDPIDAttributes */ true);
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowPasscodeParams()
.SetNodeId(mNodeId)
.SetTimeout(mCommissioningWindowTimeout)
.SetIteration(mIteration)
.SetDiscriminator(mDiscriminator)
.SetReadVIDPIDAttributes(true),
&mOnOpenCommissioningWindowCallback, ignored);
}

ChipLogError(chipTool, "Unknown commissioning window option: %d", to_underlying(mCommissioningWindowOption));
Expand Down
1 change: 1 addition & 0 deletions examples/common/pigweed/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pw_proto_library("button_service") {

pw_proto_library("fabric_admin_service") {
sources = [ "protos/fabric_admin_service.proto" ]
inputs = [ "protos/fabric_admin_service.options" ]
deps = [ "$dir_pw_protobuf:common_protos" ]
strip_prefix = "protos"
prefix = "fabric_admin_service"
Expand Down
2 changes: 2 additions & 0 deletions examples/common/pigweed/protos/fabric_admin_service.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
chip.rpc.DeviceCommissioningWindowInfo.verifier max_size:97 // kSpake2p_VerifierSerialized_Length
chip.rpc.DeviceCommissioningWindowInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length
10 changes: 7 additions & 3 deletions examples/common/pigweed/protos/fabric_admin_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import 'pw_protobuf_protos/common.proto';
package chip.rpc;

// Define the message for a synchronized end device with necessary fields
message DeviceInfo {
message DeviceCommissioningWindowInfo {
uint64 node_id = 1;
uint32 commissioning_timeout = 2;
uint32 discriminator = 3;
uint32 iterations = 4;
bytes salt = 5;
bytes verifier = 6;
}

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

service FabricAdmin {
rpc OpenCommissioningWindow(DeviceInfo) returns (OperationStatus){}
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
}

3 changes: 2 additions & 1 deletion examples/common/pigweed/rpc_services/FabricAdmin.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
public:
virtual ~FabricAdmin() = default;

virtual pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response)
virtual pw::Status OpenCommissioningWindow(const chip_rpc_DeviceCommissioningWindowInfo & request,
chip_rpc_OperationStatus & response)
{
return pw::Status::Unimplemented();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,30 @@ CHIP_ERROR OpenCommissioningWindowCommand::RunCommand()

if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN)
{
SetupPayload ignored;
return mWindowOpener->OpenCommissioningWindow(mNodeId, System::Clock::Seconds16(mCommissioningWindowTimeout), mIteration,
mDiscriminator, NullOptional, NullOptional,
&mOnOpenCommissioningWindowCallback, ignored,
/* readVIDPIDAttributes */ true);
if (mVerifier.HasValue())
{
VerifyOrReturnError(mSalt.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowVerifierParams()
.SetNodeId(mNodeId)
.SetTimeout(mCommissioningWindowTimeout)
.SetIteration(mIteration)
.SetDiscriminator(mDiscriminator)
.SetVerifier(mVerifier.Value())
.SetSalt(mSalt.Value()),
&mOnOpenCommissioningWindowVerifierCallback);
}
else
{
SetupPayload ignored;
return mWindowOpener->OpenCommissioningWindow(Controller::CommissioningWindowPasscodeParams()
.SetNodeId(mNodeId)
.SetTimeout(mCommissioningWindowTimeout)
.SetIteration(mIteration)
.SetDiscriminator(mDiscriminator)
.SetSalt(mSalt)
.SetReadVIDPIDAttributes(true),
&mOnOpenCommissioningWindowCallback, ignored);
}
}

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

void OpenCommissioningWindowCommand::OnOpenCommissioningWindowVerifierResponse(void * context, NodeId remoteId, CHIP_ERROR err)
{
OnOpenBasicCommissioningWindowResponse(context, remoteId, err);
}

void OpenCommissioningWindowCommand::OnOpenBasicCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err)
{
LogErrorOnFailure(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class OpenCommissioningWindowCommand : public CHIPCommand
OpenCommissioningWindowCommand(CredentialIssuerCommands * credIssuerCommands) :
CHIPCommand("open-commissioning-window", credIssuerCommands),
mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this),
mOnOpenCommissioningWindowVerifierCallback(OnOpenCommissioningWindowVerifierResponse, this),
mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this)
{
AddArgument("node-id", 0, UINT64_MAX, &mNodeId, "Node to send command to.");
Expand All @@ -47,6 +48,10 @@ class OpenCommissioningWindowCommand : public CHIPCommand
&mIteration, "Number of PBKDF iterations to use to derive the verifier. Ignored if 'option' is 0.");
AddArgument("discriminator", 0, 4096, &mDiscriminator, "Discriminator to use for advertising. Ignored if 'option' is 0.");
AddArgument("timeout", 0, UINT16_MAX, &mTimeout, "Time, in seconds, before this command is considered to have timed out.");
AddArgument("salt", &mSalt, "Salt payload encoded in hexadecimal. Random salt will be generated if absent");
AddArgument("verifier", &mVerifier,
"PAKE Passcode verifier encoded in hexadecimal format. Will be generated from random setup pin and other "
"params if absent");
}

void RegisterDelegate(CommissioningWindowDelegate * delegate) { mDelegate = delegate; }
Expand All @@ -69,12 +74,16 @@ class OpenCommissioningWindowCommand : public CHIPCommand
uint16_t mDiscriminator;

chip::Optional<uint16_t> mTimeout;
chip::Optional<chip::ByteSpan> mSalt;
chip::Optional<chip::ByteSpan> mVerifier;

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

static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload);
static void OnOpenCommissioningWindowVerifierResponse(void * context, NodeId deviceId, CHIP_ERROR status);
static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status);

chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindow> mOnOpenCommissioningWindowCallback;
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindowWithVerifier> mOnOpenCommissioningWindowVerifierCallback;
chip::Callback::Callback<chip::Controller::OnOpenBasicCommissioningWindow> mOnOpenBasicCommissioningWindowCallback;
};
23 changes: 18 additions & 5 deletions examples/fabric-admin/rpc/RpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,27 @@ namespace {
class FabricAdmin final : public rpc::FabricAdmin
{
public:
pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override
pw::Status OpenCommissioningWindow(const chip_rpc_DeviceCommissioningWindowInfo & request,
chip_rpc_OperationStatus & response) override
{
NodeId nodeId = request.node_id;
NodeId nodeId = request.node_id;
uint32_t commissioningTimeout = request.commissioning_timeout;
uint32_t iterations = request.iterations;
uint32_t discriminator = request.discriminator;

char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
Encoding::BytesToHex(request.salt.bytes, request.salt.size, saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);

char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1];
Encoding::BytesToHex(request.verifier.bytes, request.verifier.size, verifierHex, sizeof(verifierHex),
Encoding::HexFlags::kNullTerminate);

ChipLogProgress(NotSpecified, "Received OpenCommissioningWindow request: 0x%lx", nodeId);

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

PushCommand(command);

Expand Down
39 changes: 34 additions & 5 deletions examples/fabric-bridge-app/linux/RpcClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,16 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
return rpc::client::StartPacketProcessing();
}

CHIP_ERROR OpenCommissioningWindow(NodeId nodeId)
CHIP_ERROR OpenCommissioningWindow(chip_rpc_DeviceCommissioningWindowInfo device)
{
ChipLogProgress(NotSpecified, "OpenCommissioningWindow with Node Id 0x:" ChipLogFormatX64, ChipLogValueX64(nodeId));
ChipLogProgress(NotSpecified, "OpenCommissioningWindow with Node Id 0x" ChipLogFormatX64, ChipLogValueX64(device.node_id));

if (openCommissioningWindowCall.active())
{
ChipLogError(NotSpecified, "OpenCommissioningWindow is in progress\n");
return CHIP_ERROR_BUSY;
}

chip_rpc_DeviceInfo device;
device.node_id = nodeId;

// The RPC will remain active as long as `openCommissioningWindowCall` is alive.
openCommissioningWindowCall = fabricAdminClient.OpenCommissioningWindow(device, OnOpenCommissioningWindowCompleted);

Expand All @@ -86,3 +83,35 @@ CHIP_ERROR OpenCommissioningWindow(NodeId nodeId)

return CHIP_NO_ERROR;
}

CHIP_ERROR
OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams params)
{
chip_rpc_DeviceCommissioningWindowInfo device;
device.node_id = params.GetNodeId();
device.commissioning_timeout = params.GetTimeout().count();
device.discriminator = params.GetDiscriminator();
device.iterations = params.GetIteration();

return OpenCommissioningWindow(device);
}

CHIP_ERROR
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params)
{
chip_rpc_DeviceCommissioningWindowInfo device;
device.node_id = params.GetNodeId();
device.commissioning_timeout = params.GetTimeout().count();
device.discriminator = params.GetDiscriminator();
device.iterations = params.GetIteration();

VerifyOrReturnError(params.GetSalt().size() <= sizeof(device.salt.bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(device.salt.bytes, params.GetSalt().data(), params.GetSalt().size());
device.salt.size = static_cast<size_t>(params.GetSalt().size());

VerifyOrReturnError(params.GetVerifier().size() <= sizeof(device.verifier.bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(device.verifier.bytes, params.GetVerifier().data(), params.GetVerifier().size());
device.verifier.size = static_cast<size_t>(params.GetVerifier().size());

return OpenCommissioningWindow(device);
}
20 changes: 17 additions & 3 deletions examples/fabric-bridge-app/linux/include/RpcClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#pragma once

#include <controller/CommissioningWindowParams.h>
#include <platform/CHIPDeviceLayer.h>

constexpr uint16_t kFabricAdminServerPort = 33001;
Expand All @@ -33,12 +34,25 @@ constexpr uint16_t kFabricAdminServerPort = 33001;
CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);

/**
* Opens a commissioning window for a specified node.
* Opens a commissioning window for a specified node using setup PIN (passcode).
*
* @param nodeId The identifier of the node for which the commissioning window should be opened.
* @param params Params for opening the commissioning window using passcode.
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
* - CHIP_NO_ERROR: The RPC command was successfully sent.
* - CHIP_ERROR_BUSY: Another commissioning window is currently in progress.
* - CHIP_ERROR_INTERNAL: An internal error occurred.
*/
CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId);
CHIP_ERROR
OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams params);

/**
* Opens a commissioning window for a specified node using pre-computed PAKE passcode verifier.
*
* @param params Params for opening the commissioning window using verifier.
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
* - CHIP_NO_ERROR: The RPC command was successfully sent.
* - CHIP_ERROR_BUSY: Another commissioning window is currently in progress.
* - CHIP_ERROR_INTERNAL: An internal error occurred.
*/
CHIP_ERROR
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params);
30 changes: 24 additions & 6 deletions examples/fabric-bridge-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ void BridgePollingThread()
#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
else if (ch == 'o')
{
CHIP_ERROR err = OpenCommissioningWindow(0x1234);
CHIP_ERROR err = OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams()
.SetNodeId(0x1234)
.SetTimeout(300)
.SetDiscriminator(3840)
.SetIteration(1000));
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to call OpenCommissioningWindow RPC: %" CHIP_ERROR_FORMAT, err.Format());
Expand Down Expand Up @@ -120,7 +124,7 @@ void AdministratorCommissioningCommandHandler::InvokeCommand(HandlerContext & ha
using Protocols::InteractionModel::Status;

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

if (handlerContext.mRequestPath.mCommandId != Commands::OpenCommissioningWindow::Id || endpointId == kRootEndpointId)
{
Expand All @@ -129,23 +133,37 @@ void AdministratorCommissioningCommandHandler::InvokeCommand(HandlerContext & ha
}

handlerContext.SetCommandHandled();
Status status = Status::Success;

Commands::OpenCommissioningWindow::DecodableType commandData;
if (DataModel::Decode(handlerContext.mPayload, commandData) != CHIP_NO_ERROR)
{
handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::InvalidCommand);
return;
}

Status status = Status::Failure;

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

// TODO: issues:#33784, need to make OpenCommissioningWindow synchronous
if (device != nullptr && OpenCommissioningWindow(device->GetNodeId()) == CHIP_NO_ERROR)
if (device != nullptr &&
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams()
.SetNodeId(device->GetNodeId())
.SetTimeout(commandData.commissioningTimeout)
.SetDiscriminator(commandData.discriminator)
.SetIteration(commandData.iterations)
.SetSalt(commandData.salt)
.SetVerifier(commandData.PAKEPasscodeVerifier)) == CHIP_NO_ERROR)
{
ChipLogProgress(NotSpecified, "Commissioning window is now open");
status = Status::Success;
}
else
{
status = Status::Failure;
ChipLogProgress(NotSpecified, "Commissioning window is failed to open");
}
#else
status = Status::Failure;
ChipLogProgress(NotSpecified, "Commissioning window failed to open: PW_RPC_FABRIC_BRIDGE_SERVICE not defined");
#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE

Expand Down
1 change: 1 addition & 0 deletions src/controller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ static_library("controller") {
"CommandSenderAllocator.h",
"CommissioneeDeviceProxy.h",
"CommissioningDelegate.h",
"CommissioningWindowParams.h",
"DeviceDiscoveryDelegate.h",
"DevicePairingDelegate.h",
"InvokeInteraction.h",
Expand Down
Loading
Loading