forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommissioningDelegate.h
818 lines (735 loc) · 39.2 KB
/
CommissioningDelegate.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
/*
*
* Copyright (c) 2021 Project CHIP Authors
* 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.
*/
#pragma once
#include <app-common/zap-generated/cluster-objects.h>
#include <app/OperationalSessionSetup.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <credentials/attestation_verifier/DeviceAttestationDelegate.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/support/Variant.h>
#include <system/SystemClock.h>
namespace chip {
namespace Controller {
class DeviceCommissioner;
enum CommissioningStage : uint8_t
{
kError,
kSecurePairing, ///< Establish a PASE session with the device
kReadCommissioningInfo, ///< Query General Commissioning Attributes, Network Features and Time Synchronization Cluster
kReadCommissioningInfo2, ///< Query SupportsConcurrentConnection, ICD state, check for matching fabric
kArmFailsafe, ///< Send ArmFailSafe (0x30:0) command to the device
kConfigRegulatory, ///< Send SetRegulatoryConfig (0x30:2) command to the device
kConfigureUTCTime, ///< SetUTCTime if the DUT has a time cluster
kConfigureTimeZone, ///< Configure a time zone if one is required and available
kConfigureDSTOffset, ///< Configure DST offset if one is required and available
kConfigureDefaultNTP, ///< Configure a default NTP server if one is required and available
kSendPAICertificateRequest, ///< Send PAI CertificateChainRequest (0x3E:2) command to the device
kSendDACCertificateRequest, ///< Send DAC CertificateChainRequest (0x3E:2) command to the device
kSendAttestationRequest, ///< Send AttestationRequest (0x3E:0) command to the device
kAttestationVerification, ///< Verify AttestationResponse (0x3E:1) validity
kAttestationRevocationCheck, ///< Verify Revocation Status of device's DAC chain
kSendOpCertSigningRequest, ///< Send CSRRequest (0x3E:4) command to the device
kValidateCSR, ///< Verify CSRResponse (0x3E:5) validity
kGenerateNOCChain, ///< TLV encode Node Operational Credentials (NOC) chain certs
kSendTrustedRootCert, ///< Send AddTrustedRootCertificate (0x3E:11) command to the device
kSendNOC, ///< Send AddNOC (0x3E:6) command to the device
kConfigureTrustedTimeSource, ///< Configure a trusted time source if one is required and available (must be done after SendNOC)
kICDGetRegistrationInfo, ///< Waiting for the higher layer to provide ICD registraion informations.
kICDRegistration, ///< Register for ICD management
kWiFiNetworkSetup, ///< Send AddOrUpdateWiFiNetwork (0x31:2) command to the device
kThreadNetworkSetup, ///< Send AddOrUpdateThreadNetwork (0x31:3) command to the device
kFailsafeBeforeWiFiEnable, ///< Extend the fail-safe before doing kWiFiNetworkEnable
kFailsafeBeforeThreadEnable, ///< Extend the fail-safe before doing kThreadNetworkEnable
kWiFiNetworkEnable, ///< Send ConnectNetwork (0x31:6) command to the device for the WiFi network
kThreadNetworkEnable, ///< Send ConnectNetwork (0x31:6) command to the device for the Thread network
kEvictPreviousCaseSessions, ///< Evict previous stale case sessions from a commissioned device with this node ID before
kFindOperationalForStayActive, ///< Perform operational discovery and establish a CASE session with the device for ICD
///< StayActive command
kFindOperationalForCommissioningComplete, ///< Perform operational discovery and establish a CASE session with the device for
///< Commissioning Complete command
kSendComplete, ///< Send CommissioningComplete (0x30:4) command to the device
kICDSendStayActive, ///< Send Keep Alive to ICD
kCleanup, ///< Call delegates with status, free memory, clear timers and state
/// Send ScanNetworks (0x31:0) command to the device.
/// ScanNetworks can happen anytime after kArmFailsafe.
/// However, the cirque tests fail if it is earlier in the list
kScanNetworks,
/// Waiting for the higher layer to provide network credentials before continuing the workflow.
/// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with
/// network credentials to use in kWiFiNetworkSetup or kThreadNetworkSetup steps.
kNeedsNetworkCreds,
};
enum class ICDRegistrationStrategy : uint8_t
{
kIgnore, ///< Do not check whether the device is an ICD during commissioning
kBeforeComplete, ///< Do commissioner self-registration or external controller registration,
///< Controller should provide a ICDKey manager for generating symmetric key
};
const char * StageToString(CommissioningStage stage);
struct WiFiCredentials
{
ByteSpan ssid;
ByteSpan credentials;
WiFiCredentials(ByteSpan newSsid, ByteSpan newCreds) : ssid(newSsid), credentials(newCreds) {}
};
struct NOCChainGenerationParameters
{
ByteSpan nocsrElements;
ByteSpan signature;
};
struct CompletionStatus
{
CompletionStatus() : err(CHIP_NO_ERROR), failedStage(NullOptional), attestationResult(NullOptional) {}
CHIP_ERROR err;
Optional<CommissioningStage> failedStage;
Optional<Credentials::AttestationVerificationResult> attestationResult;
Optional<app::Clusters::GeneralCommissioning::CommissioningErrorEnum> commissioningError;
Optional<app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum> networkCommissioningStatus;
};
inline constexpr uint16_t kDefaultFailsafeTimeout = 60;
// Per spec, all commands that are sent with the failsafe armed need at least
// a 30s timeout.
inline constexpr System::Clock::Timeout kMinimumCommissioningStepTimeout = System::Clock::Seconds16(30);
class CommissioningParameters
{
public:
static constexpr size_t kMaxThreadDatasetLen = 254;
static constexpr size_t kMaxSsidLen = 32;
static constexpr size_t kMaxCredentialsLen = 64;
static constexpr size_t kMaxCountryCodeLen = 2;
// Value to use when setting the commissioning failsafe timer on the node being commissioned.
// If the failsafe timer value is passed in as part of the commissioning parameters, that value will be used. If not supplied,
// the AutoCommissioner will set this to the recommended value read from the node. If that is not set, it will fall back to the
// default kDefaultFailsafeTimeout.
// This value should be set before running PerformCommissioningStep for the kArmFailsafe step.
const Optional<uint16_t> GetFailsafeTimerSeconds() const { return mFailsafeTimerSeconds; }
// Value to use when re-setting the commissioning failsafe timer immediately prior to operational discovery.
// If a CASE failsafe timer value is passed in as part of the commissioning parameters, then the failsafe timer
// will be reset using this value before operational discovery begins. If not supplied, then the AutoCommissioner
// will not automatically reset the failsafe timer before operational discovery begins. It can be useful for the
// commissioner to set the CASE failsafe timer to a small value (ex. 30s) when the regular failsafe timer is set
// to a larger value to accommodate user interaction during setup (network credential selection, user consent
// after device attestation).
const Optional<uint16_t> GetCASEFailsafeTimerSeconds() const { return mCASEFailsafeTimerSeconds; }
// The location (indoor/outdoor) of the node being commissioned.
// The node regulartory location (indoor/outdoor) should be set by the commissioner explicitly as it may be different than the
// location of the commissioner. This location will be set on the node if the node supports configurable regulatory location
// (from GetLocationCapability - see below). If the regulatory location is not supplied, this will fall back to the location in
// GetDefaultRegulatoryLocation and then to Outdoor (most restrictive).
// This value should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetDeviceRegulatoryLocation() const
{
return mDeviceRegulatoryLocation;
}
// Value to determine whether the node supports Concurrent Connections as read from the GeneralCommissioning cluster.
// In the AutoCommissioner, this is automatically set from from the kReadCommissioningInfo2 stage.
Optional<bool> GetSupportsConcurrentConnection() const { return mSupportsConcurrentConnection; }
// The country code to be used for the node, if set.
Optional<CharSpan> GetCountryCode() const { return mCountryCode; }
// Time zone to set for the node
// If required, this will be truncated to fit the max size allowable on the node
Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>> GetTimeZone() const
{
return mTimeZone;
}
// DST offset list. If required, this will be truncated to fit the max size allowable on the node
// DST list will only be sent if the commissionee requires DST offsets, as indicated in the SetTimeZone response
Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>> GetDSTOffsets() const
{
return mDSTOffsets;
}
// Default NTP to set on the node if supported and required
// Default implementation will not overide a value already set on the commissionee
// TODO: Add a force option?
Optional<app::DataModel::Nullable<CharSpan>> GetDefaultNTP() const { return mDefaultNTP; }
// Trusted time source
// Default implementation will not override a value already set on the commissionee
// TODO: Add a force option?
Optional<app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>>
GetTrustedTimeSource() const
{
return mTrustedTimeSource;
}
// Nonce sent to the node to use during the CSR request.
// When using the AutoCommissioner, this value will be ignored in favour of the value supplied by the
// OperationalCredentialsDelegate ObtainCsrNonce function. If the credential delegate is not supplied, the value supplied here
// will be used. If neither is supplied random value will be used as a fallback.
// This value must be set before calling PerformCommissioningStep for the kSendOpCertSigningRequest step.
const Optional<ByteSpan> GetCSRNonce() const { return mCSRNonce; }
// Nonce value sent to the node to use during the attestation request.
// When using the AutoCommissioner, this value will fall back to random if not supplied.
// If a non-random value is to be used, the value must be set before calling PerformCommissioningStep for the
// kSendAttestationRequest step.
const Optional<ByteSpan> GetAttestationNonce() const { return mAttestationNonce; }
// WiFi SSID and credentials to use when adding/updating and enabling WiFi on the node.
// This value must be set before calling PerformCommissioningStep for the kWiFiNetworkSetup or kWiFiNetworkEnable steps.
const Optional<WiFiCredentials> GetWiFiCredentials() const { return mWiFiCreds; }
// Thread operational dataset to use when adding/updating and enabling the thread network on the node.
// This value must be set before calling PerformCommissioningStep for the kThreadNetworkSetup or kThreadNetworkEnable steps.
const Optional<ByteSpan> GetThreadOperationalDataset() const { return mThreadOperationalDataset; }
// The NOCSR parameters (elements and signature) returned from the node. In the AutoCommissioner, this is set using the data
// returned from the kSendOpCertSigningRequest stage.
// This value must be set before calling PerformCommissioningStep for the kGenerateNOCChain step.
const Optional<NOCChainGenerationParameters> GetNOCChainGenerationParameters() const { return mNOCChainGenerationParameters; }
// The root certificate for the operational certificate chain. In the auto commissioner, this is set by by the kGenerateNOCChain
// stage through the OperationalCredentialsDelegate.
// This value must be set before calling PerformCommissioningStep for the kSendTrustedRootCert step.
const Optional<ByteSpan> GetRootCert() const { return mRootCert; }
// The node operational certificate for the node being commissioned. In the AutoCommissioner, this is set by by the
// kGenerateNOCChain stage through the OperationalCredentialsDelegate.
// This value must be set before calling PerformCommissioningStep for the kSendNOC step.
// This value must also be set before calling PerformCommissioningStep for the kSendTrustedRootCert step, as it is used to set
// the node id in the DeviceProxy.
const Optional<ByteSpan> GetNoc() const { return mNoc; }
// The intermediate certificate for the node being commissioned. In the AutoCommissioner, this is set by by the
// kGenerateNOCChain stage through the OperationalCredentialsDelegate.
// This value should be set before calling PerformCommissioningStep for the kSendNOC step.
const Optional<ByteSpan> GetIcac() const { return mIcac; }
// Epoch key for the identity protection key for the node being commissioned. In the AutoCommissioner, this is set by by the
// kGenerateNOCChain stage through the OperationalCredentialsDelegate.
// This value must be set before calling PerformCommissioningStep for the kSendNOC step.
const Optional<Crypto::IdentityProtectionKeySpan> GetIpk() const
{
return mIpk.HasValue() ? MakeOptional(mIpk.Value().Span()) : NullOptional;
}
// Admin subject id used for the case access control entry created if the AddNOC command succeeds. In the AutoCommissioner, this
// is set by by the kGenerateNOCChain stage through the OperationalCredentialsDelegate.
// This must be set before calling PerformCommissioningStep for the kSendNOC step.
const Optional<NodeId> GetAdminSubject() const { return mAdminSubject; }
// Attestation elements from the node. These are obtained from node in response to the AttestationRequest command. In the
// AutoCommissioner, this is automatically set from the report from the kSendAttestationRequest stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
const Optional<ByteSpan> GetAttestationElements() const { return mAttestationElements; }
// Attestation signature from the node. This is obtained from node in response to the AttestationRequest command. In the
// AutoCommissioner, this is automatically set from the report from the kSendAttestationRequest stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
const Optional<ByteSpan> GetAttestationSignature() const { return mAttestationSignature; }
// Product attestation intermediate certificate from the node. This is obtained from the node in response to the
// CertificateChainRequest command for the PAI. In the AutoCommissioner, this is automatically set from the report from the
// kSendPAICertificateRequest stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerificationstep.
const Optional<ByteSpan> GetPAI() const { return mPAI; }
// Device attestation certificate from the node. This is obtained from the node in response to the CertificateChainRequest
// command for the DAC. In the AutoCommissioner, this is automatically set from the report from the kSendDACCertificateRequest
// stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
const Optional<ByteSpan> GetDAC() const { return mDAC; }
// Node ID when a matching fabric is found in the Node Operational Credentials cluster.
// In the AutoCommissioner, this is set from kReadCommissioningInfo stage.
const Optional<NodeId> GetRemoteNodeId() const { return mRemoteNodeId; }
// Node vendor ID from the basic information cluster. In the AutoCommissioner, this is automatically set from report from the
// kReadCommissioningInfo stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
const Optional<VendorId> GetRemoteVendorId() const { return mRemoteVendorId; }
// Node product ID from the basic information cluster. In the AutoCommissioner, this is automatically set from report from the
// kReadCommissioningInfo stage.
// This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
const Optional<uint16_t> GetRemoteProductId() const { return mRemoteProductId; }
// Default regulatory location set by the node, as read from the GeneralCommissioning cluster. In the AutoCommissioner, this is
// automatically set from report from the kReadCommissioningInfo stage.
// This should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetDefaultRegulatoryLocation() const
{
return mDefaultRegulatoryLocation;
}
// Location capabilities of the node, as read from the GeneralCommissioning cluster. In the AutoCommissioner, this is
// automatically set from report from the kReadCommissioningInfo stage.
// This should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetLocationCapability() const
{
return mLocationCapability;
}
// Status to send when calling CommissioningComplete on the PairingDelegate during the kCleanup step. The AutoCommissioner uses
// this to pass through any error messages received during commissioning.
const CompletionStatus & GetCompletionStatus() const { return completionStatus; }
CommissioningParameters & SetFailsafeTimerSeconds(uint16_t seconds)
{
mFailsafeTimerSeconds.SetValue(seconds);
return *this;
}
CommissioningParameters & SetCASEFailsafeTimerSeconds(uint16_t seconds)
{
mCASEFailsafeTimerSeconds.SetValue(seconds);
return *this;
}
CommissioningParameters & SetDeviceRegulatoryLocation(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum location)
{
mDeviceRegulatoryLocation.SetValue(location);
return *this;
}
CommissioningParameters & SetSupportsConcurrentConnection(bool concurrentConnection)
{
mSupportsConcurrentConnection.SetValue(concurrentConnection);
return *this;
}
// The lifetime of the buffer countryCode is pointing to should exceed the
// lifetime of CommissioningParameters object.
CommissioningParameters & SetCountryCode(CharSpan countryCode)
{
mCountryCode.SetValue(countryCode);
return *this;
}
// The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object.
CommissioningParameters &
SetTimeZone(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> timeZone)
{
mTimeZone.SetValue(timeZone);
return *this;
}
// The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object.
CommissioningParameters &
SetDSTOffsets(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type> dstOffsets)
{
mDSTOffsets.SetValue(dstOffsets);
return *this;
}
// The lifetime of the char span needs to exceed the lifetime of the CommissioningParameters
CommissioningParameters & SetDefaultNTP(app::DataModel::Nullable<CharSpan> defaultNTP)
{
mDefaultNTP.SetValue(defaultNTP);
return *this;
}
CommissioningParameters & SetTrustedTimeSource(
app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>
trustedTimeSource)
{
mTrustedTimeSource.SetValue(trustedTimeSource);
return *this;
}
// The lifetime of the buffer csrNonce is pointing to, should exceed the lifetime of CommissioningParameters object.
CommissioningParameters & SetCSRNonce(ByteSpan csrNonce)
{
mCSRNonce.SetValue(csrNonce);
return *this;
}
// The lifetime of the buffer attestationNonce is pointing to, should exceed the lifetime of CommissioningParameters object.
CommissioningParameters & SetAttestationNonce(ByteSpan attestationNonce)
{
mAttestationNonce.SetValue(attestationNonce);
return *this;
}
// If a WiFiCredentials is provided, then the WiFiNetworkScan will not be attempted
CommissioningParameters & SetWiFiCredentials(WiFiCredentials wifiCreds)
{
mWiFiCreds.SetValue(wifiCreds);
mAttemptWiFiNetworkScan.SetValue(false);
return *this;
}
// If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
CommissioningParameters & SetThreadOperationalDataset(ByteSpan threadOperationalDataset)
{
mThreadOperationalDataset.SetValue(threadOperationalDataset);
mAttemptThreadNetworkScan = MakeOptional(static_cast<bool>(false));
return *this;
}
// This parameter should be set with the information returned from kSendOpCertSigningRequest. It must be set before calling
// kGenerateNOCChain.
CommissioningParameters & SetNOCChainGenerationParameters(const NOCChainGenerationParameters & params)
{
mNOCChainGenerationParameters.SetValue(params);
return *this;
}
// Root certs can be generated from the kGenerateNOCChain step. This must be set before calling kSendTrustedRootCert.
CommissioningParameters & SetRootCert(const ByteSpan & rcac)
{
mRootCert.SetValue(rcac);
return *this;
}
// NOC and intermediate cert can be generated from the kGenerateNOCChain step. NOC must be set before calling
// kSendTrustedRootCert. ICAC and NOC must be set before calling kSendNOC
CommissioningParameters & SetNoc(const ByteSpan & noc)
{
mNoc.SetValue(noc);
return *this;
}
CommissioningParameters & SetIcac(const ByteSpan & icac)
{
mIcac.SetValue(icac);
return *this;
}
CommissioningParameters & SetIpk(const Crypto::IdentityProtectionKeySpan ipk)
{
mIpk.SetValue(Crypto::IdentityProtectionKey(ipk));
return *this;
}
CommissioningParameters & SetAdminSubject(const NodeId adminSubject)
{
mAdminSubject.SetValue(adminSubject);
return *this;
}
CommissioningParameters & SetAttestationElements(const ByteSpan & attestationElements)
{
mAttestationElements = MakeOptional(attestationElements);
return *this;
}
CommissioningParameters & SetAttestationSignature(const ByteSpan & attestationSignature)
{
mAttestationSignature = MakeOptional(attestationSignature);
return *this;
}
CommissioningParameters & SetPAI(const ByteSpan & pai)
{
mPAI = MakeOptional(pai);
return *this;
}
CommissioningParameters & SetDAC(const ByteSpan & dac)
{
mDAC = MakeOptional(dac);
return *this;
}
CommissioningParameters & SetRemoteNodeId(NodeId id)
{
mRemoteNodeId = MakeOptional(id);
return *this;
}
CommissioningParameters & SetRemoteVendorId(VendorId id)
{
mRemoteVendorId = MakeOptional(id);
return *this;
}
CommissioningParameters & SetRemoteProductId(uint16_t id)
{
mRemoteProductId = MakeOptional(id);
return *this;
}
CommissioningParameters & SetDefaultRegulatoryLocation(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum location)
{
mDefaultRegulatoryLocation = MakeOptional(location);
return *this;
}
CommissioningParameters & SetLocationCapability(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum capability)
{
mLocationCapability = MakeOptional(capability);
return *this;
}
void SetCompletionStatus(const CompletionStatus & status) { completionStatus = status; }
CommissioningParameters & SetDeviceAttestationDelegate(Credentials::DeviceAttestationDelegate * deviceAttestationDelegate)
{
mDeviceAttestationDelegate = deviceAttestationDelegate;
return *this;
}
Credentials::DeviceAttestationDelegate * GetDeviceAttestationDelegate() const { return mDeviceAttestationDelegate; }
// If an SSID is provided, and AttemptWiFiNetworkScan is true,
// then a directed scan will be performed using the SSID provided in the WiFiCredentials object
Optional<bool> GetAttemptWiFiNetworkScan() const { return mAttemptWiFiNetworkScan; }
CommissioningParameters & SetAttemptWiFiNetworkScan(bool attemptWiFiNetworkScan)
{
mAttemptWiFiNetworkScan = MakeOptional(attemptWiFiNetworkScan);
return *this;
}
// If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
Optional<bool> GetAttemptThreadNetworkScan() const { return mAttemptThreadNetworkScan; }
CommissioningParameters & SetAttemptThreadNetworkScan(bool attemptThreadNetworkScan)
{
if (!mThreadOperationalDataset.HasValue())
{
mAttemptThreadNetworkScan = MakeOptional(attemptThreadNetworkScan);
}
return *this;
}
// Only perform the PASE steps of commissioning.
// Commissioning will be completed by another admin on the network.
Optional<bool> GetSkipCommissioningComplete() const { return mSkipCommissioningComplete; }
CommissioningParameters & SetSkipCommissioningComplete(bool skipCommissioningComplete)
{
mSkipCommissioningComplete = MakeOptional(skipCommissioningComplete);
return *this;
}
// Check for matching fabric on target device by reading fabric list and looking for a
// fabricId and RootCert match. If a match is detected, then use GetNodeId() to
// access the nodeId for the device on the matching fabric.
bool GetCheckForMatchingFabric() const { return mCheckForMatchingFabric; }
CommissioningParameters & SetCheckForMatchingFabric(bool checkForMatchingFabric)
{
mCheckForMatchingFabric = checkForMatchingFabric;
return *this;
}
ICDRegistrationStrategy GetICDRegistrationStrategy() const { return mICDRegistrationStrategy; }
CommissioningParameters & SetICDRegistrationStrategy(ICDRegistrationStrategy icdRegistrationStrategy)
{
mICDRegistrationStrategy = icdRegistrationStrategy;
return *this;
}
Optional<NodeId> GetICDCheckInNodeId() const { return mICDCheckInNodeId; }
CommissioningParameters & SetICDCheckInNodeId(NodeId icdCheckInNodeId)
{
mICDCheckInNodeId = MakeOptional(icdCheckInNodeId);
return *this;
}
Optional<uint64_t> GetICDMonitoredSubject() const { return mICDMonitoredSubject; }
CommissioningParameters & SetICDMonitoredSubject(uint64_t icdMonitoredSubject)
{
mICDMonitoredSubject = MakeOptional(icdMonitoredSubject);
return *this;
}
Optional<ByteSpan> GetICDSymmetricKey() const { return mICDSymmetricKey; }
CommissioningParameters & SetICDSymmetricKey(ByteSpan icdSymmetricKey)
{
mICDSymmetricKey = MakeOptional(icdSymmetricKey);
return *this;
}
Optional<uint32_t> GetICDStayActiveDurationMsec() const { return mICDStayActiveDurationMsec; }
CommissioningParameters & SetICDStayActiveDurationMsec(uint32_t stayActiveDurationMsec)
{
mICDStayActiveDurationMsec = MakeOptional(stayActiveDurationMsec);
return *this;
}
void ClearICDStayActiveDurationMsec() { mICDStayActiveDurationMsec.ClearValue(); }
// Clear all members that depend on some sort of external buffer. Can be
// used to make sure that we are not holding any dangling pointers.
void ClearExternalBufferDependentValues()
{
mCSRNonce.ClearValue();
mAttestationNonce.ClearValue();
mWiFiCreds.ClearValue();
mCountryCode.ClearValue();
mThreadOperationalDataset.ClearValue();
mNOCChainGenerationParameters.ClearValue();
mRootCert.ClearValue();
mNoc.ClearValue();
mIcac.ClearValue();
mIpk.ClearValue();
mAttestationElements.ClearValue();
mAttestationSignature.ClearValue();
mPAI.ClearValue();
mDAC.ClearValue();
mTimeZone.ClearValue();
mDSTOffsets.ClearValue();
mDefaultNTP.ClearValue();
mICDSymmetricKey.ClearValue();
}
private:
// Items that can be set by the commissioner
Optional<uint16_t> mFailsafeTimerSeconds;
Optional<uint16_t> mCASEFailsafeTimerSeconds;
Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mDeviceRegulatoryLocation;
Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>> mTimeZone;
Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>> mDSTOffsets;
Optional<app::DataModel::Nullable<CharSpan>> mDefaultNTP;
Optional<app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>>
mTrustedTimeSource;
Optional<ByteSpan> mCSRNonce;
Optional<ByteSpan> mAttestationNonce;
Optional<WiFiCredentials> mWiFiCreds;
Optional<CharSpan> mCountryCode;
Optional<ByteSpan> mThreadOperationalDataset;
Optional<NOCChainGenerationParameters> mNOCChainGenerationParameters;
Optional<ByteSpan> mRootCert;
Optional<ByteSpan> mNoc;
Optional<ByteSpan> mIcac;
Optional<Crypto::IdentityProtectionKey> mIpk;
Optional<NodeId> mAdminSubject;
// Items that come from the device in commissioning steps
Optional<ByteSpan> mAttestationElements;
Optional<ByteSpan> mAttestationSignature;
Optional<ByteSpan> mPAI;
Optional<ByteSpan> mDAC;
Optional<NodeId> mRemoteNodeId;
Optional<VendorId> mRemoteVendorId;
Optional<uint16_t> mRemoteProductId;
Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mDefaultRegulatoryLocation;
Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mLocationCapability;
Optional<bool> mSupportsConcurrentConnection;
CompletionStatus completionStatus;
Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate =
nullptr; // Delegate to handle device attestation failures during commissioning
Optional<bool> mAttemptWiFiNetworkScan;
Optional<bool> mAttemptThreadNetworkScan; // This automatically gets set to false when a ThreadOperationalDataset is set
Optional<bool> mSkipCommissioningComplete;
Optional<NodeId> mICDCheckInNodeId;
Optional<uint64_t> mICDMonitoredSubject;
Optional<ByteSpan> mICDSymmetricKey;
Optional<uint32_t> mICDStayActiveDurationMsec;
ICDRegistrationStrategy mICDRegistrationStrategy = ICDRegistrationStrategy::kIgnore;
bool mCheckForMatchingFabric = false;
};
struct RequestedCertificate
{
RequestedCertificate(ByteSpan newCertificate) : certificate(newCertificate) {}
ByteSpan certificate;
};
struct AttestationResponse
{
AttestationResponse(ByteSpan newAttestationElements, ByteSpan newSignature) :
attestationElements(newAttestationElements), signature(newSignature)
{}
ByteSpan attestationElements;
ByteSpan signature;
};
struct CSRResponse
{
CSRResponse(ByteSpan elements, ByteSpan newSignature) : nocsrElements(elements), signature(newSignature) {}
ByteSpan nocsrElements;
ByteSpan signature;
};
struct NocChain
{
NocChain(ByteSpan newNoc, ByteSpan newIcac, ByteSpan newRcac, Crypto::IdentityProtectionKeySpan newIpk,
NodeId newAdminSubject) :
noc(newNoc),
icac(newIcac), rcac(newRcac), ipk(newIpk), adminSubject(newAdminSubject)
{}
ByteSpan noc;
ByteSpan icac;
ByteSpan rcac;
Crypto::IdentityProtectionKeySpan ipk;
NodeId adminSubject;
};
struct OperationalNodeFoundData
{
OperationalNodeFoundData(OperationalDeviceProxy proxy) : operationalProxy(proxy) {}
OperationalDeviceProxy operationalProxy;
};
struct NetworkClusterInfo
{
EndpointId endpoint = kInvalidEndpointId;
app::Clusters::NetworkCommissioning::Attributes::ConnectMaxTimeSeconds::TypeInfo::DecodableType minConnectionTime;
};
struct NetworkClusters
{
NetworkClusterInfo wifi;
NetworkClusterInfo thread;
NetworkClusterInfo eth;
};
struct BasicClusterInfo
{
VendorId vendorId = VendorId::Common;
uint16_t productId = 0;
};
struct GeneralCommissioningInfo
{
uint64_t breadcrumb = 0;
uint16_t recommendedFailsafe = 0;
app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum currentRegulatoryLocation =
app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor;
app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum locationCapability =
app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor;
;
};
// ICDManagementClusterInfo is populated when the controller reads information from
// the ICD Management cluster, and is used to communicate that information.
struct ICDManagementClusterInfo
{
// Whether the ICD is capable of functioning as a LIT device. If false, the ICD can only be a SIT device.
bool isLIT = false;
// Whether the ICD supports the check-in protocol. LIT devices have to support it, but SIT devices
// might or might not.
bool checkInProtocolSupport = false;
// Indicate the maximum interval in seconds the server can stay in idle mode.
uint32_t idleModeDuration = 0;
// Indicate the minimum interval in milliseconds the server typically will stay in active mode after initial transition out of
// idle mode.
uint32_t activeModeDuration = 0;
// Indicate the minimum amount of time in milliseconds the server typically will stay active after network activity when in
// active mode.
uint16_t activeModeThreshold = 0;
// userActiveModeTriggerHint indicates which user action(s) will trigger the ICD to switch to Active mode.
// For a LIT: The device is required to provide a value for the bitmap.
// For a SIT: The device may not provide a value. In that case, none of the bits will be set.
//
// userActiveModeTriggerInstruction may provide additional information for users for some specific
// userActiveModeTriggerHint values.
BitMask<app::Clusters::IcdManagement::UserActiveModeTriggerBitmap> userActiveModeTriggerHint;
CharSpan userActiveModeTriggerInstruction;
};
struct ReadCommissioningInfo
{
NetworkClusters network;
BasicClusterInfo basic;
GeneralCommissioningInfo general;
bool requiresUTC = false;
bool requiresTimeZone = false;
bool requiresDefaultNTP = false;
bool requiresTrustedTimeSource = false;
uint8_t maxTimeZoneSize = 1;
uint8_t maxDSTSize = 1;
NodeId remoteNodeId = kUndefinedNodeId;
bool supportsConcurrentConnection = true;
ICDManagementClusterInfo icd;
};
struct TimeZoneResponseInfo
{
bool requiresDSTOffsets;
};
struct AttestationErrorInfo
{
AttestationErrorInfo(Credentials::AttestationVerificationResult result) : attestationResult(result) {}
Credentials::AttestationVerificationResult attestationResult;
};
struct CommissioningErrorInfo
{
CommissioningErrorInfo(app::Clusters::GeneralCommissioning::CommissioningErrorEnum result) : commissioningError(result) {}
app::Clusters::GeneralCommissioning::CommissioningErrorEnum commissioningError;
};
struct NetworkCommissioningStatusInfo
{
NetworkCommissioningStatusInfo(app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum result) :
networkCommissioningStatus(result)
{}
app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum networkCommissioningStatus;
};
class CommissioningDelegate
{
public:
virtual ~CommissioningDelegate(){};
/* CommissioningReport is returned after each commissioning step is completed. The reports for each step are:
* kReadCommissioningInfo: Reported together with ReadCommissioningInfo2
* kReadCommissioningInfo2: ReadCommissioningInfo
* kArmFailsafe: CommissioningErrorInfo if there is an error
* kConfigRegulatory: CommissioningErrorInfo if there is an error
* kConfigureUTCTime: None
* kConfigureTimeZone: TimeZoneResponseInfo
* kConfigureDSTOffset: None
* kConfigureDefaultNTP: None
* kSendPAICertificateRequest: RequestedCertificate
* kSendDACCertificateRequest: RequestedCertificate
* kSendAttestationRequest: AttestationResponse
* kAttestationVerification: AttestationErrorInfo if there is an error
* kAttestationRevocationCheck: AttestationErrorInfo if there is an error
* kSendOpCertSigningRequest: CSRResponse
* kGenerateNOCChain: NocChain
* kSendTrustedRootCert: None
* kSendNOC: None
* kConfigureTrustedTimeSource: None
* kWiFiNetworkSetup: NetworkCommissioningStatusInfo if there is an error
* kThreadNetworkSetup: NetworkCommissioningStatusInfo if there is an error
* kWiFiNetworkEnable: NetworkCommissioningStatusInfo if there is an error
* kThreadNetworkEnable: NetworkCommissioningStatusInfo if there is an error
* kEvictPreviousCaseSessions: None
* kFindOperationalForStayActive OperationalNodeFoundData
* kFindOperationalForCommissioningComplete: OperationalNodeFoundData
* kICDSendStayActive: CommissioningErrorInfo if there is an error
* kSendComplete: CommissioningErrorInfo if there is an error
* kCleanup: None
*/
struct CommissioningReport
: Variant<RequestedCertificate, AttestationResponse, CSRResponse, NocChain, OperationalNodeFoundData, ReadCommissioningInfo,
AttestationErrorInfo, CommissioningErrorInfo, NetworkCommissioningStatusInfo, TimeZoneResponseInfo>
{
CommissioningReport() : stageCompleted(CommissioningStage::kError) {}
CommissioningStage stageCompleted;
};
virtual CHIP_ERROR SetCommissioningParameters(const CommissioningParameters & params) = 0;
virtual const CommissioningParameters & GetCommissioningParameters() const = 0;
virtual void SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate) = 0;
virtual CHIP_ERROR StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy) = 0;
virtual CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err, CommissioningReport report) = 0;
};
} // namespace Controller
} // namespace chip