forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCHIPDeviceController.h
895 lines (780 loc) · 40.8 KB
/
CHIPDeviceController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Declaration of CHIP Device Controller, a common class
* that implements connecting and messaging and will later
* be expanded to support discovery, pairing and
* provisioning of CHIP devices.
*
*/
#pragma once
#include <app/CASEClientPool.h>
#include <app/CASESessionManager.h>
#include <app/ClusterStateCache.h>
#include <app/OperationalSessionSetup.h>
#include <app/OperationalSessionSetupPool.h>
#include <controller/AbstractDnssdDiscoveryController.h>
#include <controller/AutoCommissioner.h>
#include <controller/CHIPCluster.h>
#include <controller/CHIPDeviceControllerSystemState.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <controller/CommissioningDelegate.h>
#include <controller/DevicePairingDelegate.h>
#include <controller/OperationalCredentialsDelegate.h>
#include <controller/SetUpCodePairer.h>
#include <credentials/FabricTable.h>
#include <credentials/attestation_verifier/DeviceAttestationDelegate.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <inet/InetInterface.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/CHIPTLV.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/DLLUtil.h>
#include <lib/support/Pool.h>
#include <lib/support/SafeInt.h>
#include <lib/support/SerializableIntegerSet.h>
#include <lib/support/Span.h>
#include <lib/support/ThreadOperationalDataset.h>
#include <messaging/ExchangeMgr.h>
#include <protocols/secure_channel/MessageCounterManager.h>
#include <protocols/secure_channel/RendezvousParameters.h>
#include <protocols/user_directed_commissioning/UserDirectedCommissioning.h>
#include <transport/SessionManager.h>
#include <transport/TransportMgr.h>
#include <transport/raw/UDP.h>
#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif
#if CONFIG_NETWORK_LAYER_BLE
#include <ble/BleLayer.h>
#endif
#include <controller/DeviceDiscoveryDelegate.h>
namespace chip {
namespace Controller {
using namespace chip::Protocols::UserDirectedCommissioning;
constexpr uint16_t kNumMaxActiveDevices = CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES;
// Raw functions for cluster callbacks
void OnBasicFailure(void * context, CHIP_ERROR err);
struct ControllerInitParams
{
DeviceControllerSystemState * systemState = nullptr;
DeviceDiscoveryDelegate * deviceDiscoveryDelegate = nullptr;
OperationalCredentialsDelegate * operationalCredentialsDelegate = nullptr;
/* The following keypair must correspond to the public key used for generating
controllerNOC. It's used by controller to establish CASE sessions with devices */
Crypto::P256Keypair * operationalKeypair = nullptr;
/**
* Controls whether or not the operationalKeypair should be owned by the caller.
* By default, this is false, but if the keypair cannot be serialized, then
* setting this to true will allow the caller to manage this keypair's lifecycle.
*/
bool hasExternallyOwnedOperationalKeypair = false;
/* The following certificates must be in x509 DER format */
ByteSpan controllerNOC;
ByteSpan controllerICAC;
ByteSpan controllerRCAC;
/**
* Controls whether we permit multiple DeviceController instances to exist
* on the same logical fabric (identified by the tuple of the fabric's
* root public key + fabric id).
*
* Each controller instance will be associated with its own FabricIndex.
* This pivots the FabricTable to tracking identities instead of fabrics,
* represented by FabricInfo instances that can have colliding logical fabrics.
*
*/
bool permitMultiControllerFabrics = false;
//
// Controls enabling server cluster interactions on a controller. This in turn
// causes the following to get enabled:
//
// - Advertisement of active controller operational identities.
//
bool enableServerInteractions = false;
chip::VendorId controllerVendorId;
};
struct CommissionerInitParams : public ControllerInitParams
{
DevicePairingDelegate * pairingDelegate = nullptr;
CommissioningDelegate * defaultCommissioner = nullptr;
// Device attestation verifier instance for the commissioning.
// If null, the globally set attestation verifier (e.g. from GetDeviceAttestationVerifier()
// singleton) will be used.
Credentials::DeviceAttestationVerifier * deviceAttestationVerifier = nullptr;
};
/**
* @brief
* Controller applications can use this class to communicate with already paired CHIP devices. The
* application is required to provide access to the persistent storage, where the paired device information
* is stored. This object of this class can be initialized with the data from the storage (List of devices,
* and device pairing information for individual devices). Alternatively, this class can retrieve the
* relevant information when the application tries to communicate with the device
*/
class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController
{
public:
DeviceController();
~DeviceController() override {}
CHIP_ERROR Init(ControllerInitParams params);
/**
* @brief
* Tears down the entirety of the stack, including destructing key objects in the system.
* This expects to be called with external thread synchronization, and will not internally
* grab the CHIP stack lock.
*
* This will also not stop the CHIP event queue / thread (if one exists). Consumers are expected to
* ensure this happened before calling this method.
*/
virtual void Shutdown();
SessionManager * SessionMgr()
{
if (mSystemState)
{
return mSystemState->SessionMgr();
}
return nullptr;
}
CHIP_ERROR GetPeerAddressAndPort(NodeId peerId, Inet::IPAddress & addr, uint16_t & port);
/**
* @brief
* Looks up the PeerAddress for an established CASE session.
*
* @param[in] nodeId the NodeId of the target.
* @param[out] addr the PeerAddress to be filled on success
*
* @return CHIP_ERROR CHIP_ERROR_NOT_CONNECTED if no CASE session exists for the device
*/
CHIP_ERROR GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr);
ScopedNodeId GetPeerScopedId(NodeId nodeId) { return ScopedNodeId(nodeId, GetFabricIndex()); }
/**
* This function finds the device corresponding to deviceId, and establishes
* a CASE session with it.
*
* Once the CASE session is successfully established the `onConnectedDevice`
* callback is called. This can happen before GetConnectedDevice returns if
* there is an existing CASE session.
*
* If a CASE sessions fails to be established, the `onError` callback will
* be called. This can also happen before GetConnectedDevice returns.
*
* An error return from this function means that neither callback has been
* called yet, and neither callback will be called in the future.
*/
CHIP_ERROR GetConnectedDevice(NodeId peerNodeId, Callback::Callback<OnDeviceConnected> * onConnection,
chip::Callback::Callback<OnDeviceConnectionFailure> * onFailure)
{
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
mSystemState->CASESessionMgr()->FindOrEstablishSession(ScopedNodeId(peerNodeId, GetFabricIndex()), onConnection, onFailure);
return CHIP_NO_ERROR;
}
/**
* @brief
* Compute a PASE verifier and passcode ID for the desired setup pincode.
*
* This can be used to open a commissioning window on the device for
* additional administrator commissioning.
*
* @param[in] iterations The number of iterations to use when generating the verifier
* @param[in] setupPincode The desired PIN code to use
* @param[in] salt The 16-byte salt for verifier computation
* @param[out] outVerifier The Spake2pVerifier to be populated on success
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR ComputePASEVerifier(uint32_t iterations, uint32_t setupPincode, const ByteSpan & salt,
Spake2pVerifier & outVerifier);
void RegisterDeviceDiscoveryDelegate(DeviceDiscoveryDelegate * delegate) { mDeviceDiscoveryDelegate = delegate; }
/**
* @brief Get the Compressed Fabric ID assigned to the device.
*/
uint64_t GetCompressedFabricId() const
{
const auto * fabricInfo = GetFabricInfo();
return (fabricInfo != nullptr) ? static_cast<uint64_t>(fabricInfo->GetCompressedFabricId()) : kUndefinedCompressedFabricId;
}
/**
* @brief Get the Compressed Fabric Id as a big-endian 64 bit octet string.
*
* Output span is resized to 8 bytes on success if it was larger.
*
* @param outBytes span to contain the compressed fabric ID, must be at least 8 bytes long
* @return CHIP_ERROR_BUFFER_TOO_SMALL if `outBytes` is too small, CHIP_ERROR_INVALID_FABRIC_INDEX
* if the controller is somehow not associated with a fabric (internal error!) or
* CHIP_NO_ERROR on success.
*/
CHIP_ERROR GetCompressedFabricIdBytes(MutableByteSpan & outBytes) const;
/**
* @brief Get the raw Fabric ID assigned to the device.
*/
uint64_t GetFabricId() const
{
const auto * fabricInfo = GetFabricInfo();
return (fabricInfo != nullptr) ? static_cast<uint64_t>(fabricInfo->GetFabricId()) : kUndefinedFabricId;
}
/**
* @brief Get the Node ID of this instance.
*/
NodeId GetNodeId() const
{
const auto * fabricInfo = GetFabricInfo();
return (fabricInfo != nullptr) ? static_cast<uint64_t>(fabricInfo->GetNodeId()) : kUndefinedNodeId;
}
/**
* @brief Get the root public key for the fabric
*
* @param outRootPublicKey reference to public key object that gets updated on success.
*
* @return CHIP_NO_ERROR on success, CHIP_ERROR_INCORRECT_STATE if fabric table is unset, or another internal error
* on storage access failure.
*/
CHIP_ERROR GetRootPublicKey(Crypto::P256PublicKey & outRootPublicKey) const;
FabricIndex GetFabricIndex() const { return mFabricIndex; }
const FabricTable * GetFabricTable() const
{
if (mSystemState == nullptr)
{
return nullptr;
}
return mSystemState->Fabrics();
}
OperationalCredentialsDelegate * GetOperationalCredentialsDelegate() { return mOperationalCredentialsDelegate; }
/**
* @brief
* Reconfigures a new set of operational credentials to be used with this
* controller given ControllerInitParams state.
*
* WARNING: This is a low-level method that should only be called directly
* if you know exactly how this will interact with controller state,
* since there are several integrations that do this call for you.
* It can be used for fine-grained dependency injection of a controller's
* NOC and operational keypair.
*/
CHIP_ERROR InitControllerNOCChain(const ControllerInitParams & params);
protected:
enum class State
{
NotInitialized,
Initialized
};
// This is not public to avoid users of DeviceController relying on "innards" access to
// the raw fabric table. Everything needed should be available with getters on DeviceController.
const FabricInfo * GetFabricInfo() const
{
VerifyOrReturnError((mState == State::Initialized) && (mFabricIndex != kUndefinedFabricIndex), nullptr);
VerifyOrReturnError(GetFabricTable() != nullptr, nullptr);
return GetFabricTable()->FindFabricWithIndex(mFabricIndex);
}
State mState;
FabricIndex mFabricIndex = kUndefinedFabricIndex;
// TODO(cecille): Make this configuarable.
static constexpr int kMaxCommissionableNodes = 10;
Dnssd::DiscoveredNodeData mCommissionableNodes[kMaxCommissionableNodes];
DeviceControllerSystemState * mSystemState = nullptr;
ControllerDeviceInitParams GetControllerDeviceInitParams();
OperationalCredentialsDelegate * mOperationalCredentialsDelegate;
chip::VendorId mVendorId;
DiscoveredNodeList GetDiscoveredNodes() override { return DiscoveredNodeList(mCommissionableNodes); }
};
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
using UdcTransportMgr = TransportMgr<Transport::UDP /* IPv6 */
#if INET_CONFIG_ENABLE_IPV4
,
Transport::UDP /* IPv4 */
#endif
>;
#endif
/**
* @brief
* The commissioner applications can use this class to pair new/unpaired CHIP devices. The application is
* required to provide write access to the persistent storage, where the paired device information
* will be stored.
*/
class DLL_EXPORT DeviceCommissioner : public DeviceController,
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
public Protocols::UserDirectedCommissioning::InstanceNameResolver,
#endif
public SessionEstablishmentDelegate,
public app::ClusterStateCache::Callback
{
public:
DeviceCommissioner();
~DeviceCommissioner() override {}
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
/**
* Set port for User Directed Commissioning
*/
CHIP_ERROR SetUdcListenPort(uint16_t listenPort);
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
/**
* Commissioner-specific initialization, includes parameters such as the pairing delegate.
*/
CHIP_ERROR Init(CommissionerInitParams params);
/**
* @brief
* Tears down the entirety of the stack, including destructing key objects in the system.
* This is not a thread-safe API, and should be called with external synchronization.
*
* Please see implementation for more details.
*/
void Shutdown() override;
// ----- Connection Management -----
/**
* @brief
* Pair a CHIP device with the provided code. The code can be either a QRCode
* or a Manual Setup Code.
* Use registered DevicePairingDelegate object to receive notifications on
* pairing status updates.
*
* Note: Pairing process requires that the caller has registered PersistentStorageDelegate
* in the Init() call.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] setUpCode The setup code for connecting to the device
* @param[in] discoveryType The network discovery type, defaults to DiscoveryType::kAll.
*/
CHIP_ERROR PairDevice(NodeId remoteDeviceId, const char * setUpCode, DiscoveryType discoveryType = DiscoveryType::kAll);
CHIP_ERROR PairDevice(NodeId remoteDeviceId, const char * setUpCode, const CommissioningParameters & CommissioningParameters,
DiscoveryType discoveryType = DiscoveryType::kAll);
/**
* @brief
* Pair a CHIP device with the provided Rendezvous connection parameters.
* Use registered DevicePairingDelegate object to receive notifications on
* pairing status updates.
*
* Note: Pairing process requires that the caller has registered PersistentStorageDelegate
* in the Init() call.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] rendezvousParams The Rendezvous connection parameters
*/
CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams);
/**
* @overload
* @param[in] remoteDeviceId The remote device Id.
* @param[in] rendezvousParams The Rendezvous connection parameters
* @param[in] commissioningParams The commissioning parameters (uses default if not supplied)
*/
CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams,
CommissioningParameters & commissioningParams);
/**
* @brief
* Start establishing a PASE connection with a node for the purposes of commissioning.
* Commissioners that wish to use the auto-commissioning functions should use the
* supplied "PairDevice" functions above to automatically establish a connection then
* perform commissioning. This function is intended to be use by commissioners that
* are not using the supplied auto-commissioner.
*
* This function is non-blocking. PASE is established once the DevicePairingDelegate
* receives the OnPairingComplete call.
*
* PASE connections can only be established with nodes that have their commissioning
* window open. The PASE connection will fail if this window is not open and the
* OnPairingComplete will be called with an error.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] params The Rendezvous connection parameters
*/
CHIP_ERROR EstablishPASEConnection(NodeId remoteDeviceId, RendezvousParameters & params);
/**
* @brief
* Start establishing a PASE connection with a node for the purposes of commissioning.
* Commissioners that wish to use the auto-commissioning functions should use the
* supplied "PairDevice" functions above to automatically establish a connection then
* perform commissioning. This function is intended to be used by commissioners that
* are not using the supplied auto-commissioner.
*
* This function is non-blocking. PASE is established once the DevicePairingDelegate
* receives the OnPairingComplete call.
*
* PASE connections can only be established with nodes that have their commissioning
* window open. The PASE connection will fail if this window is not open and in that case
* OnPairingComplete will be called with an error.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] setUpCode The setup code for connecting to the device
* @param[in] discoveryType The network discovery type, defaults to DiscoveryType::kAll.
*/
CHIP_ERROR EstablishPASEConnection(NodeId remoteDeviceId, const char * setUpCode,
DiscoveryType discoveryType = DiscoveryType::kAll);
/**
* @brief
* Start the auto-commissioning process on a node after establishing a PASE connection.
* This function is intended to be used in conjunction with the EstablishPASEConnection
* function. It can be called either before or after the DevicePairingDelegate receives
* the OnPairingComplete call. Commissioners that want to perform simple auto-commissioning
* should use the supplied "PairDevice" functions above, which will establish the PASE
* connection and commission automatically.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] params The commissioning parameters
*/
CHIP_ERROR Commission(NodeId remoteDeviceId, CommissioningParameters & params);
CHIP_ERROR Commission(NodeId remoteDeviceId);
/**
* @brief
* This function instructs the commissioner to proceed to the next stage of commissioning after
* attestation is reported to an installed attestation delegate.
*
* @param[in] device The device being commissioned.
* @param[in] attestationResult The attestation result to use instead of whatever the device
* attestation verifier came up with. May be a success or an error result.
*/
CHIP_ERROR
ContinueCommissioningAfterDeviceAttestation(DeviceProxy * device, Credentials::AttestationVerificationResult attestationResult);
CHIP_ERROR GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** device);
/**
* @brief
* This function stops a pairing process that's in progress. It does not delete the pairing of a previously
* paired device.
*
* @param[in] remoteDeviceId The remote device Id.
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR StopPairing(NodeId remoteDeviceId);
/**
* @brief
* Remove pairing for a paired device. If the device is currently being paired, it'll stop the pairing process.
*
* @param[in] remoteDeviceId The remote device Id.
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR UnpairDevice(NodeId remoteDeviceId);
//////////// SessionEstablishmentDelegate Implementation ///////////////
void OnSessionEstablishmentError(CHIP_ERROR error) override;
void OnSessionEstablished(const SessionHandle & session) override;
void RendezvousCleanup(CHIP_ERROR status);
void PerformCommissioningStep(DeviceProxy * device, CommissioningStage step, CommissioningParameters & params,
CommissioningDelegate * delegate, EndpointId endpoint, Optional<System::Clock::Timeout> timeout);
/**
* @brief
* This function validates the Attestation Information sent by the device.
*
* @param[in] info Structure contatining all the required information for validating the device attestation.
*/
CHIP_ERROR ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info);
/**
* @brief
* Sends CommissioningStepComplete report to the commissioning delegate. Function will fill in current step.
* @params[in] err error from the current step
* @params[in] report report to send. Current step will be filled in automatically
*/
void
CommissioningStageComplete(CHIP_ERROR err,
CommissioningDelegate::CommissioningReport report = CommissioningDelegate::CommissioningReport());
/**
* @brief
* This function is called by the DevicePairingDelegate to indicate that network credentials have been set
* on the CommissioningParameters of the CommissioningDelegate using CommissioningDelegate.SetCommissioningParameters().
* As a result, commissioning can advance to the next stage.
*
* The DevicePairingDelegate may call this method from the OnScanNetworksSuccess and OnScanNetworksFailure callbacks,
* or it may call this method after obtaining network credentials using asyncronous methods (prompting user, cloud API call,
* etc).
*
* @return CHIP_ERROR The return status. Returns CHIP_ERROR_INCORRECT_STATE if not in the correct state (kNeedsNetworkCreds).
*/
CHIP_ERROR NetworkCredentialsReady();
/**
* @brief
* This function returns the current CommissioningStage for this commissioner.
*/
CommissioningStage GetCommissioningStage() { return mCommissioningStage; }
#if CONFIG_NETWORK_LAYER_BLE
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
/**
* @brief
* Prior to commissioning, the Controller should make sure the BleLayer transport
* is set to the Commissioner transport and not the Server transport.
*/
void ConnectBleTransportToSelf();
#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
/**
* @brief
* Once we have finished all commissioning work, the Controller should close the BLE
* connection to the device and establish CASE session / another PASE session to the device
* if needed.
*/
void CloseBleConnection();
#endif
/**
* @brief
* Discover all devices advertising as commissionable.
* Should be called on main loop thread.
* * @param[in] filter Browse filter - controller will look for only the specified subtype.
* @return CHIP_ERROR The return status
*/
CHIP_ERROR DiscoverCommissionableNodes(Dnssd::DiscoveryFilter filter);
/**
* Stop commissionable discovery triggered by a previous
* DiscoverCommissionableNodes call.
*/
CHIP_ERROR StopCommissionableDiscovery();
/**
* @brief
* Returns information about discovered devices.
* Should be called on main loop thread.
* @return const DiscoveredNodeData* info about the selected device. May be nullptr if no information has been returned yet.
*/
const Dnssd::DiscoveredNodeData * GetDiscoveredDevice(int idx);
/**
* @brief
* Returns the max number of commissionable nodes this commissioner can track mdns information for.
* @return int The max number of commissionable nodes supported
*/
int GetMaxCommissionableNodesSupported() { return kMaxCommissionableNodes; }
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
/**
* @brief
* Called when a UDC message is received specifying the given instanceName
* This method indicates that UDC Server needs the Commissionable Node corresponding to
* the given instance name to be found. UDC Server will wait for OnCommissionableNodeFound.
*
* @param instanceName DNS-SD instance name for the client requesting commissioning
*
*/
void FindCommissionableNode(char * instanceName) override;
/**
* @brief
* Return the UDC Server instance
*
*/
UserDirectedCommissioningServer * GetUserDirectedCommissioningServer() { return mUdcServer; }
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
/**
* @brief
* Overrides method from AbstractDnssdDiscoveryController
*
* @param nodeData DNS-SD node information
*
*/
void OnNodeDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData) override;
void RegisterPairingDelegate(DevicePairingDelegate * pairingDelegate) { mPairingDelegate = pairingDelegate; }
DevicePairingDelegate * GetPairingDelegate() const { return mPairingDelegate; }
// ClusterStateCache::Callback impl
void OnDone(app::ReadClient *) override;
// Issue an NOC chain using the associated OperationalCredentialsDelegate. The NOC chain will
// be provided in X509 DER format.
// NOTE: This is only valid assuming that `mOperationalCredentialsDelegate` is what is desired
// to issue the NOC chain.
CHIP_ERROR IssueNOCChain(const ByteSpan & NOCSRElements, NodeId nodeId,
chip::Callback::Callback<OnNOCChainGeneration> * callback);
void SetDeviceAttestationVerifier(Credentials::DeviceAttestationVerifier * deviceAttestationVerifier)
{
mDeviceAttestationVerifier = deviceAttestationVerifier;
}
Optional<CommissioningParameters> GetCommissioningParameters()
{
return mDefaultCommissioner == nullptr ? NullOptional : MakeOptional(mDefaultCommissioner->GetCommissioningParameters());
}
private:
DevicePairingDelegate * mPairingDelegate;
DeviceProxy * mDeviceBeingCommissioned = nullptr;
CommissioneeDeviceProxy * mDeviceInPASEEstablishment = nullptr;
CommissioningStage mCommissioningStage = CommissioningStage::kSecurePairing;
bool mRunCommissioningAfterConnection = false;
ObjectPool<CommissioneeDeviceProxy, kNumMaxActiveDevices> mCommissioneeDevicePool;
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
UserDirectedCommissioningServer * mUdcServer = nullptr;
// mUdcTransportMgr is for insecure communication (ex. user directed commissioning)
UdcTransportMgr * mUdcTransportMgr = nullptr;
uint16_t mUdcListenPort = CHIP_UDC_PORT;
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
CHIP_ERROR LoadKeyId(PersistentStorageDelegate * delegate, uint16_t & out);
/* This function sends a Device Attestation Certificate chain request to the device.
The function does not hold a reference to the device object.
*/
CHIP_ERROR SendCertificateChainRequestCommand(DeviceProxy * device, Credentials::CertificateType certificateType,
Optional<System::Clock::Timeout> timeout);
/* This function sends an Attestation request to the device.
The function does not hold a reference to the device object.
*/
CHIP_ERROR SendAttestationRequestCommand(DeviceProxy * device, const ByteSpan & attestationNonce,
Optional<System::Clock::Timeout> timeout);
/* This function sends an CSR request to the device.
The function does not hold a reference to the device object.
*/
CHIP_ERROR SendOperationalCertificateSigningRequestCommand(DeviceProxy * device, const ByteSpan & csrNonce,
Optional<System::Clock::Timeout> timeout);
/* This function sends the operational credentials to the device.
The function does not hold a reference to the device object.
*/
CHIP_ERROR SendOperationalCertificate(DeviceProxy * device, const ByteSpan & nocCertBuf, const Optional<ByteSpan> & icaCertBuf,
AesCcm128KeySpan ipk, NodeId adminSubject, Optional<System::Clock::Timeout> timeout);
/* This function sends the trusted root certificate to the device.
The function does not hold a reference to the device object.
*/
CHIP_ERROR SendTrustedRootCertificate(DeviceProxy * device, const ByteSpan & rcac, Optional<System::Clock::Timeout> timeout);
/* This function is called by the commissioner code when the device completes
the operational credential provisioning process.
The function does not hold a reference to the device object.
*/
CHIP_ERROR OnOperationalCredentialsProvisioningCompletion(DeviceProxy * device);
/* Callback when the previously sent CSR request results in failure */
static void OnCSRFailureResponse(void * context, CHIP_ERROR error);
void ExtendArmFailSafeForDeviceAttestation(const Credentials::DeviceAttestationVerifier::AttestationInfo & info,
Credentials::AttestationVerificationResult result);
static void OnCertificateChainFailureResponse(void * context, CHIP_ERROR error);
static void OnCertificateChainResponse(
void * context, const app::Clusters::OperationalCredentials::Commands::CertificateChainResponse::DecodableType & response);
static void OnAttestationFailureResponse(void * context, CHIP_ERROR error);
static void
OnAttestationResponse(void * context,
const app::Clusters::OperationalCredentials::Commands::AttestationResponse::DecodableType & data);
/**
* @brief
* This function is called by the IM layer when the commissioner receives the CSR from the device.
* (Reference: Specifications section 11.18.5.6. NOCSR Elements)
*
* @param[in] context The context provided while registering the callback.
* @param[in] data The response struct containing the following fields:
* NOCSRElements: CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
* AttestationSignature: Cryptographic signature generated for the fields in the response
* message.
*/
static void OnOperationalCertificateSigningRequest(
void * context, const app::Clusters::OperationalCredentials::Commands::CSRResponse::DecodableType & data);
/* Callback when adding operational certs to device results in failure */
static void OnAddNOCFailureResponse(void * context, CHIP_ERROR errro);
/* Callback when the device confirms that it has added the operational certificates */
static void
OnOperationalCertificateAddResponse(void * context,
const app::Clusters::OperationalCredentials::Commands::NOCResponse::DecodableType & data);
/* Callback when the device confirms that it has added the root certificate */
static void OnRootCertSuccessResponse(void * context, const chip::app::DataModel::NullObjectType &);
/* Callback called when adding root cert to device results in failure */
static void OnRootCertFailureResponse(void * context, CHIP_ERROR error);
static void OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr, SessionHandle & sessionHandle);
static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
static void OnDeviceAttestationInformationVerification(void * context,
const Credentials::DeviceAttestationVerifier::AttestationInfo & info,
Credentials::AttestationVerificationResult result);
static void OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const ByteSpan & noc, const ByteSpan & icac,
const ByteSpan & rcac, Optional<AesCcm128KeySpan> ipk, Optional<NodeId> adminSubject);
static void OnArmFailSafe(void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data);
static void OnSetRegulatoryConfigResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data);
static void
OnScanNetworksResponse(void * context,
const app::Clusters::NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & data);
static void OnScanNetworksFailure(void * context, CHIP_ERROR err);
static void
OnNetworkConfigResponse(void * context,
const app::Clusters::NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data);
static void OnConnectNetworkResponse(
void * context, const chip::app::Clusters::NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data);
static void OnCommissioningCompleteResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::CommissioningCompleteResponse::DecodableType & data);
static void OnDisarmFailsafe(void * context,
const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data);
static void OnDisarmFailsafeFailure(void * context, CHIP_ERROR error);
void DisarmDone();
static void OnArmFailSafeExtendedForDeviceAttestation(
void * context, const chip::app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data);
static void OnFailedToExtendedArmFailSafeDeviceAttestation(void * context, CHIP_ERROR error);
/**
* @brief
* This function processes the CSR sent by the device.
* (Reference: Specifications section 11.18.5.6. NOCSR Elements)
*
* @param[in] proxy device proxy
* @param[in] NOCSRElements CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
* @param[in] AttestationSignature Cryptographic signature generated for all the above fields.
* @param[in] dac device attestation certificate
* @param[in] pai Product Attestation Intermediate certificate
* @param[in] csrNonce certificate signing request nonce
*/
CHIP_ERROR ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature,
const ByteSpan & dac, const ByteSpan & pai, const ByteSpan & csrNonce);
/**
* @brief
* This function validates the CSR information from the device.
* (Reference: Specifications section 11.18.5.6. NOCSR Elements)
*
* @param[in] proxy device proxy
* @param[in] NOCSRElements CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
* @param[in] AttestationSignature Cryptographic signature generated for all the above fields.
* @param[in] dac device attestation certificate
* @param[in] csrNonce certificate signing request nonce
*/
CHIP_ERROR ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature,
const ByteSpan & dac, const ByteSpan & csrNonce);
/**
* @brief
* This function processes the DAC or PAI certificate sent by the device.
*/
CHIP_ERROR ProcessCertificateChain(const ByteSpan & certificate);
void HandleAttestationResult(CHIP_ERROR err);
CommissioneeDeviceProxy * FindCommissioneeDevice(NodeId id);
CommissioneeDeviceProxy * FindCommissioneeDevice(const Transport::PeerAddress & peerAddress);
void ReleaseCommissioneeDevice(CommissioneeDeviceProxy * device);
template <typename ClusterObjectT, typename RequestObjectT>
CHIP_ERROR SendCommand(DeviceProxy * device, const RequestObjectT & request,
CommandResponseSuccessCallback<typename RequestObjectT::ResponseType> successCb,
CommandResponseFailureCallback failureCb, Optional<System::Clock::Timeout> timeout)
{
return SendCommand<ClusterObjectT>(device, request, successCb, failureCb, 0, timeout);
}
template <typename ClusterObjectT, typename RequestObjectT>
CHIP_ERROR SendCommand(DeviceProxy * device, const RequestObjectT & request,
CommandResponseSuccessCallback<typename RequestObjectT::ResponseType> successCb,
CommandResponseFailureCallback failureCb, EndpointId endpoint, Optional<System::Clock::Timeout> timeout)
{
ClusterObjectT cluster(*device->GetExchangeManager(), device->GetSecureSession().Value(), endpoint);
cluster.SetCommandTimeout(timeout);
return cluster.InvokeCommand(request, this, successCb, failureCb);
}
static CHIP_ERROR ConvertFromOperationalCertStatus(chip::app::Clusters::OperationalCredentials::OperationalCertStatus err);
// Sends commissioning complete callbacks to the delegate depending on the status. Sends
// OnCommissioningComplete and either OnCommissioningSuccess or OnCommissioningFailure depending on the given completion status.
void SendCommissioningCompleteCallbacks(NodeId nodeId, const CompletionStatus & completionStatus);
// Cleans up and resets failsafe as appropriate depending on the error and the failed stage.
// For success, sends completion report with the CommissioningDelegate and sends callbacks to the PairingDelegate
// For failures after AddNOC succeeds, sends completion report with the CommissioningDelegate and sends callbacks to the
// PairingDelegate. In this case, it does not disarm the failsafe or close the pase connection. For failures up through AddNOC,
// sends a command to immediately expire the failsafe, then sends completion report with the CommissioningDelegate and callbacks
// to the PairingDelegate upon arm failsafe command completion.
void CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus);
chip::Callback::Callback<OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
chip::Callback::Callback<Credentials::DeviceAttestationVerifier::OnAttestationInformationVerification>
mDeviceAttestationInformationVerificationCallback;
chip::Callback::Callback<OnNOCChainGeneration> mDeviceNOCChainCallback;
SetUpCodePairer mSetUpCodePairer;
AutoCommissioner mAutoCommissioner;
CommissioningDelegate * mDefaultCommissioner =
nullptr; // Commissioning delegate to call when PairDevice / Commission functions are used
CommissioningDelegate * mCommissioningDelegate =
nullptr; // Commissioning delegate that issued the PerformCommissioningStep command
CompletionStatus commissioningCompletionStatus;
Platform::UniquePtr<app::ClusterStateCache> mAttributeCache;
Platform::UniquePtr<app::ReadClient> mReadClient;
Credentials::AttestationVerificationResult mAttestationResult;
Platform::UniquePtr<Credentials::DeviceAttestationVerifier::AttestationDeviceInfo> mAttestationDeviceInfo;
Credentials::DeviceAttestationVerifier * mDeviceAttestationVerifier = nullptr;
};
} // namespace Controller
} // namespace chip