Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2024 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #pragma once
20 : #include <app-common/zap-generated/cluster-objects.h>
21 : #include <app/AttributePathParams.h>
22 : #include <app/ClusterStateCache.h>
23 : #include <app/OperationalSessionSetup.h>
24 : #include <controller/CommissioneeDeviceProxy.h>
25 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
26 : #include <controller/jcm/TrustVerification.h> // nogncheck
27 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
28 : #include <credentials/attestation_verifier/DeviceAttestationDelegate.h>
29 : #include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
30 : #include <crypto/CHIPCryptoPAL.h>
31 : #include <lib/support/Span.h>
32 : #include <lib/support/Variant.h>
33 : #include <matter/tracing/build_config.h>
34 : #include <system/SystemClock.h>
35 :
36 : namespace chip {
37 : namespace Controller {
38 :
39 : class DeviceCommissioner;
40 :
41 : enum CommissioningStage : uint8_t
42 : {
43 : kError,
44 : kSecurePairing, ///< Establish a PASE session with the device
45 : kReadCommissioningInfo, ///< Query Attributes relevant to commissioning (can perform multiple read interactions)
46 : kArmFailsafe, ///< Send ArmFailSafe (0x30:0) command to the device
47 : kConfigRegulatory, ///< Send SetRegulatoryConfig (0x30:2) command to the device
48 : kConfigureUTCTime, ///< SetUTCTime if the DUT has a time cluster
49 : kConfigureTimeZone, ///< Configure a time zone if one is required and available
50 : kConfigureDSTOffset, ///< Configure DST offset if one is required and available
51 : kConfigureDefaultNTP, ///< Configure a default NTP server if one is required and available
52 : kSendPAICertificateRequest, ///< Send PAI CertificateChainRequest (0x3E:2) command to the device
53 : kSendDACCertificateRequest, ///< Send DAC CertificateChainRequest (0x3E:2) command to the device
54 : kSendAttestationRequest, ///< Send AttestationRequest (0x3E:0) command to the device
55 : kAttestationVerification, ///< Verify AttestationResponse (0x3E:1) validity
56 : kAttestationRevocationCheck, ///< Verify Revocation Status of device's DAC chain
57 : kJCMTrustVerification, ///< Perform JCM trust verification steps
58 : kSendOpCertSigningRequest, ///< Send CSRRequest (0x3E:4) command to the device
59 : kValidateCSR, ///< Verify CSRResponse (0x3E:5) validity
60 : kGenerateNOCChain, ///< TLV encode Node Operational Credentials (NOC) chain certs
61 : kSendTrustedRootCert, ///< Send AddTrustedRootCertificate (0x3E:11) command to the device
62 : kSendNOC, ///< Send AddNOC (0x3E:6) command to the device
63 : kConfigureTrustedTimeSource, ///< Configure a trusted time source if one is required and available (must be done after SendNOC)
64 : kICDGetRegistrationInfo, ///< Waiting for the higher layer to provide ICD registration informations.
65 : kICDRegistration, ///< Register for ICD management
66 : kWiFiNetworkSetup, ///< Send AddOrUpdateWiFiNetwork (0x31:2) command to the device
67 : kThreadNetworkSetup, ///< Send AddOrUpdateThreadNetwork (0x31:3) command to the device
68 : kFailsafeBeforeWiFiEnable, ///< Extend the fail-safe before doing kWiFiNetworkEnable
69 : kFailsafeBeforeThreadEnable, ///< Extend the fail-safe before doing kThreadNetworkEnable
70 : kWiFiNetworkEnable, ///< Send ConnectNetwork (0x31:6) command to the device for the WiFi network
71 : kThreadNetworkEnable, ///< Send ConnectNetwork (0x31:6) command to the device for the Thread network
72 : kEvictPreviousCaseSessions, ///< Evict previous stale case sessions from a commissioned device with this node ID before
73 : kFindOperationalForStayActive, ///< Perform operational discovery and establish a CASE session with the device for ICD
74 : ///< StayActive command
75 : kFindOperationalForCommissioningComplete, ///< Perform operational discovery and establish a CASE session with the device for
76 : ///< Commissioning Complete command
77 : kSendComplete, ///< Send CommissioningComplete (0x30:4) command to the device
78 : kICDSendStayActive, ///< Send Keep Alive to ICD
79 : /// Send ScanNetworks (0x31:0) command to the device.
80 : /// ScanNetworks can happen anytime after kArmFailsafe.
81 : kScanNetworks,
82 : /// Waiting for the higher layer to provide network credentials before continuing the workflow.
83 : /// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with
84 : /// network credentials to use in kWiFiNetworkSetup or kThreadNetworkSetup steps.
85 : kNeedsNetworkCreds,
86 : kPrimaryOperationalNetworkFailed, ///< Indicate that the primary operational network (on root endpoint) failed, should remove
87 : ///< the primary network config later.
88 : kRemoveWiFiNetworkConfig, ///< Remove Wi-Fi network config.
89 : kRemoveThreadNetworkConfig, ///< Remove Thread network config.
90 : kConfigureTCAcknowledgments, ///< Send SetTCAcknowledgements (0x30:6) command to the device
91 : kCleanup, ///< Call delegates with status, free memory, clear timers and state/
92 : };
93 :
94 : enum class ICDRegistrationStrategy : uint8_t
95 : {
96 : kIgnore, ///< Do not check whether the device is an ICD during commissioning
97 : kBeforeComplete, ///< Do commissioner self-registration or external controller registration,
98 : ///< Controller should provide a ICDKey manager for generating symmetric key
99 : };
100 :
101 : const char * StageToString(CommissioningStage stage);
102 :
103 : #if MATTER_TRACING_ENABLED
104 : const char * MetricKeyForCommissioningStage(CommissioningStage stage);
105 : #endif
106 :
107 : struct WiFiCredentials
108 : {
109 : ByteSpan ssid;
110 : ByteSpan credentials;
111 1 : WiFiCredentials(ByteSpan newSsid, ByteSpan newCreds) : ssid(newSsid), credentials(newCreds) {}
112 : };
113 :
114 : struct TermsAndConditionsAcknowledgement
115 : {
116 : uint16_t acceptedTermsAndConditions;
117 : uint16_t acceptedTermsAndConditionsVersion;
118 : };
119 :
120 : struct NOCChainGenerationParameters
121 : {
122 : ByteSpan nocsrElements;
123 : ByteSpan signature;
124 : };
125 :
126 : struct CompletionStatus
127 : {
128 45 : CompletionStatus() : err(CHIP_NO_ERROR), failedStage(NullOptional), attestationResult(NullOptional) {}
129 : CHIP_ERROR err;
130 : Optional<CommissioningStage> failedStage;
131 : Optional<Credentials::AttestationVerificationResult> attestationResult;
132 : Optional<app::Clusters::GeneralCommissioning::CommissioningErrorEnum> commissioningError;
133 : Optional<app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum> networkCommissioningStatus;
134 : };
135 :
136 : inline constexpr uint16_t kDefaultFailsafeTimeout = 60;
137 :
138 : // Per spec, all commands that are sent with the failsafe armed need at least
139 : // a 30s timeout.
140 : inline constexpr System::Clock::Timeout kMinimumCommissioningStepTimeout = System::Clock::Seconds16(30);
141 :
142 : class CommissioningParameters
143 : {
144 : public:
145 : static constexpr size_t kMaxThreadDatasetLen = 254;
146 : static constexpr size_t kMaxSsidLen = 32;
147 : static constexpr size_t kMaxCredentialsLen = 64;
148 : static constexpr size_t kMaxCountryCodeLen = 2;
149 :
150 : // Value to use when setting the commissioning failsafe timer on the node being commissioned.
151 : // If the failsafe timer value is passed in as part of the commissioning parameters, that value will be used. If not supplied,
152 : // the AutoCommissioner will set this to the recommended value read from the node. If that is not set, it will fall back to the
153 : // default kDefaultFailsafeTimeout.
154 : // This value should be set before running PerformCommissioningStep for the kArmFailsafe step.
155 0 : const Optional<uint16_t> GetFailsafeTimerSeconds() const { return mFailsafeTimerSeconds; }
156 :
157 : // Value to use when re-setting the commissioning failsafe timer immediately prior to operational discovery.
158 : // If a CASE failsafe timer value is passed in as part of the commissioning parameters, then the failsafe timer
159 : // will be reset using this value before operational discovery begins. If not supplied, then the AutoCommissioner
160 : // will not automatically reset the failsafe timer before operational discovery begins. It can be useful for the
161 : // commissioner to set the CASE failsafe timer to a small value (ex. 30s) when the regular failsafe timer is set
162 : // to a larger value to accommodate user interaction during setup (network credential selection, user consent
163 : // after device attestation).
164 2 : const Optional<uint16_t> GetCASEFailsafeTimerSeconds() const { return mCASEFailsafeTimerSeconds; }
165 :
166 : // The location (indoor/outdoor) of the node being commissioned.
167 : // The node regulartory location (indoor/outdoor) should be set by the commissioner explicitly as it may be different than the
168 : // location of the commissioner. This location will be set on the node if the node supports configurable regulatory location
169 : // (from GetLocationCapability - see below). If the regulatory location is not supplied, this will fall back to the location in
170 : // GetDefaultRegulatoryLocation and then to Outdoor (most restrictive).
171 : // This value should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
172 0 : const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetDeviceRegulatoryLocation() const
173 : {
174 0 : return mDeviceRegulatoryLocation;
175 : }
176 :
177 : // Value to determine whether the node supports Concurrent Connections as read from the GeneralCommissioning cluster.
178 : // In the AutoCommissioner, this is automatically set from from the kReadCommissioningInfo stage.
179 0 : Optional<bool> GetSupportsConcurrentConnection() const { return mSupportsConcurrentConnection; }
180 :
181 : // The country code to be used for the node, if set.
182 23 : Optional<CharSpan> GetCountryCode() const { return mCountryCode; }
183 :
184 0 : Optional<TermsAndConditionsAcknowledgement> GetTermsAndConditionsAcknowledgement() const
185 : {
186 0 : return mTermsAndConditionsAcknowledgement;
187 : }
188 :
189 : // Time zone to set for the node
190 : // If required, this will be truncated to fit the max size allowable on the node
191 30 : Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>> GetTimeZone() const
192 : {
193 30 : return mTimeZone;
194 : }
195 :
196 : // DST offset list. If required, this will be truncated to fit the max size allowable on the node
197 : // DST list will only be sent if the commissionee requires DST offsets, as indicated in the SetTimeZone response
198 26 : Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>> GetDSTOffsets() const
199 : {
200 26 : return mDSTOffsets;
201 : }
202 :
203 : // Default NTP to set on the node if supported and required
204 : // Default implementation will not overide a value already set on the commissionee
205 : // TODO: Add a force option?
206 25 : Optional<app::DataModel::Nullable<CharSpan>> GetDefaultNTP() const { return mDefaultNTP; }
207 :
208 : // Trusted time source
209 : // Default implementation will not override a value already set on the commissionee
210 : // TODO: Add a force option?
211 : Optional<app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>>
212 0 : GetTrustedTimeSource() const
213 : {
214 0 : return mTrustedTimeSource;
215 : }
216 :
217 : // Nonce sent to the node to use during the CSR request.
218 : // When using the AutoCommissioner, this value will be ignored in favour of the value supplied by the
219 : // OperationalCredentialsDelegate ObtainCsrNonce function. If the credential delegate is not supplied, the value supplied here
220 : // will be used. If neither is supplied random value will be used as a fallback.
221 : // This value must be set before calling PerformCommissioningStep for the kSendOpCertSigningRequest step.
222 21 : const Optional<ByteSpan> GetCSRNonce() const { return mCSRNonce; }
223 :
224 : // Nonce value sent to the node to use during the attestation request.
225 : // When using the AutoCommissioner, this value will fall back to random if not supplied.
226 : // If a non-random value is to be used, the value must be set before calling PerformCommissioningStep for the
227 : // kSendAttestationRequest step.
228 22 : const Optional<ByteSpan> GetAttestationNonce() const { return mAttestationNonce; }
229 :
230 : // WiFi SSID and credentials to use when adding/updating and enabling WiFi on the node.
231 : // This value must be set before calling PerformCommissioningStep for the kWiFiNetworkSetup or kWiFiNetworkEnable steps.
232 24 : const Optional<WiFiCredentials> GetWiFiCredentials() const { return mWiFiCreds; }
233 :
234 : // Thread operational dataset to use when adding/updating and enabling the thread network on the node.
235 : // This value must be set before calling PerformCommissioningStep for the kThreadNetworkSetup or kThreadNetworkEnable steps.
236 25 : const Optional<ByteSpan> GetThreadOperationalDataset() const { return mThreadOperationalDataset; }
237 :
238 : // The NOCSR parameters (elements and signature) returned from the node. In the AutoCommissioner, this is set using the data
239 : // returned from the kSendOpCertSigningRequest stage.
240 : // This value must be set before calling PerformCommissioningStep for the kGenerateNOCChain step.
241 0 : const Optional<NOCChainGenerationParameters> GetNOCChainGenerationParameters() const { return mNOCChainGenerationParameters; }
242 :
243 : // The root certificate for the operational certificate chain. In the auto commissioner, this is set by by the kGenerateNOCChain
244 : // stage through the OperationalCredentialsDelegate.
245 : // This value must be set before calling PerformCommissioningStep for the kSendTrustedRootCert step.
246 0 : const Optional<ByteSpan> GetRootCert() const { return mRootCert; }
247 :
248 : // The node operational certificate for the node being commissioned. In the AutoCommissioner, this is set by by the
249 : // kGenerateNOCChain stage through the OperationalCredentialsDelegate.
250 : // This value must be set before calling PerformCommissioningStep for the kSendNOC step.
251 : // This value must also be set before calling PerformCommissioningStep for the kSendTrustedRootCert step, as it is used to set
252 : // the node id in the DeviceProxy.
253 0 : const Optional<ByteSpan> GetNoc() const { return mNoc; }
254 :
255 : // The intermediate certificate for the node being commissioned. In the AutoCommissioner, this is set by by the
256 : // kGenerateNOCChain stage through the OperationalCredentialsDelegate.
257 : // This value should be set before calling PerformCommissioningStep for the kSendNOC step.
258 0 : const Optional<ByteSpan> GetIcac() const { return mIcac; }
259 :
260 : // Epoch key for the identity protection key for the node being commissioned. In the AutoCommissioner, this is set by by the
261 : // kGenerateNOCChain stage through the OperationalCredentialsDelegate.
262 : // This value must be set before calling PerformCommissioningStep for the kSendNOC step.
263 0 : const Optional<Crypto::IdentityProtectionKeySpan> GetIpk() const
264 : {
265 0 : return mIpk.HasValue() ? MakeOptional(mIpk.Value().Span()) : NullOptional;
266 : }
267 :
268 : // Admin subject id used for the case access control entry created if the AddNOC command succeeds. In the AutoCommissioner, this
269 : // is set by by the kGenerateNOCChain stage through the OperationalCredentialsDelegate.
270 : // This must be set before calling PerformCommissioningStep for the kSendNOC step.
271 0 : const Optional<NodeId> GetAdminSubject() const { return mAdminSubject; }
272 :
273 : // Attestation elements from the node. These are obtained from node in response to the AttestationRequest command. In the
274 : // AutoCommissioner, this is automatically set from the report from the kSendAttestationRequest stage.
275 : // This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
276 0 : const Optional<ByteSpan> GetAttestationElements() const { return mAttestationElements; }
277 :
278 : // Attestation signature from the node. This is obtained from node in response to the AttestationRequest command. In the
279 : // AutoCommissioner, this is automatically set from the report from the kSendAttestationRequest stage.
280 : // This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
281 0 : const Optional<ByteSpan> GetAttestationSignature() const { return mAttestationSignature; }
282 :
283 : // Product attestation intermediate certificate from the node. This is obtained from the node in response to the
284 : // CertificateChainRequest command for the PAI. In the AutoCommissioner, this is automatically set from the report from the
285 : // kSendPAICertificateRequest stage.
286 : // This must be set before calling PerformCommissioningStep for the kAttestationVerificationstep.
287 0 : const Optional<ByteSpan> GetPAI() const { return mPAI; }
288 :
289 : // Device attestation certificate from the node. This is obtained from the node in response to the CertificateChainRequest
290 : // command for the DAC. In the AutoCommissioner, this is automatically set from the report from the kSendDACCertificateRequest
291 : // stage.
292 : // This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
293 0 : const Optional<ByteSpan> GetDAC() const { return mDAC; }
294 :
295 : // Node ID when a matching fabric is found in the Node Operational Credentials cluster.
296 : // In the AutoCommissioner, this is set from kReadCommissioningInfo stage.
297 : const Optional<NodeId> GetRemoteNodeId() const { return mRemoteNodeId; }
298 :
299 : // Node vendor ID from the basic information cluster. In the AutoCommissioner, this is automatically set from report from the
300 : // kReadCommissioningInfo stage.
301 : // This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
302 0 : const Optional<VendorId> GetRemoteVendorId() const { return mRemoteVendorId; }
303 :
304 : // Node product ID from the basic information cluster. In the AutoCommissioner, this is automatically set from report from the
305 : // kReadCommissioningInfo stage.
306 : // This must be set before calling PerformCommissioningStep for the kAttestationVerification step.
307 0 : const Optional<uint16_t> GetRemoteProductId() const { return mRemoteProductId; }
308 :
309 : // Default regulatory location set by the node, as read from the GeneralCommissioning cluster. In the AutoCommissioner, this is
310 : // automatically set from report from the kReadCommissioningInfo stage.
311 : // This should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
312 0 : const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetDefaultRegulatoryLocation() const
313 : {
314 0 : return mDefaultRegulatoryLocation;
315 : }
316 :
317 : // Location capabilities of the node, as read from the GeneralCommissioning cluster. In the AutoCommissioner, this is
318 : // automatically set from report from the kReadCommissioningInfo stage.
319 : // This should be set before calling PerformCommissioningStep for the kConfigRegulatory step.
320 0 : const Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> GetLocationCapability() const
321 : {
322 0 : return mLocationCapability;
323 : }
324 :
325 : // Status to send when calling CommissioningComplete on the PairingDelegate during the kCleanup step. The AutoCommissioner uses
326 : // this to pass through any error messages received during commissioning.
327 0 : const CompletionStatus & GetCompletionStatus() const { return completionStatus; }
328 :
329 0 : CommissioningParameters & SetFailsafeTimerSeconds(uint16_t seconds)
330 : {
331 0 : mFailsafeTimerSeconds.SetValue(seconds);
332 0 : return *this;
333 : }
334 :
335 : CommissioningParameters & SetCASEFailsafeTimerSeconds(uint16_t seconds)
336 : {
337 : mCASEFailsafeTimerSeconds.SetValue(seconds);
338 : return *this;
339 : }
340 :
341 : CommissioningParameters & SetDeviceRegulatoryLocation(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum location)
342 : {
343 : mDeviceRegulatoryLocation.SetValue(location);
344 : return *this;
345 : }
346 :
347 0 : CommissioningParameters & SetSupportsConcurrentConnection(bool concurrentConnection)
348 : {
349 0 : mSupportsConcurrentConnection.SetValue(concurrentConnection);
350 0 : return *this;
351 : }
352 :
353 : // The lifetime of the buffer countryCode is pointing to should exceed the
354 : // lifetime of CommissioningParameters object.
355 1 : CommissioningParameters & SetCountryCode(CharSpan countryCode)
356 : {
357 1 : mCountryCode.SetValue(countryCode);
358 1 : return *this;
359 : }
360 :
361 : CommissioningParameters &
362 : SetTermsAndConditionsAcknowledgement(TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement)
363 : {
364 : mTermsAndConditionsAcknowledgement.SetValue(termsAndConditionsAcknowledgement);
365 : return *this;
366 : }
367 :
368 : // The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object.
369 : CommissioningParameters &
370 2 : SetTimeZone(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> timeZone)
371 : {
372 2 : mTimeZone.SetValue(timeZone);
373 2 : return *this;
374 : }
375 :
376 : // The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object.
377 : CommissioningParameters &
378 2 : SetDSTOffsets(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type> dstOffsets)
379 : {
380 2 : mDSTOffsets.SetValue(dstOffsets);
381 2 : return *this;
382 : }
383 :
384 : // The lifetime of the char span needs to exceed the lifetime of the CommissioningParameters
385 2 : CommissioningParameters & SetDefaultNTP(app::DataModel::Nullable<CharSpan> defaultNTP)
386 : {
387 2 : mDefaultNTP.SetValue(defaultNTP);
388 2 : return *this;
389 : }
390 :
391 : CommissioningParameters & SetTrustedTimeSource(
392 : app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>
393 : trustedTimeSource)
394 : {
395 : mTrustedTimeSource.SetValue(trustedTimeSource);
396 : return *this;
397 : }
398 :
399 : // The lifetime of the buffer csrNonce is pointing to, should exceed the lifetime of CommissioningParameters object.
400 20 : CommissioningParameters & SetCSRNonce(ByteSpan csrNonce)
401 : {
402 20 : mCSRNonce.SetValue(csrNonce);
403 20 : return *this;
404 : }
405 :
406 : // The lifetime of the buffer attestationNonce is pointing to, should exceed the lifetime of CommissioningParameters object.
407 21 : CommissioningParameters & SetAttestationNonce(ByteSpan attestationNonce)
408 : {
409 21 : mAttestationNonce.SetValue(attestationNonce);
410 21 : return *this;
411 : }
412 :
413 : // If a WiFiCredentials is provided, then the WiFiNetworkScan will not be attempted
414 1 : CommissioningParameters & SetWiFiCredentials(WiFiCredentials wifiCreds)
415 : {
416 1 : mWiFiCreds.SetValue(wifiCreds);
417 1 : mAttemptWiFiNetworkScan.SetValue(false);
418 1 : return *this;
419 : }
420 :
421 : // If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
422 1 : CommissioningParameters & SetThreadOperationalDataset(ByteSpan threadOperationalDataset)
423 : {
424 :
425 1 : mThreadOperationalDataset.SetValue(threadOperationalDataset);
426 1 : mAttemptThreadNetworkScan = MakeOptional(static_cast<bool>(false));
427 1 : return *this;
428 : }
429 : // This parameter should be set with the information returned from kSendOpCertSigningRequest. It must be set before calling
430 : // kGenerateNOCChain.
431 0 : CommissioningParameters & SetNOCChainGenerationParameters(const NOCChainGenerationParameters & params)
432 : {
433 0 : mNOCChainGenerationParameters.SetValue(params);
434 0 : return *this;
435 : }
436 : // Root certs can be generated from the kGenerateNOCChain step. This must be set before calling kSendTrustedRootCert.
437 0 : CommissioningParameters & SetRootCert(const ByteSpan & rcac)
438 : {
439 0 : mRootCert.SetValue(rcac);
440 0 : return *this;
441 : }
442 : // NOC and intermediate cert can be generated from the kGenerateNOCChain step. NOC must be set before calling
443 : // kSendTrustedRootCert. ICAC and NOC must be set before calling kSendNOC
444 0 : CommissioningParameters & SetNoc(const ByteSpan & noc)
445 : {
446 0 : mNoc.SetValue(noc);
447 0 : return *this;
448 : }
449 0 : CommissioningParameters & SetIcac(const ByteSpan & icac)
450 : {
451 0 : mIcac.SetValue(icac);
452 0 : return *this;
453 : }
454 0 : CommissioningParameters & SetIpk(const Crypto::IdentityProtectionKeySpan ipk)
455 : {
456 0 : mIpk.SetValue(Crypto::IdentityProtectionKey(ipk));
457 0 : return *this;
458 : }
459 0 : CommissioningParameters & SetAdminSubject(const NodeId adminSubject)
460 : {
461 0 : mAdminSubject.SetValue(adminSubject);
462 0 : return *this;
463 : }
464 0 : CommissioningParameters & SetAttestationElements(const ByteSpan & attestationElements)
465 : {
466 0 : mAttestationElements = MakeOptional(attestationElements);
467 0 : return *this;
468 : }
469 0 : CommissioningParameters & SetAttestationSignature(const ByteSpan & attestationSignature)
470 : {
471 0 : mAttestationSignature = MakeOptional(attestationSignature);
472 0 : return *this;
473 : }
474 0 : CommissioningParameters & SetPAI(const ByteSpan & pai)
475 : {
476 0 : mPAI = MakeOptional(pai);
477 0 : return *this;
478 : }
479 0 : CommissioningParameters & SetDAC(const ByteSpan & dac)
480 : {
481 0 : mDAC = MakeOptional(dac);
482 0 : return *this;
483 : }
484 0 : CommissioningParameters & SetRemoteNodeId(NodeId id)
485 : {
486 0 : mRemoteNodeId = MakeOptional(id);
487 0 : return *this;
488 : }
489 0 : CommissioningParameters & SetRemoteVendorId(VendorId id)
490 : {
491 0 : mRemoteVendorId = MakeOptional(id);
492 0 : return *this;
493 : }
494 0 : CommissioningParameters & SetRemoteProductId(uint16_t id)
495 : {
496 0 : mRemoteProductId = MakeOptional(id);
497 0 : return *this;
498 : }
499 0 : CommissioningParameters & SetDefaultRegulatoryLocation(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum location)
500 : {
501 0 : mDefaultRegulatoryLocation = MakeOptional(location);
502 0 : return *this;
503 : }
504 0 : CommissioningParameters & SetLocationCapability(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum capability)
505 : {
506 0 : mLocationCapability = MakeOptional(capability);
507 0 : return *this;
508 : }
509 0 : void SetCompletionStatus(const CompletionStatus & status) { completionStatus = status; }
510 :
511 : CommissioningParameters & SetDeviceAttestationDelegate(Credentials::DeviceAttestationDelegate * deviceAttestationDelegate)
512 : {
513 : mDeviceAttestationDelegate = deviceAttestationDelegate;
514 : return *this;
515 : }
516 :
517 0 : Credentials::DeviceAttestationDelegate * GetDeviceAttestationDelegate() const { return mDeviceAttestationDelegate; }
518 :
519 : // If an SSID is provided, and AttemptWiFiNetworkScan is true,
520 : // then a directed scan will be performed using the SSID provided in the WiFiCredentials object
521 0 : Optional<bool> GetAttemptWiFiNetworkScan() const { return mAttemptWiFiNetworkScan; }
522 : CommissioningParameters & SetAttemptWiFiNetworkScan(bool attemptWiFiNetworkScan)
523 : {
524 : mAttemptWiFiNetworkScan = MakeOptional(attemptWiFiNetworkScan);
525 : return *this;
526 : }
527 :
528 : // If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
529 0 : Optional<bool> GetAttemptThreadNetworkScan() const { return mAttemptThreadNetworkScan; }
530 : CommissioningParameters & SetAttemptThreadNetworkScan(bool attemptThreadNetworkScan)
531 : {
532 : if (!mThreadOperationalDataset.HasValue())
533 : {
534 : mAttemptThreadNetworkScan = MakeOptional(attemptThreadNetworkScan);
535 : }
536 : return *this;
537 : }
538 :
539 : // Only perform the PASE steps of commissioning.
540 : // Commissioning will be completed by another admin on the network.
541 2 : Optional<bool> GetSkipCommissioningComplete() const { return mSkipCommissioningComplete; }
542 : CommissioningParameters & SetSkipCommissioningComplete(bool skipCommissioningComplete)
543 : {
544 : mSkipCommissioningComplete = MakeOptional(skipCommissioningComplete);
545 : return *this;
546 : }
547 :
548 : // Check for matching fabric on target device by reading fabric list and looking for a
549 : // fabricId and RootCert match. If a match is detected, then use GetNodeId() to
550 : // access the nodeId for the device on the matching fabric.
551 0 : bool GetCheckForMatchingFabric() const { return mCheckForMatchingFabric; }
552 : CommissioningParameters & SetCheckForMatchingFabric(bool checkForMatchingFabric)
553 : {
554 : mCheckForMatchingFabric = checkForMatchingFabric;
555 : return *this;
556 : }
557 :
558 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
559 : // Check for Joint Commissioning Method
560 : Optional<bool> GetUseJCM() const { return mUseJCM; }
561 :
562 : // Set the Joint Commissioning Method
563 : CommissioningParameters & SetUseJCM(bool useJCM)
564 : {
565 : mUseJCM = MakeOptional(useJCM);
566 : return *this;
567 : }
568 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
569 :
570 20 : ICDRegistrationStrategy GetICDRegistrationStrategy() const { return mICDRegistrationStrategy; }
571 1 : CommissioningParameters & SetICDRegistrationStrategy(ICDRegistrationStrategy icdRegistrationStrategy)
572 : {
573 1 : mICDRegistrationStrategy = icdRegistrationStrategy;
574 1 : return *this;
575 : }
576 :
577 4 : Optional<NodeId> GetICDCheckInNodeId() const { return mICDCheckInNodeId; }
578 2 : CommissioningParameters & SetICDCheckInNodeId(NodeId icdCheckInNodeId)
579 : {
580 2 : mICDCheckInNodeId = MakeOptional(icdCheckInNodeId);
581 2 : return *this;
582 : }
583 :
584 4 : Optional<uint64_t> GetICDMonitoredSubject() const { return mICDMonitoredSubject; }
585 2 : CommissioningParameters & SetICDMonitoredSubject(uint64_t icdMonitoredSubject)
586 : {
587 2 : mICDMonitoredSubject = MakeOptional(icdMonitoredSubject);
588 2 : return *this;
589 : }
590 :
591 9 : Optional<ByteSpan> GetICDSymmetricKey() const { return mICDSymmetricKey; }
592 2 : CommissioningParameters & SetICDSymmetricKey(ByteSpan icdSymmetricKey)
593 : {
594 2 : mICDSymmetricKey = MakeOptional(icdSymmetricKey);
595 2 : return *this;
596 : }
597 :
598 4 : Optional<app::Clusters::IcdManagement::ClientTypeEnum> GetICDClientType() const { return mICDClientType; }
599 2 : CommissioningParameters & SetICDClientType(app::Clusters::IcdManagement::ClientTypeEnum icdClientType)
600 : {
601 2 : mICDClientType = MakeOptional(icdClientType);
602 2 : return *this;
603 : }
604 :
605 0 : Optional<uint32_t> GetICDStayActiveDurationMsec() const { return mICDStayActiveDurationMsec; }
606 : CommissioningParameters & SetICDStayActiveDurationMsec(uint32_t stayActiveDurationMsec)
607 : {
608 : mICDStayActiveDurationMsec = MakeOptional(stayActiveDurationMsec);
609 : return *this;
610 : }
611 0 : void ClearICDStayActiveDurationMsec() { mICDStayActiveDurationMsec.ClearValue(); }
612 :
613 20 : Span<const app::AttributePathParams> GetExtraReadPaths() const { return mExtraReadPaths; }
614 :
615 : // Additional attribute paths to read as part of the kReadCommissioningInfo stage.
616 : // These values read from the device will be available in ReadCommissioningInfo.attributes.
617 : // Clients should avoid requesting paths that are already read internally by the commissioner
618 : // as no consolidation of internally read and extra paths provided here will be performed.
619 1 : CommissioningParameters & SetExtraReadPaths(Span<const app::AttributePathParams> paths)
620 : {
621 1 : mExtraReadPaths = paths;
622 1 : return *this;
623 : }
624 :
625 : // Clear all members that depend on some sort of external buffer. Can be
626 : // used to make sure that we are not holding any dangling pointers.
627 24 : void ClearExternalBufferDependentValues()
628 : {
629 24 : mCSRNonce.ClearValue();
630 24 : mAttestationNonce.ClearValue();
631 24 : mWiFiCreds.ClearValue();
632 24 : mCountryCode.ClearValue();
633 24 : mThreadOperationalDataset.ClearValue();
634 24 : mNOCChainGenerationParameters.ClearValue();
635 24 : mRootCert.ClearValue();
636 24 : mNoc.ClearValue();
637 24 : mIcac.ClearValue();
638 24 : mIpk.ClearValue();
639 24 : mAttestationElements.ClearValue();
640 24 : mAttestationSignature.ClearValue();
641 24 : mPAI.ClearValue();
642 24 : mDAC.ClearValue();
643 24 : mTimeZone.ClearValue();
644 24 : mDSTOffsets.ClearValue();
645 24 : mDefaultNTP.ClearValue();
646 24 : mICDSymmetricKey.ClearValue();
647 24 : mExtraReadPaths = decltype(mExtraReadPaths)();
648 24 : }
649 :
650 : private:
651 : // Items that can be set by the commissioner
652 : Optional<uint16_t> mFailsafeTimerSeconds;
653 : Optional<uint16_t> mCASEFailsafeTimerSeconds;
654 : Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mDeviceRegulatoryLocation;
655 : Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>> mTimeZone;
656 : Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>> mDSTOffsets;
657 : Optional<app::DataModel::Nullable<CharSpan>> mDefaultNTP;
658 : Optional<app::DataModel::Nullable<app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type>>
659 : mTrustedTimeSource;
660 : Optional<ByteSpan> mCSRNonce;
661 : Optional<ByteSpan> mAttestationNonce;
662 : Optional<WiFiCredentials> mWiFiCreds;
663 : Optional<CharSpan> mCountryCode;
664 : Optional<TermsAndConditionsAcknowledgement> mTermsAndConditionsAcknowledgement;
665 : Optional<ByteSpan> mThreadOperationalDataset;
666 : Optional<NOCChainGenerationParameters> mNOCChainGenerationParameters;
667 : Optional<ByteSpan> mRootCert;
668 : Optional<ByteSpan> mNoc;
669 : Optional<ByteSpan> mIcac;
670 : Optional<Crypto::IdentityProtectionKey> mIpk;
671 : Optional<NodeId> mAdminSubject;
672 : // Items that come from the device in commissioning steps
673 : Optional<ByteSpan> mAttestationElements;
674 : Optional<ByteSpan> mAttestationSignature;
675 : Optional<ByteSpan> mPAI;
676 : Optional<ByteSpan> mDAC;
677 : Optional<NodeId> mRemoteNodeId;
678 : Optional<VendorId> mRemoteVendorId;
679 : Optional<uint16_t> mRemoteProductId;
680 : Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mDefaultRegulatoryLocation;
681 : Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum> mLocationCapability;
682 : Optional<bool> mSupportsConcurrentConnection;
683 : CompletionStatus completionStatus;
684 : Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate =
685 : nullptr; // Delegate to handle device attestation failures during commissioning
686 : Optional<bool> mAttemptWiFiNetworkScan;
687 : Optional<bool> mAttemptThreadNetworkScan; // This automatically gets set to false when a ThreadOperationalDataset is set
688 : Optional<bool> mSkipCommissioningComplete;
689 :
690 : Optional<NodeId> mICDCheckInNodeId;
691 : Optional<uint64_t> mICDMonitoredSubject;
692 : Optional<ByteSpan> mICDSymmetricKey;
693 : Optional<app::Clusters::IcdManagement::ClientTypeEnum> mICDClientType;
694 : Optional<uint32_t> mICDStayActiveDurationMsec;
695 : ICDRegistrationStrategy mICDRegistrationStrategy = ICDRegistrationStrategy::kIgnore;
696 : bool mCheckForMatchingFabric = false;
697 : Span<const app::AttributePathParams> mExtraReadPaths;
698 :
699 : Optional<bool> mUseJCM;
700 : };
701 :
702 : struct RequestedCertificate
703 : {
704 0 : RequestedCertificate(ByteSpan newCertificate) : certificate(newCertificate) {}
705 : ByteSpan certificate;
706 : };
707 :
708 : struct AttestationResponse
709 : {
710 0 : AttestationResponse(ByteSpan newAttestationElements, ByteSpan newSignature) :
711 0 : attestationElements(newAttestationElements), signature(newSignature)
712 0 : {}
713 : ByteSpan attestationElements;
714 : ByteSpan signature;
715 : };
716 :
717 : struct CSRResponse
718 : {
719 0 : CSRResponse(ByteSpan elements, ByteSpan newSignature) : nocsrElements(elements), signature(newSignature) {}
720 : ByteSpan nocsrElements;
721 : ByteSpan signature;
722 : };
723 :
724 : struct NocChain
725 : {
726 0 : NocChain(ByteSpan newNoc, ByteSpan newIcac, ByteSpan newRcac, Crypto::IdentityProtectionKeySpan newIpk,
727 0 : NodeId newAdminSubject) :
728 0 : noc(newNoc),
729 0 : icac(newIcac), rcac(newRcac), ipk(newIpk), adminSubject(newAdminSubject)
730 0 : {}
731 : ByteSpan noc;
732 : ByteSpan icac;
733 : ByteSpan rcac;
734 : Crypto::IdentityProtectionKeySpan ipk;
735 : NodeId adminSubject;
736 : };
737 :
738 : struct OperationalNodeFoundData
739 : {
740 0 : OperationalNodeFoundData(OperationalDeviceProxy proxy) : operationalProxy(proxy) {}
741 : OperationalDeviceProxy operationalProxy;
742 : };
743 :
744 : struct NetworkClusterInfo
745 : {
746 : EndpointId endpoint = kInvalidEndpointId;
747 : app::Clusters::NetworkCommissioning::Attributes::ConnectMaxTimeSeconds::TypeInfo::DecodableType minConnectionTime = 0;
748 : };
749 : struct NetworkClusters
750 : {
751 : NetworkClusterInfo wifi;
752 : NetworkClusterInfo thread;
753 : NetworkClusterInfo eth;
754 : };
755 : struct BasicClusterInfo
756 : {
757 : VendorId vendorId = VendorId::Common;
758 : uint16_t productId = 0;
759 : };
760 : struct GeneralCommissioningInfo
761 : {
762 : uint64_t breadcrumb = 0;
763 : uint16_t recommendedFailsafe = 0;
764 : app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum currentRegulatoryLocation =
765 : app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor;
766 : app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum locationCapability =
767 : app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor;
768 : ;
769 : };
770 :
771 : // ICDManagementClusterInfo is populated when the controller reads information from
772 : // the ICD Management cluster, and is used to communicate that information.
773 : struct ICDManagementClusterInfo
774 : {
775 : // Whether the ICD is capable of functioning as a LIT device. If false, the ICD can only be a SIT device.
776 : bool isLIT = false;
777 : // Whether the ICD supports the check-in protocol. LIT devices have to support it, but SIT devices
778 : // might or might not.
779 : bool checkInProtocolSupport = false;
780 : // Indicate the maximum interval in seconds the server can stay in idle mode.
781 : uint32_t idleModeDuration = 0;
782 : // Indicate the minimum interval in milliseconds the server typically will stay in active mode after initial transition out of
783 : // idle mode.
784 : uint32_t activeModeDuration = 0;
785 : // Indicate the minimum amount of time in milliseconds the server typically will stay active after network activity when in
786 : // active mode.
787 : uint16_t activeModeThreshold = 0;
788 : // userActiveModeTriggerHint indicates which user action(s) will trigger the ICD to switch to Active mode.
789 : // For a LIT: The device is required to provide a value for the bitmap.
790 : // For a SIT: The device may not provide a value. In that case, none of the bits will be set.
791 : //
792 : // userActiveModeTriggerInstruction may provide additional information for users for some specific
793 : // userActiveModeTriggerHint values.
794 : BitMask<app::Clusters::IcdManagement::UserActiveModeTriggerBitmap> userActiveModeTriggerHint;
795 : CharSpan userActiveModeTriggerInstruction;
796 : };
797 :
798 : struct ReadCommissioningInfo
799 : {
800 : #if CHIP_CONFIG_ENABLE_READ_CLIENT
801 : app::ClusterStateCache const * attributes = nullptr;
802 : #endif
803 : NetworkClusters network;
804 : BasicClusterInfo basic;
805 : GeneralCommissioningInfo general;
806 : bool requiresUTC = false;
807 : bool requiresTimeZone = false;
808 : bool requiresDefaultNTP = false;
809 : bool requiresTrustedTimeSource = false;
810 : uint8_t maxTimeZoneSize = 1;
811 : uint8_t maxDSTSize = 1;
812 : NodeId remoteNodeId = kUndefinedNodeId;
813 : bool supportsConcurrentConnection = true;
814 : ICDManagementClusterInfo icd;
815 : };
816 :
817 : struct TimeZoneResponseInfo
818 : {
819 : bool requiresDSTOffsets;
820 : };
821 :
822 : struct AttestationErrorInfo
823 : {
824 0 : AttestationErrorInfo(Credentials::AttestationVerificationResult result) : attestationResult(result) {}
825 : Credentials::AttestationVerificationResult attestationResult;
826 : };
827 :
828 : struct CommissioningErrorInfo
829 : {
830 0 : CommissioningErrorInfo(app::Clusters::GeneralCommissioning::CommissioningErrorEnum result) : commissioningError(result) {}
831 : app::Clusters::GeneralCommissioning::CommissioningErrorEnum commissioningError;
832 : };
833 :
834 : struct NetworkCommissioningStatusInfo
835 : {
836 0 : NetworkCommissioningStatusInfo(app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum result) :
837 0 : networkCommissioningStatus(result)
838 0 : {}
839 : app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum networkCommissioningStatus;
840 : };
841 :
842 : class CommissioningDelegate
843 : {
844 : public:
845 15 : virtual ~CommissioningDelegate(){};
846 : /* CommissioningReport is returned after each commissioning step is completed. The reports for each step are:
847 : * kReadCommissioningInfo: ReadCommissioningInfo
848 : * kArmFailsafe: CommissioningErrorInfo if there is an error
849 : * kConfigRegulatory: CommissioningErrorInfo if there is an error
850 : * kConfigureUTCTime: None
851 : * kConfigureTimeZone: TimeZoneResponseInfo
852 : * kConfigureDSTOffset: None
853 : * kConfigureDefaultNTP: None
854 : * kSendPAICertificateRequest: RequestedCertificate
855 : * kSendDACCertificateRequest: RequestedCertificate
856 : * kSendAttestationRequest: AttestationResponse
857 : * kAttestationVerification: AttestationErrorInfo if there is an error
858 : * kAttestationRevocationCheck: AttestationErrorInfo if there is an error
859 : * kJCMTrustVerification: JCMTrustVerificationError if there is an error
860 : * kSendOpCertSigningRequest: CSRResponse
861 : * kGenerateNOCChain: NocChain
862 : * kSendTrustedRootCert: None
863 : * kSendNOC: None
864 : * kConfigureTrustedTimeSource: None
865 : * kWiFiNetworkSetup: NetworkCommissioningStatusInfo if there is an error
866 : * kThreadNetworkSetup: NetworkCommissioningStatusInfo if there is an error
867 : * kWiFiNetworkEnable: NetworkCommissioningStatusInfo if there is an error
868 : * kThreadNetworkEnable: NetworkCommissioningStatusInfo if there is an error
869 : * kEvictPreviousCaseSessions: None
870 : * kFindOperationalForStayActive OperationalNodeFoundData
871 : * kFindOperationalForCommissioningComplete: OperationalNodeFoundData
872 : * kICDSendStayActive: CommissioningErrorInfo if there is an error
873 : * kSendComplete: CommissioningErrorInfo if there is an error
874 : * kCleanup: None
875 : */
876 : struct CommissioningReport
877 : : Variant<RequestedCertificate, AttestationResponse, CSRResponse, NocChain, OperationalNodeFoundData, ReadCommissioningInfo,
878 : AttestationErrorInfo, CommissioningErrorInfo, NetworkCommissioningStatusInfo, TimeZoneResponseInfo
879 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
880 : ,
881 : JCM::TrustVerificationError
882 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
883 : >
884 : {
885 0 : CommissioningReport() : stageCompleted(CommissioningStage::kError) {}
886 : CommissioningStage stageCompleted;
887 : };
888 : virtual CHIP_ERROR SetCommissioningParameters(const CommissioningParameters & params) = 0;
889 : virtual const CommissioningParameters & GetCommissioningParameters() const = 0;
890 : virtual void SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate) = 0;
891 : virtual CHIP_ERROR StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy) = 0;
892 : virtual CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err, CommissioningReport report) = 0;
893 : };
894 :
895 : } // namespace Controller
896 : } // namespace chip
|