Skip to content

Commit 7e80407

Browse files
Separate out OCW with passcode and verifier, bring back stable API
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent b96c5cc commit 7e80407

8 files changed

+242
-71
lines changed

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,17 @@ 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, NullOptional,
39-
&mOnOpenCommissioningWindowCallback, ignored,
40-
/* readVIDPIDAttributes */ true);
37+
Controller::CommissioningWindowOpener::CommissioningWindowPasscodeParams params = {
38+
.common = { .deviceId = mNodeId,
39+
.timeout = System::Clock::Seconds16(mCommissioningWindowTimeout),
40+
.iteration = mIteration,
41+
.discriminator = mDiscriminator },
42+
.setupPIN = NullOptional,
43+
.salt = NullOptional,
44+
.readVIDPIDAttributes = true,
45+
.callback = &mOnOpenCommissioningWindowCallback,
46+
};
47+
return mWindowOpener->OpenCommissioningWindow(params, ignored);
4148
}
4249

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

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

+34-5
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,35 @@ 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, mSalt, mVerifier,
39-
&mOnOpenCommissioningWindowCallback, ignored,
40-
/* readVIDPIDAttributes */ true);
36+
Controller::CommissioningWindowOpener::CommissioningWindowCommonParams common = { .deviceId = mNodeId,
37+
.timeout = System::Clock::Seconds16(
38+
mCommissioningWindowTimeout),
39+
.iteration = mIteration,
40+
.discriminator = mDiscriminator };
41+
42+
if (mVerifier.HasValue())
43+
{
44+
VerifyOrReturnError(mSalt.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
45+
Controller::CommissioningWindowOpener::CommissioningWindowVerifierParams params = {
46+
.common = common,
47+
.verifier = mVerifier.Value(),
48+
.salt = mSalt.Value(),
49+
.callback = &mOnOpenCommissioningWindowVerifierCallback,
50+
};
51+
return mWindowOpener->OpenCommissioningWindow(params);
52+
}
53+
else
54+
{
55+
SetupPayload ignored;
56+
Controller::CommissioningWindowOpener::CommissioningWindowPasscodeParams params = {
57+
.common = common,
58+
.setupPIN = NullOptional,
59+
.salt = mSalt,
60+
.readVIDPIDAttributes = true,
61+
.callback = &mOnOpenCommissioningWindowCallback,
62+
};
63+
return mWindowOpener->OpenCommissioningWindow(params, ignored);
64+
}
4165
}
4266

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

85+
void OpenCommissioningWindowCommand::OnOpenCommissioningWindowVerifierResponse(void * context, NodeId remoteId, CHIP_ERROR err)
86+
{
87+
OnOpenBasicCommissioningWindowResponse(context, remoteId, err);
88+
}
89+
6190
void OpenCommissioningWindowCommand::OnOpenBasicCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err)
6291
{
6392
LogErrorOnFailure(err);

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

+3
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.");
@@ -79,8 +80,10 @@ class OpenCommissioningWindowCommand : public CHIPCommand
7980
chip::Platform::UniquePtr<chip::Controller::CommissioningWindowOpener> mWindowOpener;
8081

8182
static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload);
83+
static void OnOpenCommissioningWindowVerifierResponse(void * context, NodeId deviceId, CHIP_ERROR status);
8284
static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status);
8385

8486
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindow> mOnOpenCommissioningWindowCallback;
87+
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindowWithVerifier> mOnOpenCommissioningWindowVerifierCallback;
8588
chip::Callback::Callback<chip::Controller::OnOpenBasicCommissioningWindow> mOnOpenBasicCommissioningWindowCallback;
8689
};

src/controller/CommissioningWindowOpener.cpp

+88-50
Original file line numberDiff line numberDiff line change
@@ -43,83 +43,87 @@ CHIP_ERROR CommissioningWindowOpener::OpenBasicCommissioningWindow(NodeId device
4343

4444
// Basic commissioning does not use the setup payload.
4545

46-
mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode;
47-
mBasicCommissioningWindowCallback = callback;
48-
mCommissioningWindowCallback = nullptr;
49-
mNodeId = deviceId;
50-
mCommissioningWindowTimeout = timeout;
46+
mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode;
47+
mBasicCommissioningWindowCallback = callback;
48+
mCommissioningWindowCallback = nullptr;
49+
mCommissioningWindowVerifierCallback = nullptr;
50+
mNodeId = deviceId;
51+
mCommissioningWindowTimeout = timeout;
5152

5253
mNextStep = Step::kOpenCommissioningWindow;
5354
return mController->GetConnectedDevice(mNodeId, &mDeviceConnected, &mDeviceConnectionFailure);
5455
}
5556

5657
CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindow(NodeId deviceId, Seconds16 timeout, uint32_t iteration,
5758
uint16_t discriminator, Optional<uint32_t> setupPIN,
58-
Optional<ByteSpan> salt, Optional<ByteSpan> verifier,
59+
Optional<ByteSpan> salt,
5960
Callback::Callback<OnOpenCommissioningWindow> * callback,
6061
SetupPayload & payload, bool readVIDPIDAttributes)
6162
{
62-
VerifyOrReturnError(mNextStep == Step::kAcceptCommissioningStart, CHIP_ERROR_INCORRECT_STATE);
63+
CommissioningWindowPasscodeParams params = {
64+
.common = { .deviceId = deviceId, .timeout = timeout, .iteration = iteration, .discriminator = discriminator },
65+
.setupPIN = setupPIN,
66+
.salt = salt,
67+
.readVIDPIDAttributes = readVIDPIDAttributes,
68+
.callback = callback,
69+
};
70+
71+
return OpenCommissioningWindow(params, payload);
72+
}
6373

64-
VerifyOrReturnError(kSpake2p_Min_PBKDF_Iterations <= iteration && iteration <= kSpake2p_Max_PBKDF_Iterations,
74+
CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindow(const CommissioningWindowPasscodeParams & params,
75+
SetupPayload & payload)
76+
{
77+
VerifyOrReturnError(mNextStep == Step::kAcceptCommissioningStart, CHIP_ERROR_INCORRECT_STATE);
78+
VerifyOrReturnError(kSpake2p_Min_PBKDF_Iterations <= params.common.iteration &&
79+
params.common.iteration <= kSpake2p_Max_PBKDF_Iterations,
80+
CHIP_ERROR_INVALID_ARGUMENT);
81+
VerifyOrReturnError(!params.salt.HasValue() ||
82+
(params.salt.Value().size() >= kSpake2p_Min_PBKDF_Salt_Length &&
83+
params.salt.Value().size() <= kSpake2p_Max_PBKDF_Salt_Length),
6584
CHIP_ERROR_INVALID_ARGUMENT);
66-
VerifyOrReturnError(
67-
!salt.HasValue() ||
68-
(salt.Value().size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.Value().size() <= kSpake2p_Max_PBKDF_Salt_Length),
69-
CHIP_ERROR_INVALID_ARGUMENT);
7085

7186
mSetupPayload = SetupPayload();
7287

73-
if (setupPIN.HasValue())
88+
if (params.setupPIN.HasValue())
7489
{
75-
if (!SetupPayload::IsValidSetupPIN(setupPIN.Value()))
76-
{
77-
return CHIP_ERROR_INVALID_ARGUMENT;
78-
}
79-
90+
VerifyOrReturnError(SetupPayload::IsValidSetupPIN(params.setupPIN.Value()), CHIP_ERROR_INVALID_ARGUMENT);
8091
mCommissioningWindowOption = CommissioningWindowOption::kTokenWithProvidedPIN;
81-
mSetupPayload.setUpPINCode = setupPIN.Value();
92+
mSetupPayload.setUpPINCode = params.setupPIN.Value();
8293
}
8394
else
8495
{
8596
mCommissioningWindowOption = CommissioningWindowOption::kTokenWithRandomPIN;
8697
}
8798

88-
if (salt.HasValue())
89-
{
90-
memcpy(mPBKDFSaltBuffer, salt.Value().data(), salt.Value().size());
91-
mPBKDFSalt = ByteSpan(mPBKDFSaltBuffer, salt.Value().size());
92-
}
93-
else
94-
{
95-
ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFSaltBuffer, sizeof(mPBKDFSaltBuffer)));
96-
mPBKDFSalt = ByteSpan(mPBKDFSaltBuffer);
97-
}
98-
9999
mSetupPayload.version = 0;
100-
mSetupPayload.discriminator.SetLongValue(discriminator);
100+
mSetupPayload.discriminator.SetLongValue(params.common.discriminator);
101101
mSetupPayload.rendezvousInformation.SetValue(RendezvousInformationFlag::kOnNetwork);
102102

103-
mCommissioningWindowCallback = callback;
104-
mBasicCommissioningWindowCallback = nullptr;
105-
mNodeId = deviceId;
106-
mCommissioningWindowTimeout = timeout;
107-
mPBKDFIterations = iteration;
108-
109-
if (verifier.HasValue())
103+
if (params.salt.HasValue())
110104
{
111-
ReturnErrorOnFailure(mVerifier.Deserialize(verifier.Value()));
105+
memcpy(mPBKDFSaltBuffer, params.salt.Value().data(), params.salt.Value().size());
106+
mPBKDFSalt = ByteSpan(mPBKDFSaltBuffer, params.salt.Value().size());
112107
}
113108
else
114109
{
115-
bool randomSetupPIN = !setupPIN.HasValue();
116-
ReturnErrorOnFailure(
117-
PASESession::GeneratePASEVerifier(mVerifier, mPBKDFIterations, mPBKDFSalt, randomSetupPIN, mSetupPayload.setUpPINCode));
110+
ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFSaltBuffer, sizeof(mPBKDFSaltBuffer)));
111+
mPBKDFSalt = ByteSpan(mPBKDFSaltBuffer);
118112
}
119113

120-
payload = mSetupPayload;
114+
bool randomSetupPIN = !params.setupPIN.HasValue();
115+
ReturnErrorOnFailure(
116+
PASESession::GeneratePASEVerifier(mVerifier, mPBKDFIterations, mPBKDFSalt, randomSetupPIN, mSetupPayload.setUpPINCode));
117+
118+
payload = mSetupPayload;
119+
mCommissioningWindowCallback = params.callback;
120+
mBasicCommissioningWindowCallback = nullptr;
121+
mCommissioningWindowVerifierCallback = nullptr;
122+
mNodeId = params.common.deviceId;
123+
mCommissioningWindowTimeout = params.common.timeout;
124+
mPBKDFIterations = params.common.iteration;
121125

122-
if (readVIDPIDAttributes)
126+
if (params.readVIDPIDAttributes)
123127
{
124128
mNextStep = Step::kReadVID;
125129
}
@@ -131,6 +135,31 @@ CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindow(NodeId deviceId, S
131135
return mController->GetConnectedDevice(mNodeId, &mDeviceConnected, &mDeviceConnectionFailure);
132136
}
133137

138+
CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindow(const CommissioningWindowVerifierParams & params)
139+
{
140+
VerifyOrReturnError(mNextStep == Step::kAcceptCommissioningStart, CHIP_ERROR_INCORRECT_STATE);
141+
VerifyOrReturnError(kSpake2p_Min_PBKDF_Iterations <= params.common.iteration &&
142+
params.common.iteration <= kSpake2p_Max_PBKDF_Iterations,
143+
CHIP_ERROR_INVALID_ARGUMENT);
144+
VerifyOrReturnError(params.salt.size() >= kSpake2p_Min_PBKDF_Salt_Length &&
145+
params.salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
146+
CHIP_ERROR_INVALID_ARGUMENT);
147+
memcpy(mPBKDFSaltBuffer, params.salt.data(), params.salt.size());
148+
mPBKDFSalt = ByteSpan(mPBKDFSaltBuffer, params.salt.size());
149+
150+
ReturnErrorOnFailure(mVerifier.Deserialize(params.verifier));
151+
mCommissioningWindowVerifierCallback = params.callback;
152+
mBasicCommissioningWindowCallback = nullptr;
153+
mCommissioningWindowCallback = nullptr;
154+
mNodeId = params.common.deviceId;
155+
mCommissioningWindowTimeout = params.common.timeout;
156+
mPBKDFIterations = params.common.iteration;
157+
158+
mNextStep = Step::kOpenCommissioningWindow;
159+
160+
return mController->GetConnectedDevice(mNodeId, &mDeviceConnected, &mDeviceConnectionFailure);
161+
}
162+
134163
CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindowInternal(Messaging::ExchangeManager & exchangeMgr,
135164
const SessionHandle & sessionHandle)
136165
{
@@ -237,15 +266,19 @@ void CommissioningWindowOpener::OnOpenCommissioningWindowSuccess(void * context,
237266

238267
self->mCommissioningWindowCallback->mCall(self->mCommissioningWindowCallback->mContext, self->mNodeId, CHIP_NO_ERROR,
239268
self->mSetupPayload);
240-
// Don't touch `self` anymore; it might have been destroyed by the
241-
// callee.
269+
// Don't touch `self` anymore; it might have been destroyed by the callee.
270+
}
271+
else if (self->mCommissioningWindowVerifierCallback != nullptr)
272+
{
273+
self->mCommissioningWindowVerifierCallback->mCall(self->mCommissioningWindowVerifierCallback->mContext, self->mNodeId,
274+
CHIP_NO_ERROR);
275+
// Don't touch `self` anymore; it might have been destroyed by the callee.
242276
}
243277
else if (self->mBasicCommissioningWindowCallback != nullptr)
244278
{
245279
self->mBasicCommissioningWindowCallback->mCall(self->mBasicCommissioningWindowCallback->mContext, self->mNodeId,
246280
CHIP_NO_ERROR);
247-
// Don't touch `self` anymore; it might have been destroyed by the
248-
// callee.
281+
// Don't touch `self` anymore; it might have been destroyed by the callee.
249282
}
250283
}
251284

@@ -259,6 +292,11 @@ void CommissioningWindowOpener::OnOpenCommissioningWindowFailure(void * context,
259292
self->mCommissioningWindowCallback->mCall(self->mCommissioningWindowCallback->mContext, self->mNodeId, error,
260293
SetupPayload());
261294
}
295+
else if (self->mCommissioningWindowVerifierCallback != nullptr)
296+
{
297+
self->mCommissioningWindowVerifierCallback->mCall(self->mCommissioningWindowVerifierCallback->mContext, self->mNodeId,
298+
error);
299+
}
262300
else if (self->mBasicCommissioningWindowCallback != nullptr)
263301
{
264302
self->mBasicCommissioningWindowCallback->mCall(self->mBasicCommissioningWindowCallback->mContext, self->mNodeId, error);
@@ -361,8 +399,8 @@ CHIP_ERROR AutoCommissioningWindowOpener::OpenCommissioningWindow(DeviceControll
361399
}
362400

363401
CHIP_ERROR err = opener->CommissioningWindowOpener::OpenCommissioningWindow(
364-
deviceId, timeout, iteration, discriminator, setupPIN, salt, NullOptional, &opener->mOnOpenCommissioningWindowCallback,
365-
payload, readVIDPIDAttributes);
402+
deviceId, timeout, iteration, discriminator, setupPIN, salt, &opener->mOnOpenCommissioningWindowCallback, payload,
403+
readVIDPIDAttributes);
366404
if (err != CHIP_NO_ERROR)
367405
{
368406
delete opener;

0 commit comments

Comments
 (0)