Skip to content

Commit 1498444

Browse files
cecilleturonrestyled-commits
authored andcommitted
Separate PASE and commissioning. (#12060)
* Separate PASE and commissioning. Current "PairDevice" commands will continue to work as previously, but separating out the commissioning part from the PASE connection so vendors can have an easier time implemeting their own commissioning flows. * Update src/controller/CHIPDeviceController.cpp Co-authored-by: Martin Turon <[email protected]> * Fix android. * Restyled by autopep8 * Add comments on appropriate use of functions. Co-authored-by: Martin Turon <[email protected]> Co-authored-by: Restyled.io <[email protected]>
1 parent 7c1468e commit 1498444

7 files changed

+273
-70
lines changed

src/controller/CHIPDeviceController.cpp

+85-36
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,20 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * se
761761

762762
CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params)
763763
{
764+
CommissioningParameters commissioningParams;
765+
return PairDevice(remoteDeviceId, params, commissioningParams);
766+
}
767+
768+
CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams,
769+
CommissioningParameters & commissioningParams)
770+
{
771+
ReturnErrorOnFailure(EstablishPASEConnection(remoteDeviceId, rendezvousParams));
772+
return Commission(remoteDeviceId, commissioningParams);
773+
}
774+
775+
CHIP_ERROR DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, RendezvousParameters & params)
776+
{
777+
764778
CHIP_ERROR err = CHIP_NO_ERROR;
765779
CommissioneeDeviceProxy * device = nullptr;
766780
Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
@@ -804,39 +818,13 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
804818

805819
mDeviceBeingCommissioned = device;
806820

807-
// If the CSRNonce is passed in, using that else using a random one..
808-
if (params.HasCSRNonce())
809-
{
810-
ReturnErrorOnFailure(device->SetCSRNonce(params.GetCSRNonce().Value()));
811-
}
812-
else
813-
{
814-
uint8_t mCSRNonce[kOpCSRNonceLength];
815-
Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
816-
ReturnErrorOnFailure(device->SetCSRNonce(ByteSpan(mCSRNonce)));
817-
}
818-
819-
// If the AttestationNonce is passed in, using that else using a random one..
820-
if (params.HasAttestationNonce())
821-
{
822-
ReturnErrorOnFailure(device->SetAttestationNonce(params.GetAttestationNonce().Value()));
823-
}
824-
else
825-
{
826-
uint8_t mAttestationNonce[kAttestationNonceLength];
827-
Crypto::DRBG_get_bytes(mAttestationNonce, sizeof(mAttestationNonce));
828-
ReturnErrorOnFailure(device->SetAttestationNonce(ByteSpan(mAttestationNonce)));
829-
}
830-
831821
mIsIPRendezvous = (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle);
832822

833823
device->Init(GetControllerDeviceInitParams(), remoteDeviceId, peerAddress, fabric->GetFabricIndex());
834824

835825
err = device->GetPairing().MessageDispatch().Init(mSystemState->SessionMgr());
836826
SuccessOrExit(err);
837827

838-
mSystemState->SystemLayer()->StartTimer(chip::System::Clock::Milliseconds32(kSessionEstablishmentTimeout),
839-
OnSessionEstablishmentTimeoutCallback, this);
840828
if (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle)
841829
{
842830
device->SetAddress(params.GetPeerAddress().GetIPAddress());
@@ -874,9 +862,10 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
874862
err = device->GetPairing().Pair(params.GetPeerAddress(), params.GetSetupPINCode(), keyID, exchangeCtxt, this);
875863
SuccessOrExit(err);
876864

877-
// Immediately persist the updted mNextKeyID value
865+
// Immediately persist the updated mNextKeyID value
878866
// TODO maybe remove FreeRendezvousSession() since mNextKeyID is always persisted immediately
879867
PersistNextKeyId();
868+
mCommissioningStage = kSecurePairing;
880869

881870
exit:
882871
if (err != CHIP_NO_ERROR)
@@ -897,6 +886,58 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
897886
return err;
898887
}
899888

889+
CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId, CommissioningParameters & params)
890+
{
891+
// TODO(cecille): Can we get rid of mDeviceBeingCommissioned and use the remote id instead? Would require storing the
892+
// commissioning stage in the device.
893+
CommissioneeDeviceProxy * device = mDeviceBeingCommissioned;
894+
if (device->GetDeviceId() != remoteDeviceId || (!device->IsSecureConnected() && !device->IsSessionSetupInProgress()))
895+
{
896+
ChipLogError(Controller, "Invalid device for commissioning" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
897+
return CHIP_ERROR_INCORRECT_STATE;
898+
}
899+
if (mCommissioningStage != CommissioningStage::kSecurePairing)
900+
{
901+
ChipLogError(Controller, "Commissioning already in progress - not restarting");
902+
return CHIP_ERROR_INCORRECT_STATE;
903+
}
904+
// If the CSRNonce is passed in, using that else using a random one..
905+
if (params.HasCSRNonce())
906+
{
907+
ReturnErrorOnFailure(device->SetCSRNonce(params.GetCSRNonce().Value()));
908+
}
909+
else
910+
{
911+
uint8_t mCSRNonce[kOpCSRNonceLength];
912+
Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
913+
ReturnErrorOnFailure(device->SetCSRNonce(ByteSpan(mCSRNonce)));
914+
}
915+
916+
// If the AttestationNonce is passed in, using that else using a random one..
917+
if (params.HasAttestationNonce())
918+
{
919+
ReturnErrorOnFailure(device->SetAttestationNonce(params.GetAttestationNonce().Value()));
920+
}
921+
else
922+
{
923+
uint8_t mAttestationNonce[kAttestationNonceLength];
924+
Crypto::DRBG_get_bytes(mAttestationNonce, sizeof(mAttestationNonce));
925+
ReturnErrorOnFailure(device->SetAttestationNonce(ByteSpan(mAttestationNonce)));
926+
}
927+
928+
mSystemState->SystemLayer()->StartTimer(chip::System::Clock::Milliseconds32(kSessionEstablishmentTimeout),
929+
OnSessionEstablishmentTimeoutCallback, this);
930+
if (device->IsSecureConnected())
931+
{
932+
AdvanceCommissioningStage(CHIP_NO_ERROR);
933+
}
934+
else
935+
{
936+
mRunCommissioningAfterConnection = true;
937+
}
938+
return CHIP_NO_ERROR;
939+
}
940+
900941
CHIP_ERROR DeviceCommissioner::StopPairing(NodeId remoteDeviceId)
901942
{
902943
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
@@ -981,21 +1022,29 @@ void DeviceCommissioner::OnSessionEstablished()
9811022

9821023
// TODO: Add code to receive OpCSR from the device, and process the signing request
9831024
// For IP rendezvous, this is sent as part of the state machine.
984-
bool usingLegacyFlowWithImmediateStart = !mIsIPRendezvous;
985-
986-
if (usingLegacyFlowWithImmediateStart)
1025+
if (mRunCommissioningAfterConnection)
9871026
{
988-
err = SendCertificateChainRequestCommand(mDeviceBeingCommissioned, CertificateType::kPAI);
989-
if (err != CHIP_NO_ERROR)
1027+
mRunCommissioningAfterConnection = false;
1028+
bool usingLegacyFlowWithImmediateStart = !mIsIPRendezvous;
1029+
if (usingLegacyFlowWithImmediateStart)
9901030
{
991-
ChipLogError(Ble, "Failed in sending 'Certificate Chain request' command to the device: err %s", ErrorStr(err));
992-
OnSessionEstablishmentError(err);
993-
return;
1031+
err = SendCertificateChainRequestCommand(mDeviceBeingCommissioned, CertificateType::kPAI);
1032+
if (err != CHIP_NO_ERROR)
1033+
{
1034+
ChipLogError(Ble, "Failed in sending 'Certificate Chain request' command to the device: err %s", ErrorStr(err));
1035+
OnSessionEstablishmentError(err);
1036+
return;
1037+
}
1038+
}
1039+
else
1040+
{
1041+
AdvanceCommissioningStage(CHIP_NO_ERROR);
9941042
}
9951043
}
9961044
else
9971045
{
998-
AdvanceCommissioningStage(CHIP_NO_ERROR);
1046+
ChipLogProgress(Controller, "OnPairingComplete");
1047+
mPairingDelegate->OnPairingComplete(CHIP_NO_ERROR);
9991048
}
10001049
}
10011050

src/controller/CHIPDeviceController.h

+41-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <lib/support/Pool.h>
4949
#include <lib/support/SerializableIntegerSet.h>
5050
#include <lib/support/Span.h>
51+
#include <lib/support/ThreadOperationalDataset.h>
5152
#include <messaging/ExchangeMgr.h>
5253
#include <protocols/secure_channel/MessageCounterManager.h>
5354
#include <protocols/secure_channel/RendezvousParameters.h>
@@ -490,9 +491,46 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
490491
* in the Init() call.
491492
*
492493
* @param[in] remoteDeviceId The remote device Id.
493-
* @param[in] params The Rendezvous connection parameters
494+
* @param[in] rendezvousParams The Rendezvous connection parameters
495+
* @param[in] commssioningParams The commissioning parameters (uses defualt if not supplied)
494496
*/
495-
CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & params);
497+
CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams);
498+
CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams,
499+
CommissioningParameters & commissioningParams);
500+
501+
/**
502+
* @brief
503+
* Start establishing a PASE connection with a node for the purposes of commissioning.
504+
* Commissioners that wish to use the auto-commissioning functions should use the
505+
* supplied "PairDevice" functions above to automatically establish a connection then
506+
* perform commissioning. This function is intended to be use by commissioners that
507+
* are not using the supplied auto-commissioner.
508+
*
509+
* This function is non-blocking. PASE is established once the DevicePairingDelegate
510+
* receives the OnPairingComplete call.
511+
*
512+
* PASE connections can only be established with nodes that have their commissioning
513+
* window open. The PASE connection will fail if this window is not open and the
514+
* OnPairingComplete will be called with an error.
515+
*
516+
* @param[in] remoteDeviceId The remote device Id.
517+
* @param[in] rendezvousParams The Rendezvous connection parameters
518+
*/
519+
CHIP_ERROR EstablishPASEConnection(NodeId remoteDeviceId, RendezvousParameters & params);
520+
521+
/**
522+
* @brief
523+
* Start the auto-commissioning process on a node after establishing a PASE connection.
524+
* This function is intended to be used in conjunction with the EstablishPASEConnection
525+
* function. It can be called either before or after the DevicePairingDelegate receives
526+
* the OnPairingComplete call. Commissioners that want to perform simple auto-commissioning
527+
* should use the supplied "PairDevice" functions above, which will establish the PASE
528+
* connection and commission automatically.
529+
*
530+
* @param[in] remoteDeviceId The remote device Id.
531+
* @param[in] params The commissioning parameters
532+
*/
533+
CHIP_ERROR Commission(NodeId remoteDeviceId, CommissioningParameters & params);
496534

497535
CHIP_ERROR GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** device);
498536

@@ -628,6 +666,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
628666
bool mPairedDevicesUpdated;
629667

630668
CommissioningStage mCommissioningStage = CommissioningStage::kSecurePairing;
669+
bool mRunCommissioningAfterConnection = false;
631670

632671
BitMapObjectPool<CommissioneeDeviceProxy, kNumMaxActiveDevices> mCommissioneeDevicePool;
633672

src/controller/java/CHIPDeviceController-JNI.cpp

+14-12
Original file line numberDiff line numberDiff line change
@@ -185,18 +185,19 @@ JNI_METHOD(void, pairDevice)
185185

186186
ChipLogProgress(Controller, "pairDevice() called with device ID, connection object, and pincode");
187187

188-
RendezvousParameters params = RendezvousParameters()
189-
.SetSetupPINCode(pinCode)
188+
RendezvousParameters rendezvousParams = RendezvousParameters()
189+
.SetSetupPINCode(pinCode)
190190
#if CONFIG_NETWORK_LAYER_BLE
191-
.SetConnectionObject(reinterpret_cast<BLE_CONNECTION_OBJECT>(connObj))
191+
.SetConnectionObject(reinterpret_cast<BLE_CONNECTION_OBJECT>(connObj))
192192
#endif
193-
.SetPeerAddress(Transport::PeerAddress::BLE());
193+
.SetPeerAddress(Transport::PeerAddress::BLE());
194+
CommissioningParameters commissioningParams = CommissioningParameters();
194195
if (csrNonce != nullptr)
195196
{
196197
JniByteArray jniCsrNonce(env, csrNonce);
197-
params.SetCSRNonce(jniCsrNonce.byteSpan());
198+
commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan());
198199
}
199-
err = wrapper->Controller()->PairDevice(deviceId, params);
200+
err = wrapper->Controller()->PairDevice(deviceId, rendezvousParams, commissioningParams);
200201

201202
if (err != CHIP_NO_ERROR)
202203
{
@@ -221,16 +222,17 @@ JNI_METHOD(void, pairDeviceWithAddress)
221222
ChipLogError(Controller, "Failed to parse IP address."),
222223
JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT));
223224

224-
RendezvousParameters params = RendezvousParameters()
225-
.SetDiscriminator(discriminator)
226-
.SetSetupPINCode(pinCode)
227-
.SetPeerAddress(Transport::PeerAddress::UDP(addr, port));
225+
RendezvousParameters rendezvousParams = RendezvousParameters()
226+
.SetDiscriminator(discriminator)
227+
.SetSetupPINCode(pinCode)
228+
.SetPeerAddress(Transport::PeerAddress::UDP(addr, port));
229+
CommissioningParameters commissioningParams = CommissioningParameters();
228230
if (csrNonce != nullptr)
229231
{
230232
JniByteArray jniCsrNonce(env, csrNonce);
231-
params.SetCSRNonce(jniCsrNonce.byteSpan());
233+
commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan());
232234
}
233-
err = wrapper->Controller()->PairDevice(deviceId, params);
235+
err = wrapper->Controller()->PairDevice(deviceId, rendezvousParams, commissioningParams);
234236

235237
if (err != CHIP_NO_ERROR)
236238
{

src/controller/python/ChipDeviceController-ScriptBinding.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ ChipError::StorageType pychip_DeviceController_ConnectBLE(chip::Controller::Devi
112112
ChipError::StorageType pychip_DeviceController_ConnectIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr,
113113
uint32_t setupPINCode, chip::NodeId nodeid);
114114
ChipError::StorageType pychip_DeviceController_CloseSession(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid);
115+
ChipError::StorageType pychip_DeviceController_EstablishPASESessionIP(chip::Controller::DeviceCommissioner * devCtrl,
116+
const char * peerAddrStr, uint32_t setupPINCode,
117+
chip::NodeId nodeid);
118+
ChipError::StorageType pychip_DeviceController_Commission(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid);
115119

116120
ChipError::StorageType
117121
pychip_DeviceController_DiscoverCommissionableNodesLongDiscriminator(chip::Controller::DeviceCommissioner * devCtrl,
@@ -346,6 +350,23 @@ ChipError::StorageType pychip_DeviceController_CloseSession(chip::Controller::De
346350
{
347351
return pychip_GetConnectedDeviceByNodeId(devCtrl, nodeid, CloseSessionCallback);
348352
}
353+
ChipError::StorageType pychip_DeviceController_EstablishPASESessionIP(chip::Controller::DeviceCommissioner * devCtrl,
354+
const char * peerAddrStr, uint32_t setupPINCode,
355+
chip::NodeId nodeid)
356+
{
357+
chip::Inet::IPAddress peerAddr;
358+
chip::Transport::PeerAddress addr;
359+
RendezvousParameters params = chip::RendezvousParameters().SetSetupPINCode(setupPINCode);
360+
VerifyOrReturnError(chip::Inet::IPAddress::FromString(peerAddrStr, peerAddr), CHIP_ERROR_INVALID_ARGUMENT.AsInteger());
361+
addr.SetTransportType(chip::Transport::Type::kUdp).SetIPAddress(peerAddr);
362+
params.SetPeerAddress(addr).SetDiscriminator(0);
363+
return devCtrl->EstablishPASEConnection(nodeid, params).AsInteger();
364+
}
365+
ChipError::StorageType pychip_DeviceController_Commission(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid)
366+
{
367+
CommissioningParameters params;
368+
return devCtrl->Commission(nodeid, params).AsInteger();
369+
}
349370

350371
ChipError::StorageType pychip_DeviceController_DiscoverAllCommissionableNodes(chip::Controller::DeviceCommissioner * devCtrl)
351372
{

src/controller/python/chip-device-ctrl.py

+54
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ def __init__(self, rendezvousAddr=None, controllerNodeId=0, bluetoothAdapter=Non
200200
"close-ble",
201201
"close-session",
202202
"resolve",
203+
"paseonly",
204+
"commission",
203205
"zcl",
204206
"zclread",
205207
"zclsubscribe",
@@ -491,6 +493,58 @@ def ConnectFromSetupPayload(self, setupPayload, nodeid):
491493
print(f"Unable to connect: {ex}")
492494
return -1
493495

496+
def do_paseonly(self, line):
497+
"""
498+
paseonly -ip <ip address> <setup pin code> [<nodeid>]
499+
500+
TODO: Add more methods to connect to device (like cert for auth, and IP
501+
for connection)
502+
"""
503+
504+
try:
505+
args = shlex.split(line)
506+
if len(args) <= 1:
507+
print("Usage:")
508+
self.do_help("paseonly")
509+
return
510+
511+
nodeid = random.randint(1, 1000000) # Just a random number
512+
if len(args) == 4:
513+
nodeid = int(args[3])
514+
print("Device is assigned with nodeid = {}".format(nodeid))
515+
516+
if args[0] == "-ip" and len(args) >= 3:
517+
self.devCtrl.EstablishPASESessionIP(args[1].encode(
518+
"utf-8"), int(args[2]), nodeid)
519+
else:
520+
print("Usage:")
521+
self.do_help("paseonly")
522+
return
523+
print(
524+
"Device temporary node id (**this does not match spec**): {}".format(nodeid))
525+
except Exception as ex:
526+
print(str(ex))
527+
return
528+
529+
def do_commission(self, line):
530+
"""
531+
commission nodeid
532+
533+
Runs commissioning on a device that has been connected with paseonly
534+
"""
535+
try:
536+
args = shlex.split(line)
537+
if len(args) != 1:
538+
print("Usage:")
539+
self.do_help("commission")
540+
return
541+
542+
nodeid = int(args[0])
543+
self.devCtrl.Commission(nodeid)
544+
except Exception as ex:
545+
print(str(ex))
546+
return
547+
494548
def do_connect(self, line):
495549
"""
496550
connect -ip <ip address> <setup pin code> [<nodeid>]

0 commit comments

Comments
 (0)