Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2024 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * Implementation of CHIP Device Controller, a common class
23 : * that implements discovery, pairing and provisioning of CHIP
24 : * devices.
25 : *
26 : */
27 :
28 : // module header, comes first
29 : #include <controller/CHIPDeviceController.h>
30 :
31 : #include <app-common/zap-generated/ids/Attributes.h>
32 : #include <app-common/zap-generated/ids/Clusters.h>
33 :
34 : #include <app/InteractionModelEngine.h>
35 : #include <app/OperationalSessionSetup.h>
36 : #include <app/server/Dnssd.h>
37 : #include <controller/CurrentFabricRemover.h>
38 : #include <controller/InvokeInteraction.h>
39 : #include <controller/WriteInteraction.h>
40 : #include <credentials/CHIPCert.h>
41 : #include <credentials/DeviceAttestationCredsProvider.h>
42 : #include <crypto/CHIPCryptoPAL.h>
43 : #include <lib/address_resolve/AddressResolve.h>
44 : #include <lib/core/CHIPCore.h>
45 : #include <lib/core/CHIPEncoding.h>
46 : #include <lib/core/CHIPSafeCasts.h>
47 : #include <lib/core/ErrorStr.h>
48 : #include <lib/core/NodeId.h>
49 : #include <lib/support/Base64.h>
50 : #include <lib/support/CHIPMem.h>
51 : #include <lib/support/CHIPMemString.h>
52 : #include <lib/support/CodeUtils.h>
53 : #include <lib/support/PersistentStorageMacros.h>
54 : #include <lib/support/SafeInt.h>
55 : #include <lib/support/ScopedMemoryBuffer.h>
56 : #include <lib/support/ThreadOperationalDataset.h>
57 : #include <lib/support/TimeUtils.h>
58 : #include <lib/support/logging/CHIPLogging.h>
59 : #include <messaging/ExchangeContext.h>
60 : #include <platform/LockTracker.h>
61 : #include <protocols/secure_channel/MessageCounterManager.h>
62 : #include <setup_payload/QRCodeSetupPayloadParser.h>
63 : #include <tracing/macros.h>
64 : #include <tracing/metric_event.h>
65 :
66 : #if CONFIG_NETWORK_LAYER_BLE
67 : #include <ble/Ble.h>
68 : #include <transport/raw/BLE.h>
69 : #endif
70 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
71 : #include <transport/raw/WiFiPAF.h>
72 : #endif
73 :
74 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
75 : #include <platform/internal/NFCCommissioningManager.h>
76 : #endif
77 :
78 : #include <algorithm>
79 : #include <array>
80 : #include <errno.h>
81 : #include <inttypes.h>
82 : #include <limits>
83 : #include <memory>
84 : #include <stdint.h>
85 : #include <stdlib.h>
86 : #include <string>
87 : #include <time.h>
88 :
89 : using namespace chip::app;
90 : using namespace chip::app::Clusters;
91 : using namespace chip::Inet;
92 : using namespace chip::System;
93 : using namespace chip::Transport;
94 : using namespace chip::Credentials;
95 : using namespace chip::Crypto;
96 : using namespace chip::Tracing;
97 :
98 : namespace chip {
99 : namespace Controller {
100 :
101 : using namespace chip::Encoding;
102 : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
103 : using namespace chip::Protocols::UserDirectedCommissioning;
104 : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
105 :
106 : using chip::AddressResolve::Resolver;
107 : using chip::AddressResolve::ResolveResult;
108 :
109 275 : DeviceController::DeviceController()
110 : {
111 25 : mState = State::NotInitialized;
112 25 : }
113 :
114 0 : CHIP_ERROR DeviceController::Init(ControllerInitParams params)
115 : {
116 0 : assertChipStackLockedByCurrentThread();
117 :
118 0 : VerifyOrReturnError(mState == State::NotInitialized, CHIP_ERROR_INCORRECT_STATE);
119 0 : VerifyOrReturnError(params.systemState != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
120 :
121 0 : VerifyOrReturnError(params.systemState->SystemLayer() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
122 0 : VerifyOrReturnError(params.systemState->UDPEndPointManager() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
123 :
124 : #if CONFIG_NETWORK_LAYER_BLE
125 0 : VerifyOrReturnError(params.systemState->BleLayer() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
126 : #endif
127 :
128 0 : VerifyOrReturnError(params.systemState->TransportMgr() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
129 :
130 0 : ReturnErrorOnFailure(mDNSResolver.Init(params.systemState->UDPEndPointManager()));
131 0 : mDNSResolver.SetDiscoveryDelegate(this);
132 0 : RegisterDeviceDiscoveryDelegate(params.deviceDiscoveryDelegate);
133 :
134 0 : mVendorId = params.controllerVendorId;
135 0 : if (params.operationalKeypair != nullptr || !params.controllerNOC.empty() || !params.controllerRCAC.empty())
136 : {
137 0 : ReturnErrorOnFailure(InitControllerNOCChain(params));
138 : }
139 0 : else if (params.fabricIndex.HasValue())
140 : {
141 0 : VerifyOrReturnError(params.systemState->Fabrics()->FabricCount() > 0, CHIP_ERROR_INVALID_ARGUMENT);
142 0 : if (params.systemState->Fabrics()->FindFabricWithIndex(params.fabricIndex.Value()) != nullptr)
143 : {
144 0 : mFabricIndex = params.fabricIndex.Value();
145 : }
146 : else
147 : {
148 0 : ChipLogError(Controller, "There is no fabric corresponding to the given fabricIndex");
149 0 : return CHIP_ERROR_INVALID_ARGUMENT;
150 : }
151 : }
152 :
153 0 : mSystemState = params.systemState->Retain();
154 0 : mState = State::Initialized;
155 :
156 0 : mRemoveFromFabricTableOnShutdown = params.removeFromFabricTableOnShutdown;
157 0 : mDeleteFromFabricTableOnShutdown = params.deleteFromFabricTableOnShutdown;
158 :
159 0 : if (GetFabricIndex() != kUndefinedFabricIndex)
160 : {
161 0 : ChipLogProgress(Controller,
162 : "Joined the fabric at index %d. Fabric ID is 0x" ChipLogFormatX64
163 : " (Compressed Fabric ID: " ChipLogFormatX64 ")",
164 : GetFabricIndex(), ChipLogValueX64(GetFabricId()), ChipLogValueX64(GetCompressedFabricId()));
165 : }
166 :
167 0 : return CHIP_NO_ERROR;
168 : }
169 :
170 0 : CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams & params)
171 : {
172 0 : FabricInfo newFabric;
173 0 : constexpr uint32_t chipCertAllocatedLen = kMaxCHIPCertLength;
174 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> rcacBuf;
175 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> icacBuf;
176 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> nocBuf;
177 0 : Credentials::P256PublicKeySpan rootPublicKeySpan;
178 : FabricId fabricId;
179 : NodeId nodeId;
180 0 : bool hasExternallyOwnedKeypair = false;
181 0 : Crypto::P256Keypair * externalOperationalKeypair = nullptr;
182 0 : VendorId newFabricVendorId = params.controllerVendorId;
183 :
184 : // There are three possibilities here in terms of what happens with our
185 : // operational key:
186 : // 1) We have an externally owned operational keypair.
187 : // 2) We have an operational keypair that the fabric table should clone via
188 : // serialize/deserialize.
189 : // 3) We have no keypair at all, and the fabric table has been initialized
190 : // with a key store.
191 0 : if (params.operationalKeypair != nullptr)
192 : {
193 0 : hasExternallyOwnedKeypair = params.hasExternallyOwnedOperationalKeypair;
194 0 : externalOperationalKeypair = params.operationalKeypair;
195 : }
196 :
197 0 : VerifyOrReturnError(rcacBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
198 0 : VerifyOrReturnError(icacBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
199 0 : VerifyOrReturnError(nocBuf.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY);
200 :
201 0 : MutableByteSpan rcacSpan(rcacBuf.Get(), chipCertAllocatedLen);
202 :
203 0 : ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerRCAC, rcacSpan));
204 0 : ReturnErrorOnFailure(Credentials::ExtractPublicKeyFromChipCert(rcacSpan, rootPublicKeySpan));
205 0 : Crypto::P256PublicKey rootPublicKey{ rootPublicKeySpan };
206 :
207 0 : MutableByteSpan icacSpan;
208 0 : if (params.controllerICAC.empty())
209 : {
210 0 : ChipLogProgress(Controller, "Intermediate CA is not needed");
211 : }
212 : else
213 : {
214 0 : icacSpan = MutableByteSpan(icacBuf.Get(), chipCertAllocatedLen);
215 0 : ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerICAC, icacSpan));
216 : }
217 :
218 0 : MutableByteSpan nocSpan = MutableByteSpan(nocBuf.Get(), chipCertAllocatedLen);
219 :
220 0 : ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerNOC, nocSpan));
221 0 : ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(nocSpan, &nodeId, &fabricId));
222 :
223 0 : auto * fabricTable = params.systemState->Fabrics();
224 0 : const FabricInfo * fabricInfo = nullptr;
225 :
226 : //
227 : // When multiple controllers are permitted on the same fabric, we need to find fabrics with
228 : // nodeId as an extra discriminant since we can have multiple FabricInfo objects that all
229 : // collide on the same fabric. Not doing so may result in a match with an existing FabricInfo
230 : // instance that matches the fabric in the provided NOC but is associated with a different NodeId
231 : // that is already in use by another active controller instance. That will effectively cause it
232 : // to change its identity inadvertently, which is not acceptable.
233 : //
234 : // TODO: Figure out how to clean up unreclaimed FabricInfos restored from persistent
235 : // storage that are not in use by active DeviceController instances. Also, figure out
236 : // how to reclaim FabricInfo slots when a DeviceController instance is deleted.
237 : //
238 0 : if (params.permitMultiControllerFabrics)
239 : {
240 0 : fabricInfo = fabricTable->FindIdentity(rootPublicKey, fabricId, nodeId);
241 : }
242 : else
243 : {
244 0 : fabricInfo = fabricTable->FindFabric(rootPublicKey, fabricId);
245 : }
246 :
247 0 : bool fabricFoundInTable = (fabricInfo != nullptr);
248 :
249 0 : FabricIndex fabricIndex = fabricFoundInTable ? fabricInfo->GetFabricIndex() : kUndefinedFabricIndex;
250 :
251 0 : CHIP_ERROR err = CHIP_NO_ERROR;
252 :
253 0 : auto advertiseOperational =
254 0 : params.enableServerInteractions ? FabricTable::AdvertiseIdentity::Yes : FabricTable::AdvertiseIdentity::No;
255 :
256 : //
257 : // We permit colliding fabrics when multiple controllers are present on the same logical fabric
258 : // since each controller is associated with a unique FabricInfo 'identity' object and consequently,
259 : // a unique FabricIndex.
260 : //
261 : // This sets a flag that will be cleared automatically when the fabric is committed/reverted later
262 : // in this function.
263 : //
264 0 : if (params.permitMultiControllerFabrics)
265 : {
266 0 : fabricTable->PermitCollidingFabrics();
267 : }
268 :
269 : // We have 4 cases to handle legacy usage of direct operational key injection
270 0 : if (externalOperationalKeypair)
271 : {
272 : // Cases 1 and 2: Injected operational keys
273 :
274 : // CASE 1: Fabric update with injected key
275 0 : if (fabricFoundInTable)
276 : {
277 0 : err = fabricTable->UpdatePendingFabricWithProvidedOpKey(fabricIndex, nocSpan, icacSpan, externalOperationalKeypair,
278 : hasExternallyOwnedKeypair, advertiseOperational);
279 : }
280 : else
281 : // CASE 2: New fabric with injected key
282 : {
283 0 : err = fabricTable->AddNewPendingTrustedRootCert(rcacSpan);
284 0 : if (err == CHIP_NO_ERROR)
285 : {
286 0 : err = fabricTable->AddNewPendingFabricWithProvidedOpKey(nocSpan, icacSpan, newFabricVendorId,
287 : externalOperationalKeypair, hasExternallyOwnedKeypair,
288 : &fabricIndex, advertiseOperational);
289 : }
290 : }
291 : }
292 : else
293 : {
294 : // Cases 3 and 4: OperationalKeystore has the keys
295 :
296 : // CASE 3: Fabric update with operational keystore
297 0 : if (fabricFoundInTable)
298 : {
299 0 : VerifyOrReturnError(fabricTable->HasOperationalKeyForFabric(fabricIndex), CHIP_ERROR_KEY_NOT_FOUND);
300 :
301 0 : err = fabricTable->UpdatePendingFabricWithOperationalKeystore(fabricIndex, nocSpan, icacSpan, advertiseOperational);
302 : }
303 : else
304 : // CASE 4: New fabric with operational keystore
305 : {
306 0 : err = fabricTable->AddNewPendingTrustedRootCert(rcacSpan);
307 0 : if (err == CHIP_NO_ERROR)
308 : {
309 0 : err = fabricTable->AddNewPendingFabricWithOperationalKeystore(nocSpan, icacSpan, newFabricVendorId, &fabricIndex,
310 : advertiseOperational);
311 : }
312 :
313 0 : if (err == CHIP_NO_ERROR)
314 : {
315 : // Now that we know our planned fabric index, verify that the
316 : // keystore has a key for it.
317 0 : if (!fabricTable->HasOperationalKeyForFabric(fabricIndex))
318 : {
319 0 : err = CHIP_ERROR_KEY_NOT_FOUND;
320 : }
321 : }
322 : }
323 : }
324 :
325 : // Commit after setup, error-out on failure.
326 0 : if (err == CHIP_NO_ERROR)
327 : {
328 : // No need to revert on error: CommitPendingFabricData reverts internally on *any* error.
329 0 : err = fabricTable->CommitPendingFabricData();
330 : }
331 : else
332 : {
333 0 : fabricTable->RevertPendingFabricData();
334 : }
335 :
336 0 : ReturnErrorOnFailure(err);
337 0 : VerifyOrReturnError(fabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL);
338 :
339 0 : mFabricIndex = fabricIndex;
340 0 : mAdvertiseIdentity = advertiseOperational;
341 0 : return CHIP_NO_ERROR;
342 0 : }
343 :
344 0 : CHIP_ERROR DeviceController::UpdateControllerNOCChain(const ByteSpan & noc, const ByteSpan & icac,
345 : Crypto::P256Keypair * operationalKeypair,
346 : bool operationalKeypairExternalOwned)
347 : {
348 0 : VerifyOrReturnError(mFabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL);
349 0 : VerifyOrReturnError(mSystemState != nullptr, CHIP_ERROR_INTERNAL);
350 0 : FabricTable * fabricTable = mSystemState->Fabrics();
351 0 : CHIP_ERROR err = CHIP_NO_ERROR;
352 : FabricId fabricId;
353 : NodeId nodeId;
354 0 : CATValues oldCats;
355 0 : CATValues newCats;
356 0 : ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(noc, &nodeId, &fabricId));
357 0 : ReturnErrorOnFailure(fabricTable->FetchCATs(mFabricIndex, oldCats));
358 0 : ReturnErrorOnFailure(ExtractCATsFromOpCert(noc, newCats));
359 :
360 0 : bool needCloseSession = true;
361 0 : if (GetFabricInfo()->GetNodeId() == nodeId && oldCats == newCats)
362 : {
363 0 : needCloseSession = false;
364 : }
365 :
366 0 : if (operationalKeypair != nullptr)
367 : {
368 0 : err = fabricTable->UpdatePendingFabricWithProvidedOpKey(mFabricIndex, noc, icac, operationalKeypair,
369 : operationalKeypairExternalOwned, mAdvertiseIdentity);
370 : }
371 : else
372 : {
373 0 : VerifyOrReturnError(fabricTable->HasOperationalKeyForFabric(mFabricIndex), CHIP_ERROR_KEY_NOT_FOUND);
374 0 : err = fabricTable->UpdatePendingFabricWithOperationalKeystore(mFabricIndex, noc, icac, mAdvertiseIdentity);
375 : }
376 :
377 0 : if (err == CHIP_NO_ERROR)
378 : {
379 0 : err = fabricTable->CommitPendingFabricData();
380 : }
381 : else
382 : {
383 0 : fabricTable->RevertPendingFabricData();
384 : }
385 :
386 0 : ReturnErrorOnFailure(err);
387 0 : if (needCloseSession)
388 : {
389 : // If the node id or CATs have changed, our existing CASE sessions are no longer valid,
390 : // because the other side will think anything coming over those sessions comes from our
391 : // old node ID, and the new CATs might not satisfy the ACL requirements of the other side.
392 0 : mSystemState->SessionMgr()->ExpireAllSessionsForFabric(mFabricIndex);
393 : }
394 0 : ChipLogProgress(Controller, "Controller NOC chain has updated");
395 0 : return CHIP_NO_ERROR;
396 : }
397 :
398 0 : void DeviceController::Shutdown()
399 : {
400 0 : assertChipStackLockedByCurrentThread();
401 :
402 0 : VerifyOrReturn(mState != State::NotInitialized);
403 :
404 : // If our state is initialialized it means mSystemState is valid,
405 : // and we can use it below before we release our reference to it.
406 0 : ChipLogDetail(Controller, "Shutting down the controller");
407 0 : mState = State::NotInitialized;
408 :
409 0 : if (mFabricIndex != kUndefinedFabricIndex)
410 : {
411 : // Shut down any subscription clients for this fabric.
412 0 : app::InteractionModelEngine::GetInstance()->ShutdownSubscriptions(mFabricIndex);
413 :
414 : // Shut down any ongoing CASE session activity we have. We're going to
415 : // assume that all sessions for our fabric belong to us here.
416 0 : mSystemState->CASESessionMgr()->ReleaseSessionsForFabric(mFabricIndex);
417 :
418 : // Shut down any bdx transfers we're acting as the server for.
419 0 : mSystemState->BDXTransferServer()->AbortTransfersForFabric(mFabricIndex);
420 :
421 : // TODO: The CASE session manager does not shut down existing CASE
422 : // sessions. It just shuts down any ongoing CASE session establishment
423 : // we're in the middle of as initiator. Maybe it should shut down
424 : // existing sessions too?
425 0 : mSystemState->SessionMgr()->ExpireAllSessionsForFabric(mFabricIndex);
426 :
427 0 : if (mDeleteFromFabricTableOnShutdown)
428 : {
429 0 : TEMPORARY_RETURN_IGNORED mSystemState->Fabrics()->Delete(mFabricIndex);
430 : }
431 0 : else if (mRemoveFromFabricTableOnShutdown)
432 : {
433 0 : mSystemState->Fabrics()->Forget(mFabricIndex);
434 : }
435 : }
436 :
437 0 : mSystemState->Release();
438 0 : mSystemState = nullptr;
439 :
440 0 : mDNSResolver.Shutdown();
441 0 : mDeviceDiscoveryDelegate = nullptr;
442 : }
443 :
444 0 : CHIP_ERROR DeviceController::GetPeerAddressAndPort(NodeId peerId, Inet::IPAddress & addr, uint16_t & port)
445 : {
446 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
447 0 : Transport::PeerAddress peerAddr;
448 0 : ReturnErrorOnFailure(mSystemState->CASESessionMgr()->GetPeerAddress(GetPeerScopedId(peerId), peerAddr));
449 0 : addr = peerAddr.GetIPAddress();
450 0 : port = peerAddr.GetPort();
451 0 : return CHIP_NO_ERROR;
452 : }
453 :
454 0 : CHIP_ERROR DeviceController::GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr)
455 : {
456 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
457 0 : ReturnErrorOnFailure(mSystemState->CASESessionMgr()->GetPeerAddress(GetPeerScopedId(nodeId), addr));
458 :
459 0 : return CHIP_NO_ERROR;
460 : }
461 :
462 0 : CHIP_ERROR DeviceController::ComputePASEVerifier(uint32_t iterations, uint32_t setupPincode, const ByteSpan & salt,
463 : Spake2pVerifier & outVerifier)
464 : {
465 0 : ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(outVerifier, iterations, salt, /* useRandomPIN= */ false, setupPincode));
466 :
467 0 : return CHIP_NO_ERROR;
468 : }
469 :
470 0 : ControllerDeviceInitParams DeviceController::GetControllerDeviceInitParams()
471 : {
472 : return ControllerDeviceInitParams{
473 0 : .sessionManager = mSystemState->SessionMgr(),
474 0 : .exchangeMgr = mSystemState->ExchangeMgr(),
475 0 : };
476 : }
477 :
478 13 : DeviceCommissioner::DeviceCommissioner() :
479 13 : mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this),
480 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
481 13 : mOnDeviceConnectionRetryCallback(OnDeviceConnectionRetryFn, this),
482 : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
483 13 : mDeviceAttestationInformationVerificationCallback(OnDeviceAttestationInformationVerification, this),
484 26 : mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this), mSetUpCodePairer(this)
485 : {
486 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
487 : (void) mPeerAdminJFAdminClusterEndpointId;
488 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
489 13 : }
490 :
491 0 : CHIP_ERROR DeviceCommissioner::Init(CommissionerInitParams params)
492 : {
493 0 : VerifyOrReturnError(params.operationalCredentialsDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
494 0 : mOperationalCredentialsDelegate = params.operationalCredentialsDelegate;
495 0 : ReturnErrorOnFailure(DeviceController::Init(params));
496 :
497 0 : mPairingDelegate = params.pairingDelegate;
498 :
499 : // Configure device attestation validation
500 0 : mDeviceAttestationVerifier = params.deviceAttestationVerifier;
501 0 : if (mDeviceAttestationVerifier == nullptr)
502 : {
503 0 : mDeviceAttestationVerifier = Credentials::GetDeviceAttestationVerifier();
504 0 : if (mDeviceAttestationVerifier == nullptr)
505 : {
506 0 : ChipLogError(Controller,
507 : "Missing DeviceAttestationVerifier configuration at DeviceCommissioner init and none set with "
508 : "Credentials::SetDeviceAttestationVerifier()!");
509 0 : return CHIP_ERROR_INVALID_ARGUMENT;
510 : }
511 :
512 : // We fell back on a default from singleton accessor.
513 0 : ChipLogProgress(Controller,
514 : "*** Missing DeviceAttestationVerifier configuration at DeviceCommissioner init: using global default, "
515 : "consider passing one in CommissionerInitParams.");
516 : }
517 :
518 0 : if (params.defaultCommissioner != nullptr)
519 : {
520 0 : mDefaultCommissioner = params.defaultCommissioner;
521 : }
522 : // Otherwise leave it pointing to mAutoCommissioner.
523 :
524 : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
525 : mUdcTransportMgr = chip::Platform::New<UdcTransportMgr>();
526 : ReturnErrorOnFailure(mUdcTransportMgr->Init(Transport::UdpListenParameters(mSystemState->UDPEndPointManager())
527 : .SetAddressType(Inet::IPAddressType::kIPv6)
528 : .SetListenPort(static_cast<uint16_t>(mUdcListenPort))
529 : #if INET_CONFIG_ENABLE_IPV4
530 : ,
531 : Transport::UdpListenParameters(mSystemState->UDPEndPointManager())
532 : .SetAddressType(Inet::IPAddressType::kIPv4)
533 : .SetListenPort(static_cast<uint16_t>(mUdcListenPort))
534 : #endif // INET_CONFIG_ENABLE_IPV4
535 : ));
536 :
537 : mUdcServer = chip::Platform::New<UserDirectedCommissioningServer>();
538 : mUdcTransportMgr->SetSessionManager(mUdcServer);
539 : mUdcServer->SetTransportManager(mUdcTransportMgr);
540 :
541 : mUdcServer->SetInstanceNameResolver(this);
542 : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
543 :
544 0 : mSetUpCodePairer.SetSystemLayer(mSystemState->SystemLayer());
545 : #if CONFIG_NETWORK_LAYER_BLE
546 0 : mSetUpCodePairer.SetBleLayer(mSystemState->BleLayer());
547 : #endif // CONFIG_NETWORK_LAYER_BLE
548 :
549 0 : return CHIP_NO_ERROR;
550 : }
551 :
552 0 : void DeviceCommissioner::Shutdown()
553 : {
554 0 : VerifyOrReturn(mState != State::NotInitialized);
555 :
556 0 : ChipLogDetail(Controller, "Shutting down the commissioner");
557 :
558 0 : mSetUpCodePairer.StopPairing();
559 :
560 : // Check to see if pairing in progress before shutting down
561 0 : CommissioneeDeviceProxy * device = mDeviceInPASEEstablishment;
562 0 : if (device != nullptr && device->IsSessionSetupInProgress())
563 : {
564 0 : ChipLogDetail(Controller, "Setup in progress, stopping setup before shutting down");
565 0 : OnSessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
566 : }
567 :
568 0 : CancelCommissioningInteractions();
569 :
570 : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
571 : if (mUdcTransportMgr != nullptr)
572 : {
573 : chip::Platform::Delete(mUdcTransportMgr);
574 : mUdcTransportMgr = nullptr;
575 : }
576 : if (mUdcServer != nullptr)
577 : {
578 : mUdcServer->SetInstanceNameResolver(nullptr);
579 : chip::Platform::Delete(mUdcServer);
580 : mUdcServer = nullptr;
581 : }
582 : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
583 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
584 0 : WiFiPAF::WiFiPAFLayer::GetWiFiPAFLayer().Shutdown();
585 : #endif
586 :
587 : // Release everything from the commissionee device pool here.
588 : // Make sure to use ReleaseCommissioneeDevice so we don't keep dangling
589 : // pointers to the device objects.
590 0 : mCommissioneeDevicePool.ForEachActiveObject([this](auto * commissioneeDevice) {
591 0 : ReleaseCommissioneeDevice(commissioneeDevice);
592 0 : return Loop::Continue;
593 : });
594 :
595 0 : DeviceController::Shutdown();
596 : }
597 :
598 0 : CommissioneeDeviceProxy * DeviceCommissioner::FindCommissioneeDevice(NodeId id)
599 : {
600 : MATTER_TRACE_SCOPE("FindCommissioneeDevice", "DeviceCommissioner");
601 0 : CommissioneeDeviceProxy * foundDevice = nullptr;
602 0 : mCommissioneeDevicePool.ForEachActiveObject([&](auto * deviceProxy) {
603 0 : if (deviceProxy->GetDeviceId() == id || deviceProxy->GetTemporaryCommissioningId() == id)
604 : {
605 0 : foundDevice = deviceProxy;
606 0 : return Loop::Break;
607 : }
608 0 : return Loop::Continue;
609 : });
610 :
611 0 : return foundDevice;
612 : }
613 :
614 0 : CommissioneeDeviceProxy * DeviceCommissioner::FindCommissioneeDevice(const Transport::PeerAddress & peerAddress)
615 : {
616 0 : CommissioneeDeviceProxy * foundDevice = nullptr;
617 0 : mCommissioneeDevicePool.ForEachActiveObject([&](auto * deviceProxy) {
618 0 : if (deviceProxy->GetPeerAddress() == peerAddress)
619 : {
620 0 : foundDevice = deviceProxy;
621 0 : return Loop::Break;
622 : }
623 0 : return Loop::Continue;
624 : });
625 :
626 0 : return foundDevice;
627 : }
628 :
629 0 : void DeviceCommissioner::ReleaseCommissioneeDevice(CommissioneeDeviceProxy * device)
630 : {
631 : #if CONFIG_NETWORK_LAYER_BLE
632 0 : if (mSystemState->BleLayer() != nullptr && device->GetDeviceTransportType() == Transport::Type::kBle)
633 : {
634 : // We only support one BLE connection, so if this is BLE, close it
635 0 : ChipLogProgress(Discovery, "Closing all BLE connections");
636 0 : mSystemState->BleLayer()->CloseAllBleConnections();
637 : }
638 : #endif
639 :
640 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
641 : Nfc::NFCReaderTransport * readerTransport = DeviceLayer::Internal::NFCCommissioningMgr().GetNFCReaderTransport();
642 : if (readerTransport)
643 : {
644 : ChipLogProgress(Controller, "Stopping discovery of all NFC tags");
645 : TEMPORARY_RETURN_IGNORED readerTransport->StopDiscoveringTags();
646 : }
647 : #endif
648 :
649 : // Make sure that there will be no dangling pointer
650 0 : if (mDeviceInPASEEstablishment == device)
651 : {
652 0 : mDeviceInPASEEstablishment = nullptr;
653 : }
654 0 : if (mDeviceBeingCommissioned == device)
655 : {
656 0 : mDeviceBeingCommissioned = nullptr;
657 : }
658 :
659 : // Release the commissionee device after we have nulled out our pointers,
660 : // because that can call back in to us with error notifications as the
661 : // session is released.
662 0 : mCommissioneeDevicePool.ReleaseObject(device);
663 0 : }
664 :
665 0 : CHIP_ERROR DeviceCommissioner::GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** out_device)
666 : {
667 0 : VerifyOrReturnError(out_device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
668 0 : CommissioneeDeviceProxy * device = FindCommissioneeDevice(deviceId);
669 :
670 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
671 :
672 0 : *out_device = device;
673 :
674 0 : return CHIP_NO_ERROR;
675 : }
676 :
677 0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * setUpCode, const CommissioningParameters & params,
678 : DiscoveryType discoveryType, Optional<Dnssd::CommonResolutionData> resolutionData,
679 : Optional<SetUpCodePairer::ThreadMeshcopCommissionParameters> meshcopCommissionParams)
680 : {
681 : MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
682 : #if CHIP_SUPPORT_THREAD_MESHCOP
683 0 : if (meshcopCommissionParams.HasValue())
684 : {
685 0 : mSetUpCodePairer.SetThreadMeshcopCommissionParamsAndProxy(meshcopCommissionParams.Value(), &mThreadMeshcopCommissionProxy);
686 : }
687 : #endif
688 0 : ReturnErrorOnFailure(mDefaultCommissioner->SetCommissioningParameters(params));
689 :
690 0 : return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kCommission, discoveryType,
691 0 : resolutionData);
692 : }
693 :
694 0 : CHIP_ERROR DeviceCommissioner::GetLastThreadMeshcopDiscoveryDiagnosticJson(char * buffer, size_t bufferSize)
695 : {
696 : #if CHIP_SUPPORT_THREAD_MESHCOP
697 0 : VerifyOrReturnError(buffer != nullptr && bufferSize > 0, CHIP_ERROR_INVALID_ARGUMENT);
698 :
699 0 : const std::string json = mThreadMeshcopCommissionProxy.GetLastDiscoveryDiagnosticJson();
700 0 : VerifyOrReturnError(json.size() < bufferSize, CHIP_ERROR_BUFFER_TOO_SMALL);
701 0 : Platform::CopyString(buffer, bufferSize, json.c_str());
702 0 : return CHIP_NO_ERROR;
703 : #else
704 : return CHIP_ERROR_NOT_IMPLEMENTED;
705 : #endif // CHIP_SUPPORT_THREAD_MESHCOP
706 0 : }
707 :
708 0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * setUpCode, DiscoveryType discoveryType,
709 : Optional<Dnssd::CommonResolutionData> resolutionData)
710 : {
711 : MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
712 0 : return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kCommission, discoveryType,
713 0 : resolutionData);
714 : }
715 :
716 0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params)
717 : {
718 : MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
719 0 : ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, EstablishPASEConnection(remoteDeviceId, params));
720 0 : auto errorCode = Commission(remoteDeviceId);
721 0 : VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
722 0 : return errorCode;
723 : }
724 :
725 : #if CHIP_SUPPORT_THREAD_MESHCOP
726 0 : CHIP_ERROR DeviceCommissioner::PairThreadMeshcop(RendezvousParameters & rendezvousParams,
727 : CommissioningParameters & commissioningParams)
728 : {
729 0 : VerifyOrReturnError(rendezvousParams.GetSetupDiscriminator().has_value(), CHIP_ERROR_INVALID_ARGUMENT);
730 0 : VerifyOrReturnError(commissioningParams.GetThreadOperationalDataset().HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
731 0 : auto discriminator = rendezvousParams.GetSetupDiscriminator().value();
732 0 : Thread::DiscoveryCode code;
733 0 : if (rendezvousParams.GetSetupDiscriminator().value().IsShortDiscriminator())
734 : {
735 0 : code = Thread::DiscoveryCode(discriminator.GetShortValue());
736 0 : ChipLogProgress(Controller, "Discovery code from short discriminator: 0x%" PRIx64, code.AsUInt64());
737 : }
738 : else
739 : {
740 0 : code = Thread::DiscoveryCode(discriminator.GetLongValue());
741 0 : ChipLogProgress(Controller, "Discovery code from long discriminator: 0x%" PRIx64, code.AsUInt64());
742 : }
743 :
744 : uint8_t pskcBuffer[Thread::kSizePSKc];
745 0 : ByteSpan pskc(pskcBuffer);
746 : {
747 0 : Thread::OperationalDatasetView dataset;
748 0 : ReturnErrorOnFailure(dataset.Init(commissioningParams.GetThreadOperationalDataset().Value()));
749 :
750 0 : ReturnErrorOnFailure(dataset.GetPSKc(pskcBuffer));
751 : }
752 :
753 : {
754 0 : Dnssd::DiscoveredNodeData discoveredNodeData;
755 0 : ReturnErrorOnFailure(mThreadMeshcopCommissionProxy.Discover(pskc, rendezvousParams.GetPeerAddress(), code, discriminator,
756 : discoveredNodeData, 30));
757 :
758 0 : ChipLogProgress(Controller, "Joiner discovered");
759 0 : OnNodeDiscovered(discoveredNodeData);
760 0 : }
761 0 : return CHIP_NO_ERROR;
762 : }
763 : #endif // CHIP_SUPPORT_THREAD_MESHCOP
764 :
765 0 : CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams,
766 : CommissioningParameters & commissioningParams)
767 : {
768 : MATTER_TRACE_SCOPE("PairDevice", "DeviceCommissioner");
769 : #if CHIP_SUPPORT_THREAD_MESHCOP
770 0 : if (rendezvousParams.GetPeerAddress().GetTransportType() == Transport::Type::kThreadMeshcop)
771 : {
772 0 : return PairThreadMeshcop(rendezvousParams, commissioningParams);
773 : }
774 : #endif
775 0 : ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, EstablishPASEConnection(remoteDeviceId, rendezvousParams));
776 0 : auto errorCode = Commission(remoteDeviceId, commissioningParams);
777 0 : VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
778 0 : return errorCode;
779 : }
780 :
781 : CHIP_ERROR
782 0 : DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, const char * setUpCode, DiscoveryType discoveryType,
783 : Optional<Dnssd::CommonResolutionData> resolutionData,
784 : Optional<SetUpCodePairer::ThreadMeshcopCommissionParameters> meshcopCommissionParams)
785 : {
786 : MATTER_TRACE_SCOPE("EstablishPASEConnection", "DeviceCommissioner");
787 : #if CHIP_SUPPORT_THREAD_MESHCOP
788 0 : if (meshcopCommissionParams.HasValue())
789 : {
790 0 : mSetUpCodePairer.SetThreadMeshcopCommissionParamsAndProxy(meshcopCommissionParams.Value(), &mThreadMeshcopCommissionProxy);
791 : }
792 : #endif
793 0 : return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode, SetupCodePairerBehaviour::kPaseOnly, discoveryType,
794 0 : resolutionData);
795 : }
796 :
797 0 : CHIP_ERROR DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, RendezvousParameters & params)
798 : {
799 : MATTER_TRACE_SCOPE("EstablishPASEConnection", "DeviceCommissioner");
800 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerPASESession);
801 :
802 0 : CHIP_ERROR err = CHIP_NO_ERROR;
803 0 : CommissioneeDeviceProxy * device = nullptr;
804 0 : CommissioneeDeviceProxy * current = nullptr;
805 0 : Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
806 :
807 0 : Messaging::ExchangeContext * exchangeCtxt = nullptr;
808 0 : Optional<SessionHandle> session;
809 :
810 0 : VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE);
811 0 : VerifyOrExit(mDeviceInPASEEstablishment == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
812 :
813 : // TODO(#13940): We need to specify the peer address for BLE transport in bindings.
814 0 : if (params.GetPeerAddress().GetTransportType() == Transport::Type::kBle ||
815 0 : params.GetPeerAddress().GetTransportType() == Transport::Type::kUndefined)
816 : {
817 : #if CONFIG_NETWORK_LAYER_BLE
818 : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
819 : ConnectBleTransportToSelf();
820 : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
821 0 : if (!params.HasBleLayer())
822 : {
823 0 : params.SetPeerAddress(Transport::PeerAddress::BLE());
824 : }
825 0 : peerAddress = Transport::PeerAddress::BLE();
826 : #endif // CONFIG_NETWORK_LAYER_BLE
827 : }
828 0 : else if (params.GetPeerAddress().GetTransportType() == Transport::Type::kTcp ||
829 0 : params.GetPeerAddress().GetTransportType() == Transport::Type::kUdp)
830 : {
831 0 : peerAddress = Transport::PeerAddress::UDP(params.GetPeerAddress().GetIPAddress(), params.GetPeerAddress().GetPort(),
832 0 : params.GetPeerAddress().GetInterface());
833 : }
834 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
835 0 : else if (params.GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF)
836 : {
837 0 : peerAddress = Transport::PeerAddress::WiFiPAF(remoteDeviceId);
838 : }
839 : #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
840 :
841 0 : current = FindCommissioneeDevice(peerAddress);
842 0 : if (current != nullptr)
843 : {
844 0 : if (current->GetDeviceId() == remoteDeviceId)
845 : {
846 : // We might be able to just reuse its connection if it has one or is
847 : // working on one.
848 0 : if (current->IsSecureConnected())
849 : {
850 0 : if (mPairingDelegate)
851 : {
852 : // We already have an open secure session to this device, call the callback immediately and early return.
853 : // We don't know what the right RendezvousParameters are here.
854 0 : mPairingDelegate->OnPairingComplete(CHIP_NO_ERROR, std::nullopt, std::nullopt);
855 : }
856 : MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, CHIP_NO_ERROR);
857 0 : return CHIP_NO_ERROR;
858 : }
859 0 : if (current->IsSessionSetupInProgress())
860 : {
861 : // We're not connected yet, but we're in the process of connecting. Pairing delegate will get a callback when
862 : // connection completes
863 0 : return CHIP_NO_ERROR;
864 : }
865 : }
866 :
867 : // Either the consumer wants to assign a different device id to this
868 : // peer address now (so we can't reuse the commissionee device we have
869 : // already) or something has gone strange. Delete the old device, try
870 : // again.
871 0 : ChipLogError(Controller, "Found unconnected device, removing");
872 0 : ReleaseCommissioneeDevice(current);
873 : }
874 :
875 0 : device = mCommissioneeDevicePool.CreateObject();
876 0 : VerifyOrExit(device != nullptr, err = CHIP_ERROR_NO_MEMORY);
877 :
878 0 : mDeviceInPASEEstablishment = device;
879 0 : device->Init(GetControllerDeviceInitParams(), remoteDeviceId, peerAddress);
880 0 : device->UpdateDeviceData(params.GetPeerAddress(), params.GetMRPConfig());
881 :
882 : #if CONFIG_NETWORK_LAYER_BLE
883 0 : if (params.GetPeerAddress().GetTransportType() == Transport::Type::kBle)
884 : {
885 0 : if (params.HasConnectionObject())
886 : {
887 0 : SuccessOrExit(err = mSystemState->BleLayer()->NewBleConnectionByObject(params.GetConnectionObject()));
888 : }
889 0 : else if (params.HasDiscoveredObject())
890 : {
891 : // The RendezvousParameters argument needs to be recovered if the search succeed, so save them
892 : // for later.
893 0 : mRendezvousParametersForDeviceDiscoveredOverBle = params;
894 0 : ExitNow(err = mSystemState->BleLayer()->NewBleConnectionByObject(
895 : params.GetDiscoveredObject(), this, OnDiscoveredDeviceOverBleSuccess, OnDiscoveredDeviceOverBleError));
896 : }
897 0 : else if (params.GetSetupDiscriminator().has_value())
898 : {
899 : // The RendezvousParameters argument needs to be recovered if the search succeed, so save them
900 : // for later.
901 0 : mRendezvousParametersForDeviceDiscoveredOverBle = params;
902 0 : auto setupDiscriminator = params.GetSetupDiscriminator();
903 0 : VerifyOrExit(setupDiscriminator.has_value(), err = CHIP_ERROR_INVALID_ARGUMENT);
904 0 : ExitNow(err = mSystemState->BleLayer()->NewBleConnectionByDiscriminator(
905 : setupDiscriminator.value(), this, OnDiscoveredDeviceOverBleSuccess, OnDiscoveredDeviceOverBleError));
906 : }
907 : else
908 : {
909 0 : ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
910 : }
911 : }
912 : #endif
913 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
914 0 : if (params.GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF)
915 : {
916 0 : if (DeviceLayer::ConnectivityMgr().GetWiFiPAF()->GetWiFiPAFState() != WiFiPAF::State::kConnected)
917 : {
918 0 : ChipLogProgress(Controller, "WiFi-PAF: Subscribing to the NAN-USD devices, nodeId: %" PRIu64,
919 : params.GetPeerAddress().GetRemoteId());
920 0 : mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = params;
921 0 : auto nodeId = params.GetPeerAddress().GetRemoteId();
922 0 : const SetupDiscriminator connDiscriminator(params.GetSetupDiscriminator().value());
923 0 : VerifyOrReturnValue(!connDiscriminator.IsShortDiscriminator(), CHIP_ERROR_INVALID_ARGUMENT,
924 : ChipLogError(Controller, "Error, Long discriminator is required"));
925 0 : uint16_t discriminator = connDiscriminator.GetLongValue();
926 0 : WiFiPAF::WiFiPAFSession sessionInfo = { .role = WiFiPAF::WiFiPafRole::kWiFiPafRole_Subscriber,
927 : .nodeId = nodeId,
928 0 : .discriminator = discriminator };
929 0 : ReturnErrorOnFailure(
930 : DeviceLayer::ConnectivityMgr().GetWiFiPAF()->AddPafSession(WiFiPAF::PafInfoAccess::kAccNodeInfo, sessionInfo));
931 0 : ExitNow(err = DeviceLayer::ConnectivityMgr().WiFiPAFSubscribe(discriminator, reinterpret_cast<void *>(this),
932 : OnWiFiPAFSubscribeComplete, OnWiFiPAFSubscribeError));
933 : }
934 : }
935 : #endif
936 0 : session = mSystemState->SessionMgr()->CreateUnauthenticatedSession(params.GetPeerAddress(), params.GetMRPConfig());
937 0 : VerifyOrExit(session.HasValue(), err = CHIP_ERROR_NO_MEMORY);
938 :
939 : // Allocate the exchange immediately before calling PASESession::Pair.
940 : //
941 : // PASESession::Pair takes ownership of the exchange and will free it on
942 : // error, but can only do this if it is actually called. Allocating the
943 : // exchange context right before calling Pair ensures that if allocation
944 : // succeeds, PASESession has taken ownership.
945 0 : exchangeCtxt = mSystemState->ExchangeMgr()->NewContext(session.Value(), &device->GetPairing());
946 0 : VerifyOrExit(exchangeCtxt != nullptr, err = CHIP_ERROR_INTERNAL);
947 :
948 0 : err = device->GetPairing().Pair(*mSystemState->SessionMgr(), params.GetSetupPINCode(), GetLocalMRPConfig(), exchangeCtxt, this);
949 0 : SuccessOrExit(err);
950 :
951 0 : mRendezvousParametersForPASEEstablishment = params;
952 :
953 0 : exit:
954 0 : if (err != CHIP_NO_ERROR)
955 : {
956 0 : if (device != nullptr)
957 : {
958 0 : ReleaseCommissioneeDevice(device);
959 : }
960 : MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, err);
961 : }
962 :
963 0 : return err;
964 0 : }
965 :
966 : #if CONFIG_NETWORK_LAYER_BLE
967 0 : void DeviceCommissioner::OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj)
968 : {
969 0 : auto self = static_cast<DeviceCommissioner *>(appState);
970 0 : auto device = self->mDeviceInPASEEstablishment;
971 :
972 0 : if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kBle)
973 : {
974 0 : auto remoteId = device->GetDeviceId();
975 :
976 0 : auto params = self->mRendezvousParametersForDeviceDiscoveredOverBle;
977 0 : params.SetConnectionObject(connObj);
978 0 : self->mRendezvousParametersForDeviceDiscoveredOverBle = RendezvousParameters();
979 :
980 0 : self->ReleaseCommissioneeDevice(device);
981 0 : LogErrorOnFailure(self->EstablishPASEConnection(remoteId, params));
982 : }
983 0 : }
984 :
985 0 : void DeviceCommissioner::OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err)
986 : {
987 0 : auto self = static_cast<DeviceCommissioner *>(appState);
988 0 : auto device = self->mDeviceInPASEEstablishment;
989 :
990 0 : if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kBle)
991 : {
992 0 : self->ReleaseCommissioneeDevice(device);
993 0 : self->mRendezvousParametersForDeviceDiscoveredOverBle = RendezvousParameters();
994 :
995 : // Callback is required when BLE discovery fails, otherwise the caller will always be in a suspended state
996 : // A better way to handle it should define a new error code
997 0 : if (self->mPairingDelegate != nullptr)
998 : {
999 0 : self->mPairingDelegate->OnPairingComplete(err, std::nullopt, std::nullopt);
1000 : }
1001 : }
1002 0 : }
1003 : #endif // CONFIG_NETWORK_LAYER_BLE
1004 :
1005 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
1006 0 : void DeviceCommissioner::OnWiFiPAFSubscribeComplete(void * appState)
1007 : {
1008 0 : auto self = reinterpret_cast<DeviceCommissioner *>(appState);
1009 0 : auto device = self->mDeviceInPASEEstablishment;
1010 :
1011 0 : if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kWiFiPAF)
1012 : {
1013 0 : ChipLogProgress(Controller, "WiFi-PAF: Subscription Completed, dev_id = %" PRIu64, device->GetDeviceId());
1014 0 : auto remoteId = device->GetDeviceId();
1015 0 : auto params = self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF;
1016 :
1017 0 : self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = RendezvousParameters();
1018 0 : self->ReleaseCommissioneeDevice(device);
1019 0 : LogErrorOnFailure(self->EstablishPASEConnection(remoteId, params));
1020 : }
1021 0 : }
1022 :
1023 0 : void DeviceCommissioner::OnWiFiPAFSubscribeError(void * appState, CHIP_ERROR err)
1024 : {
1025 0 : auto self = (DeviceCommissioner *) appState;
1026 0 : auto device = self->mDeviceInPASEEstablishment;
1027 :
1028 0 : if (nullptr != device && device->GetDeviceTransportType() == Transport::Type::kWiFiPAF)
1029 : {
1030 0 : ChipLogError(Controller, "WiFi-PAF: Subscription Error, id = %" PRIu64 ", err = %" CHIP_ERROR_FORMAT, device->GetDeviceId(),
1031 : err.Format());
1032 0 : self->ReleaseCommissioneeDevice(device);
1033 0 : self->mRendezvousParametersForDeviceDiscoveredOverWiFiPAF = RendezvousParameters();
1034 0 : if (self->mPairingDelegate != nullptr)
1035 : {
1036 0 : self->mPairingDelegate->OnPairingComplete(err, std::nullopt, std::nullopt);
1037 : }
1038 : }
1039 0 : }
1040 : #endif
1041 :
1042 0 : CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId, CommissioningParameters & params)
1043 : {
1044 0 : ReturnErrorOnFailureWithMetric(kMetricDeviceCommissionerCommission, mDefaultCommissioner->SetCommissioningParameters(params));
1045 0 : auto errorCode = Commission(remoteDeviceId);
1046 0 : VerifyOrDoWithMetric(kMetricDeviceCommissionerCommission, CHIP_NO_ERROR == errorCode, errorCode);
1047 0 : return errorCode;
1048 : }
1049 :
1050 0 : CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId)
1051 : {
1052 : MATTER_TRACE_SCOPE("Commission", "DeviceCommissioner");
1053 :
1054 : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
1055 : // Reset fallback from any previous commissioning session
1056 : mFallbackOperationalResolveResult.ClearValue();
1057 : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
1058 :
1059 0 : CommissioneeDeviceProxy * device = FindCommissioneeDevice(remoteDeviceId);
1060 0 : if (device == nullptr || (!device->IsSecureConnected() && !device->IsSessionSetupInProgress()))
1061 : {
1062 0 : ChipLogError(Controller, "Invalid device for commissioning " ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
1063 0 : return CHIP_ERROR_INCORRECT_STATE;
1064 : }
1065 0 : if (!device->IsSecureConnected() && device != mDeviceInPASEEstablishment)
1066 : {
1067 : // We should not end up in this state because we won't attempt to establish more than one connection at a time.
1068 0 : ChipLogError(Controller, "Device is not connected and not being paired " ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
1069 0 : return CHIP_ERROR_INCORRECT_STATE;
1070 : }
1071 :
1072 0 : if (mCommissioningStage != CommissioningStage::kSecurePairing)
1073 : {
1074 0 : ChipLogError(Controller, "Commissioning already in progress (stage '%s') - not restarting",
1075 : StageToString(mCommissioningStage));
1076 0 : return CHIP_ERROR_INCORRECT_STATE;
1077 : }
1078 :
1079 0 : ChipLogProgress(Controller, "Commission called for node ID 0x" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
1080 :
1081 0 : mDefaultCommissioner->SetOperationalCredentialsDelegate(mOperationalCredentialsDelegate);
1082 0 : if (device->IsSecureConnected())
1083 : {
1084 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerCommission);
1085 0 : ReturnErrorOnFailure(mDefaultCommissioner->StartCommissioning(this, device));
1086 : }
1087 : else
1088 : {
1089 0 : mRunCommissioningAfterConnection = true;
1090 : }
1091 0 : return CHIP_NO_ERROR;
1092 : }
1093 :
1094 : CHIP_ERROR
1095 0 : DeviceCommissioner::ContinueCommissioningAfterDeviceAttestation(DeviceProxy * device,
1096 : Credentials::AttestationVerificationResult attestationResult)
1097 : {
1098 : MATTER_TRACE_SCOPE("continueCommissioningDevice", "DeviceCommissioner");
1099 :
1100 0 : if (device == nullptr || device != mDeviceBeingCommissioned)
1101 : {
1102 0 : ChipLogError(Controller, "Invalid device for commissioning %p", device);
1103 0 : return CHIP_ERROR_INCORRECT_STATE;
1104 : }
1105 0 : CommissioneeDeviceProxy * commissioneeDevice = FindCommissioneeDevice(device->GetDeviceId());
1106 0 : if (commissioneeDevice == nullptr)
1107 : {
1108 0 : ChipLogError(Controller, "Couldn't find commissionee device");
1109 0 : return CHIP_ERROR_INCORRECT_STATE;
1110 : }
1111 0 : if (!commissioneeDevice->IsSecureConnected() || commissioneeDevice != mDeviceBeingCommissioned)
1112 : {
1113 0 : ChipLogError(Controller, "Invalid device for commissioning after attestation failure: 0x" ChipLogFormatX64,
1114 : ChipLogValueX64(commissioneeDevice->GetDeviceId()));
1115 0 : return CHIP_ERROR_INCORRECT_STATE;
1116 : }
1117 :
1118 0 : if (mCommissioningStage != CommissioningStage::kAttestationRevocationCheck)
1119 : {
1120 0 : ChipLogError(Controller, "Commissioning is not attestation verification phase");
1121 0 : return CHIP_ERROR_INCORRECT_STATE;
1122 : }
1123 :
1124 0 : ChipLogProgress(Controller, "Continuing commissioning after attestation failure for device ID 0x" ChipLogFormatX64,
1125 : ChipLogValueX64(commissioneeDevice->GetDeviceId()));
1126 :
1127 0 : if (attestationResult != AttestationVerificationResult::kSuccess)
1128 : {
1129 0 : ChipLogError(Controller, "Client selected error: %u for failed 'Attestation Information' for device",
1130 : to_underlying(attestationResult));
1131 :
1132 0 : CommissioningDelegate::CommissioningReport report;
1133 0 : report.Set<AttestationErrorInfo>(attestationResult);
1134 0 : CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
1135 0 : }
1136 : else
1137 : {
1138 0 : ChipLogProgress(Controller, "Overriding attestation failure per client and continuing commissioning");
1139 0 : CommissioningStageComplete(CHIP_NO_ERROR);
1140 : }
1141 0 : return CHIP_NO_ERROR;
1142 : }
1143 :
1144 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
1145 : CHIP_ERROR DeviceCommissioner::ContinueCommissioningAfterConnectNetworkRequest(NodeId remoteDeviceId)
1146 : {
1147 : MATTER_TRACE_SCOPE("continueCommissioningAfterConnectNetworkRequest", "DeviceCommissioner");
1148 :
1149 : // Move to kEvictPreviousCaseSessions stage since the next stage will be to find the device
1150 : // on the operational network
1151 : mCommissioningStage = CommissioningStage::kEvictPreviousCaseSessions;
1152 :
1153 : // Setup device being commissioned
1154 : CommissioneeDeviceProxy * device = nullptr;
1155 : if (!mDeviceBeingCommissioned)
1156 : {
1157 : device = mCommissioneeDevicePool.CreateObject();
1158 : if (!device)
1159 : return CHIP_ERROR_NO_MEMORY;
1160 :
1161 : Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
1162 : device->Init(GetControllerDeviceInitParams(), remoteDeviceId, peerAddress);
1163 : mDeviceBeingCommissioned = device;
1164 : }
1165 :
1166 : mDefaultCommissioner->SetOperationalCredentialsDelegate(mOperationalCredentialsDelegate);
1167 :
1168 : ChipLogProgress(Controller, "Continuing commissioning after connect to network complete for device ID 0x" ChipLogFormatX64,
1169 : ChipLogValueX64(remoteDeviceId));
1170 :
1171 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissioningOperationalSetup);
1172 : CHIP_ERROR err = mDefaultCommissioner->StartCommissioning(this, device);
1173 : if (err != CHIP_NO_ERROR)
1174 : {
1175 : MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, err);
1176 : }
1177 : return err;
1178 : }
1179 : #endif
1180 :
1181 0 : CHIP_ERROR DeviceCommissioner::StopPairing(NodeId remoteDeviceId)
1182 : {
1183 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1184 0 : VerifyOrReturnError(remoteDeviceId != kUndefinedNodeId, CHIP_ERROR_INVALID_ARGUMENT);
1185 :
1186 0 : ChipLogProgress(Controller, "StopPairing called for node ID 0x" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
1187 :
1188 : // If we're still in the process of discovering the device, just stop the SetUpCodePairer
1189 0 : if (mSetUpCodePairer.StopPairing(remoteDeviceId))
1190 : {
1191 0 : mRunCommissioningAfterConnection = false;
1192 0 : OnSessionEstablishmentError(CHIP_ERROR_CANCELLED);
1193 0 : return CHIP_NO_ERROR;
1194 : }
1195 :
1196 : // Otherwise we might be pairing and / or commissioning it.
1197 0 : CommissioneeDeviceProxy * device = FindCommissioneeDevice(remoteDeviceId);
1198 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR);
1199 :
1200 0 : if (mDeviceBeingCommissioned == device)
1201 : {
1202 0 : CancelCommissioningInteractions();
1203 0 : CommissioningStageComplete(CHIP_ERROR_CANCELLED);
1204 : }
1205 : else
1206 : {
1207 0 : ReleaseCommissioneeDevice(device);
1208 : }
1209 0 : return CHIP_NO_ERROR;
1210 : }
1211 :
1212 0 : void DeviceCommissioner::CancelCommissioningInteractions()
1213 : {
1214 0 : if (mReadClient)
1215 : {
1216 0 : ChipLogDetail(Controller, "Cancelling read request for step '%s'", StageToString(mCommissioningStage));
1217 0 : mReadClient.reset(); // destructor cancels
1218 0 : mAttributeCache.reset();
1219 : }
1220 0 : if (mInvokeCancelFn)
1221 : {
1222 0 : ChipLogDetail(Controller, "Cancelling command invocation for step '%s'", StageToString(mCommissioningStage));
1223 0 : mInvokeCancelFn();
1224 0 : mInvokeCancelFn = nullptr;
1225 : }
1226 0 : if (mWriteCancelFn)
1227 : {
1228 0 : ChipLogDetail(Controller, "Cancelling write request for step '%s'", StageToString(mCommissioningStage));
1229 0 : mWriteCancelFn();
1230 0 : mWriteCancelFn = nullptr;
1231 : }
1232 0 : if (mOnDeviceConnectedCallback.IsRegistered())
1233 : {
1234 0 : ChipLogDetail(Controller, "Cancelling CASE setup for step '%s'", StageToString(mCommissioningStage));
1235 0 : CancelCASECallbacks();
1236 : }
1237 0 : }
1238 :
1239 0 : void DeviceCommissioner::CancelCASECallbacks()
1240 : {
1241 0 : mOnDeviceConnectedCallback.Cancel();
1242 0 : mOnDeviceConnectionFailureCallback.Cancel();
1243 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
1244 0 : mOnDeviceConnectionRetryCallback.Cancel();
1245 : #endif
1246 0 : }
1247 :
1248 0 : CHIP_ERROR DeviceCommissioner::UnpairDevice(NodeId remoteDeviceId)
1249 : {
1250 : MATTER_TRACE_SCOPE("UnpairDevice", "DeviceCommissioner");
1251 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1252 :
1253 0 : return AutoCurrentFabricRemover::RemoveCurrentFabric(this, remoteDeviceId);
1254 : }
1255 :
1256 1 : void DeviceCommissioner::RendezvousCleanup(CHIP_ERROR status)
1257 : {
1258 1 : if (mDeviceInPASEEstablishment != nullptr)
1259 : {
1260 : // Release the commissionee device. For BLE, this is stored,
1261 : // for IP commissioning, we have taken a reference to the
1262 : // operational node to send the completion command.
1263 0 : ReleaseCommissioneeDevice(mDeviceInPASEEstablishment);
1264 :
1265 0 : if (mPairingDelegate != nullptr)
1266 : {
1267 0 : mPairingDelegate->OnPairingComplete(status, std::nullopt, std::nullopt);
1268 : }
1269 : }
1270 1 : }
1271 :
1272 1 : void DeviceCommissioner::OnSessionEstablishmentError(CHIP_ERROR err)
1273 : {
1274 : MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, err);
1275 :
1276 1 : mRendezvousParametersForPASEEstablishment.reset();
1277 :
1278 1 : if (mPairingDelegate != nullptr)
1279 : {
1280 0 : mPairingDelegate->OnStatusUpdate(DevicePairingDelegate::SecurePairingFailed);
1281 : }
1282 :
1283 1 : RendezvousCleanup(err);
1284 1 : }
1285 :
1286 0 : void DeviceCommissioner::OnSessionEstablished(const SessionHandle & session)
1287 : {
1288 : // PASE session established.
1289 0 : CommissioneeDeviceProxy * device = mDeviceInPASEEstablishment;
1290 :
1291 : // We are in the callback for this pairing. Reset so we can pair another device.
1292 0 : mDeviceInPASEEstablishment = nullptr;
1293 :
1294 : // Make sure to clear out mRendezvousParametersForPASEEstablishment no
1295 : // matter what.
1296 0 : std::optional<RendezvousParameters> paseParameters;
1297 0 : paseParameters.swap(mRendezvousParametersForPASEEstablishment);
1298 :
1299 0 : VerifyOrReturn(device != nullptr, OnSessionEstablishmentError(CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR));
1300 :
1301 0 : CHIP_ERROR err = device->SetConnected(session);
1302 0 : if (err != CHIP_NO_ERROR)
1303 : {
1304 0 : ChipLogError(Controller, "Failed in setting up secure channel: %" CHIP_ERROR_FORMAT, err.Format());
1305 0 : OnSessionEstablishmentError(err);
1306 0 : return;
1307 : }
1308 :
1309 0 : ChipLogDetail(Controller, "Remote device completed SPAKE2+ handshake");
1310 :
1311 : MATTER_LOG_METRIC_END(kMetricDeviceCommissionerPASESession, CHIP_NO_ERROR);
1312 0 : if (mPairingDelegate != nullptr)
1313 : {
1314 : // If we started with a string payload, then at this point mPairingDelegate is
1315 : // mSetUpCodePairer, and it will provide the right SetupPayload argument to
1316 : // OnPairingComplete as needed. If mPairingDelegate is not
1317 : // mSetUpCodePairer, then we don't have a SetupPayload to provide.
1318 0 : mPairingDelegate->OnPairingComplete(CHIP_NO_ERROR, paseParameters, std::nullopt);
1319 : }
1320 :
1321 0 : if (mRunCommissioningAfterConnection)
1322 : {
1323 0 : mRunCommissioningAfterConnection = false;
1324 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissionerCommission);
1325 0 : ReturnAndLogOnFailure(mDefaultCommissioner->StartCommissioning(this, device), Controller, "Failed to start commissioning");
1326 : }
1327 : }
1328 :
1329 0 : CHIP_ERROR DeviceCommissioner::SendCertificateChainRequestCommand(DeviceProxy * device,
1330 : Credentials::CertificateType certificateType,
1331 : Optional<System::Clock::Timeout> timeout)
1332 : {
1333 : MATTER_TRACE_SCOPE("SendCertificateChainRequestCommand", "DeviceCommissioner");
1334 0 : ChipLogDetail(Controller, "Sending Certificate Chain request to %p device", device);
1335 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1336 :
1337 0 : OperationalCredentials::Commands::CertificateChainRequest::Type request;
1338 0 : request.certificateType = static_cast<OperationalCredentials::CertificateChainTypeEnum>(certificateType);
1339 0 : return SendCommissioningCommand(device, request, OnCertificateChainResponse, OnCertificateChainFailureResponse, kRootEndpointId,
1340 0 : timeout);
1341 : }
1342 :
1343 0 : void DeviceCommissioner::OnCertificateChainFailureResponse(void * context, CHIP_ERROR error)
1344 : {
1345 : MATTER_TRACE_SCOPE("OnCertificateChainFailureResponse", "DeviceCommissioner");
1346 0 : ChipLogProgress(Controller, "Device failed to receive the Certificate Chain request Response: %" CHIP_ERROR_FORMAT,
1347 : error.Format());
1348 0 : DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
1349 0 : commissioner->CommissioningStageComplete(error);
1350 0 : }
1351 :
1352 0 : void DeviceCommissioner::OnCertificateChainResponse(
1353 : void * context, const chip::app::Clusters::OperationalCredentials::Commands::CertificateChainResponse::DecodableType & response)
1354 : {
1355 : MATTER_TRACE_SCOPE("OnCertificateChainResponse", "DeviceCommissioner");
1356 0 : ChipLogProgress(Controller, "Received certificate chain from the device");
1357 0 : DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
1358 :
1359 0 : CommissioningDelegate::CommissioningReport report;
1360 0 : report.Set<RequestedCertificate>(RequestedCertificate(response.certificate));
1361 :
1362 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
1363 0 : }
1364 :
1365 0 : CHIP_ERROR DeviceCommissioner::SendAttestationRequestCommand(DeviceProxy * device, const ByteSpan & attestationNonce,
1366 : Optional<System::Clock::Timeout> timeout)
1367 : {
1368 : MATTER_TRACE_SCOPE("SendAttestationRequestCommand", "DeviceCommissioner");
1369 0 : ChipLogDetail(Controller, "Sending Attestation request to %p device", device);
1370 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1371 :
1372 0 : OperationalCredentials::Commands::AttestationRequest::Type request;
1373 0 : request.attestationNonce = attestationNonce;
1374 :
1375 0 : ReturnErrorOnFailure(
1376 : SendCommissioningCommand(device, request, OnAttestationResponse, OnAttestationFailureResponse, kRootEndpointId, timeout));
1377 0 : ChipLogDetail(Controller, "Sent Attestation request, waiting for the Attestation Information");
1378 0 : return CHIP_NO_ERROR;
1379 : }
1380 :
1381 0 : void DeviceCommissioner::OnAttestationFailureResponse(void * context, CHIP_ERROR error)
1382 : {
1383 : MATTER_TRACE_SCOPE("OnAttestationFailureResponse", "DeviceCommissioner");
1384 0 : ChipLogProgress(Controller, "Device failed to receive the Attestation Information Response: %" CHIP_ERROR_FORMAT,
1385 : error.Format());
1386 0 : DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
1387 0 : commissioner->CommissioningStageComplete(error);
1388 0 : }
1389 :
1390 0 : void DeviceCommissioner::OnAttestationResponse(void * context,
1391 : const OperationalCredentials::Commands::AttestationResponse::DecodableType & data)
1392 : {
1393 : MATTER_TRACE_SCOPE("OnAttestationResponse", "DeviceCommissioner");
1394 0 : ChipLogProgress(Controller, "Received Attestation Information from the device");
1395 0 : DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
1396 :
1397 0 : CommissioningDelegate::CommissioningReport report;
1398 0 : report.Set<AttestationResponse>(AttestationResponse(data.attestationElements, data.attestationSignature));
1399 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
1400 0 : }
1401 :
1402 0 : void DeviceCommissioner::OnDeviceAttestationInformationVerification(
1403 : void * context, const Credentials::DeviceAttestationVerifier::AttestationInfo & info, AttestationVerificationResult result)
1404 : {
1405 : MATTER_TRACE_SCOPE("OnDeviceAttestationInformationVerification", "DeviceCommissioner");
1406 0 : DeviceCommissioner * commissioner = reinterpret_cast<DeviceCommissioner *>(context);
1407 :
1408 0 : if (commissioner->mCommissioningStage == CommissioningStage::kAttestationVerification)
1409 : {
1410 : // Check for revoked DAC Chain before calling delegate. Enter next stage.
1411 :
1412 0 : CommissioningDelegate::CommissioningReport report;
1413 0 : report.Set<AttestationErrorInfo>(result);
1414 :
1415 0 : return commissioner->CommissioningStageComplete(
1416 0 : result == AttestationVerificationResult::kSuccess ? CHIP_NO_ERROR : CHIP_ERROR_FAILED_DEVICE_ATTESTATION, report);
1417 0 : }
1418 :
1419 0 : if (!commissioner->mDeviceBeingCommissioned)
1420 : {
1421 0 : ChipLogError(Controller, "Device attestation verification result received when we're not commissioning a device");
1422 0 : return;
1423 : }
1424 :
1425 0 : auto & params = commissioner->mDefaultCommissioner->GetCommissioningParameters();
1426 0 : Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
1427 :
1428 0 : if (params.GetCompletionStatus().attestationResult.HasValue())
1429 : {
1430 0 : auto previousResult = params.GetCompletionStatus().attestationResult.Value();
1431 0 : if (previousResult != AttestationVerificationResult::kSuccess)
1432 : {
1433 0 : result = previousResult;
1434 : }
1435 : }
1436 :
1437 0 : if (result != AttestationVerificationResult::kSuccess)
1438 : {
1439 0 : CommissioningDelegate::CommissioningReport report;
1440 0 : report.Set<AttestationErrorInfo>(result);
1441 0 : if (result == AttestationVerificationResult::kNotImplemented)
1442 : {
1443 0 : ChipLogError(Controller,
1444 : "Failed in verifying 'Attestation Information' command received from the device due to default "
1445 : "DeviceAttestationVerifier Class not being overridden by a real implementation.");
1446 0 : commissioner->CommissioningStageComplete(CHIP_ERROR_NOT_IMPLEMENTED, report);
1447 0 : return;
1448 : }
1449 :
1450 0 : ChipLogError(Controller, "Failed in verifying 'Attestation Information' command received from the device: err %hu (%s)",
1451 : static_cast<uint16_t>(result), GetAttestationResultDescription(result));
1452 : // Go look at AttestationVerificationResult enum in src/credentials/attestation_verifier/DeviceAttestationVerifier.h to
1453 : // understand the errors.
1454 :
1455 : // If a device attestation status delegate is installed, delegate handling of failure to the client and let them
1456 : // decide on whether to proceed further or not.
1457 0 : if (deviceAttestationDelegate)
1458 : {
1459 0 : commissioner->ExtendArmFailSafeForDeviceAttestation(info, result);
1460 : }
1461 : else
1462 : {
1463 0 : commissioner->CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION, report);
1464 : }
1465 0 : }
1466 : else
1467 : {
1468 0 : if (deviceAttestationDelegate && deviceAttestationDelegate->ShouldWaitAfterDeviceAttestation())
1469 : {
1470 0 : commissioner->ExtendArmFailSafeForDeviceAttestation(info, result);
1471 : }
1472 : else
1473 : {
1474 0 : ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device.");
1475 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
1476 : }
1477 : }
1478 : }
1479 :
1480 0 : void DeviceCommissioner::OnArmFailSafeExtendedForDeviceAttestation(
1481 : void * context, const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType &)
1482 : {
1483 0 : ChipLogProgress(Controller, "Successfully extended fail-safe timer to handle DA failure");
1484 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1485 :
1486 : // We have completed our command invoke, but we're not going to finish the
1487 : // commissioning step until our client examines the attestation
1488 : // information. Clear out mInvokeCancelFn (which points at the
1489 : // CommandSender we just finished using) now, so it's not dangling.
1490 0 : commissioner->mInvokeCancelFn = nullptr;
1491 :
1492 0 : commissioner->HandleDeviceAttestationCompleted();
1493 0 : }
1494 :
1495 0 : void DeviceCommissioner::HandleDeviceAttestationCompleted()
1496 : {
1497 0 : if (!mDeviceBeingCommissioned)
1498 : {
1499 0 : return;
1500 : }
1501 :
1502 0 : auto & params = mDefaultCommissioner->GetCommissioningParameters();
1503 0 : Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
1504 0 : if (deviceAttestationDelegate)
1505 : {
1506 0 : ChipLogProgress(Controller, "Device attestation completed, delegating continuation to client");
1507 0 : deviceAttestationDelegate->OnDeviceAttestationCompleted(this, mDeviceBeingCommissioned, *mAttestationDeviceInfo,
1508 : mAttestationResult);
1509 : }
1510 : else
1511 : {
1512 0 : ChipLogError(Controller, "Need to wait for device attestation delegate, but no delegate available. Failing commissioning");
1513 0 : CommissioningDelegate::CommissioningReport report;
1514 0 : report.Set<AttestationErrorInfo>(mAttestationResult);
1515 0 : CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
1516 0 : }
1517 : }
1518 :
1519 0 : void DeviceCommissioner::OnFailedToExtendedArmFailSafeDeviceAttestation(void * context, CHIP_ERROR error)
1520 : {
1521 0 : ChipLogProgress(Controller, "Failed to extend fail-safe timer to handle attestation failure: %" CHIP_ERROR_FORMAT,
1522 : error.Format());
1523 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1524 :
1525 0 : CommissioningDelegate::CommissioningReport report;
1526 0 : report.Set<AttestationErrorInfo>(commissioner->mAttestationResult);
1527 0 : commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
1528 0 : }
1529 :
1530 0 : void DeviceCommissioner::OnICDManagementRegisterClientResponse(
1531 : void * context, const app::Clusters::IcdManagement::Commands::RegisterClientResponse::DecodableType & data)
1532 : {
1533 0 : CHIP_ERROR err = CHIP_NO_ERROR;
1534 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1535 0 : VerifyOrExit(commissioner != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
1536 0 : VerifyOrExit(commissioner->mCommissioningStage == CommissioningStage::kICDRegistration, err = CHIP_ERROR_INCORRECT_STATE);
1537 0 : VerifyOrExit(commissioner->mDeviceBeingCommissioned != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1538 :
1539 0 : if (commissioner->mPairingDelegate != nullptr)
1540 : {
1541 0 : commissioner->mPairingDelegate->OnICDRegistrationComplete(
1542 0 : ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()), data.ICDCounter);
1543 : }
1544 :
1545 0 : exit:
1546 0 : CommissioningDelegate::CommissioningReport report;
1547 0 : commissioner->CommissioningStageComplete(err, report);
1548 0 : }
1549 :
1550 0 : void DeviceCommissioner::OnICDManagementStayActiveResponse(
1551 : void * context, const app::Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType & data)
1552 : {
1553 0 : CHIP_ERROR err = CHIP_NO_ERROR;
1554 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1555 0 : VerifyOrExit(commissioner != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
1556 0 : VerifyOrExit(commissioner->mCommissioningStage == CommissioningStage::kICDSendStayActive, err = CHIP_ERROR_INCORRECT_STATE);
1557 0 : VerifyOrExit(commissioner->mDeviceBeingCommissioned != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1558 :
1559 0 : if (commissioner->mPairingDelegate != nullptr)
1560 : {
1561 0 : commissioner->mPairingDelegate->OnICDStayActiveComplete(
1562 :
1563 0 : ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()),
1564 0 : data.promisedActiveDuration);
1565 : }
1566 :
1567 0 : exit:
1568 0 : CommissioningDelegate::CommissioningReport report;
1569 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
1570 0 : }
1571 :
1572 0 : bool DeviceCommissioner::ExtendArmFailSafeInternal(DeviceProxy * proxy, CommissioningStage step, uint16_t armFailSafeTimeout,
1573 : Optional<System::Clock::Timeout> commandTimeout,
1574 : OnExtendFailsafeSuccess onSuccess, OnExtendFailsafeFailure onFailure,
1575 : bool fireAndForget)
1576 : {
1577 : using namespace System;
1578 : using namespace System::Clock;
1579 0 : auto now = SystemClock().GetMonotonicTimestamp();
1580 0 : auto newFailSafeTimeout = now + Seconds16(armFailSafeTimeout);
1581 0 : if (newFailSafeTimeout < proxy->GetFailSafeExpirationTimestamp())
1582 : {
1583 0 : ChipLogProgress(
1584 : Controller, "Skipping arming failsafe: new time (%u seconds from now) before old time (%u seconds from now)",
1585 : armFailSafeTimeout, std::chrono::duration_cast<Seconds16>(proxy->GetFailSafeExpirationTimestamp() - now).count());
1586 0 : return false;
1587 : }
1588 :
1589 0 : uint64_t breadcrumb = static_cast<uint64_t>(step);
1590 0 : GeneralCommissioning::Commands::ArmFailSafe::Type request;
1591 0 : request.expiryLengthSeconds = armFailSafeTimeout;
1592 0 : request.breadcrumb = breadcrumb;
1593 0 : ChipLogProgress(Controller, "Arming failsafe (%u seconds)", request.expiryLengthSeconds);
1594 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, onSuccess, onFailure, kRootEndpointId, commandTimeout, fireAndForget);
1595 0 : if (err != CHIP_NO_ERROR)
1596 : {
1597 0 : onFailure((!fireAndForget) ? this : nullptr, err);
1598 0 : return true; // we have called onFailure already
1599 : }
1600 :
1601 : // Note: The stored timestamp may become invalid if we fail asynchronously
1602 0 : proxy->SetFailSafeExpirationTimestamp(newFailSafeTimeout);
1603 0 : return true;
1604 : }
1605 :
1606 0 : void DeviceCommissioner::ExtendArmFailSafeForDeviceAttestation(const Credentials::DeviceAttestationVerifier::AttestationInfo & info,
1607 : Credentials::AttestationVerificationResult result)
1608 : {
1609 0 : mAttestationResult = result;
1610 :
1611 0 : auto & params = mDefaultCommissioner->GetCommissioningParameters();
1612 0 : Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
1613 :
1614 0 : mAttestationDeviceInfo = Platform::MakeUnique<Credentials::DeviceAttestationVerifier::AttestationDeviceInfo>(info);
1615 :
1616 0 : auto expiryLengthSeconds = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs();
1617 0 : bool waitForFailsafeExtension = expiryLengthSeconds.HasValue();
1618 0 : if (waitForFailsafeExtension)
1619 : {
1620 0 : ChipLogProgress(Controller, "Changing fail-safe timer to %u seconds to handle DA failure", expiryLengthSeconds.Value());
1621 : // Per spec, anything we do with the fail-safe armed must not time out
1622 : // in less than kMinimumCommissioningStepTimeout.
1623 : waitForFailsafeExtension =
1624 0 : ExtendArmFailSafeInternal(mDeviceBeingCommissioned, mCommissioningStage, expiryLengthSeconds.Value(),
1625 0 : MakeOptional(kMinimumCommissioningStepTimeout), OnArmFailSafeExtendedForDeviceAttestation,
1626 : OnFailedToExtendedArmFailSafeDeviceAttestation, /* fireAndForget = */ false);
1627 : }
1628 : else
1629 : {
1630 0 : ChipLogProgress(Controller, "Proceeding without changing fail-safe timer value as delegate has not set it");
1631 : }
1632 :
1633 0 : if (!waitForFailsafeExtension)
1634 : {
1635 0 : HandleDeviceAttestationCompleted();
1636 : }
1637 0 : }
1638 :
1639 0 : CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
1640 : {
1641 : MATTER_TRACE_SCOPE("ValidateAttestationInfo", "DeviceCommissioner");
1642 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1643 0 : VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
1644 :
1645 0 : mDeviceAttestationVerifier->VerifyAttestationInformation(info, &mDeviceAttestationInformationVerificationCallback);
1646 :
1647 : // TODO: Validate Firmware Information
1648 :
1649 0 : return CHIP_NO_ERROR;
1650 : }
1651 :
1652 : CHIP_ERROR
1653 0 : DeviceCommissioner::CheckForRevokedDACChain(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
1654 : {
1655 : MATTER_TRACE_SCOPE("CheckForRevokedDACChain", "DeviceCommissioner");
1656 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1657 0 : VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
1658 :
1659 0 : mDeviceAttestationVerifier->CheckForRevokedDACChain(info, &mDeviceAttestationInformationVerificationCallback);
1660 :
1661 0 : return CHIP_NO_ERROR;
1662 : }
1663 :
1664 0 : CHIP_ERROR DeviceCommissioner::ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
1665 : const ByteSpan & AttestationSignature, const ByteSpan & dac, const ByteSpan & csrNonce)
1666 : {
1667 : MATTER_TRACE_SCOPE("ValidateCSR", "DeviceCommissioner");
1668 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1669 0 : VerifyOrReturnError(mDeviceAttestationVerifier != nullptr, CHIP_ERROR_INCORRECT_STATE);
1670 :
1671 0 : P256PublicKey dacPubkey;
1672 0 : ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));
1673 :
1674 : // Retrieve attestation challenge
1675 : ByteSpan attestationChallenge =
1676 0 : proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();
1677 :
1678 : // The operational CA should also verify this on its end during NOC generation, if end-to-end attestation is desired.
1679 0 : return mDeviceAttestationVerifier->VerifyNodeOperationalCSRInformation(NOCSRElements, attestationChallenge,
1680 0 : AttestationSignature, dacPubkey, csrNonce);
1681 0 : }
1682 :
1683 0 : CHIP_ERROR DeviceCommissioner::SendOperationalCertificateSigningRequestCommand(DeviceProxy * device, const ByteSpan & csrNonce,
1684 : Optional<System::Clock::Timeout> timeout)
1685 : {
1686 : MATTER_TRACE_SCOPE("SendOperationalCertificateSigningRequestCommand", "DeviceCommissioner");
1687 0 : ChipLogDetail(Controller, "Sending CSR request to %p device", device);
1688 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1689 :
1690 0 : OperationalCredentials::Commands::CSRRequest::Type request;
1691 0 : request.CSRNonce = csrNonce;
1692 :
1693 0 : ReturnErrorOnFailure(SendCommissioningCommand(device, request, OnOperationalCertificateSigningRequest, OnCSRFailureResponse,
1694 : kRootEndpointId, timeout));
1695 0 : ChipLogDetail(Controller, "Sent CSR request, waiting for the CSR");
1696 0 : return CHIP_NO_ERROR;
1697 : }
1698 :
1699 0 : void DeviceCommissioner::OnCSRFailureResponse(void * context, CHIP_ERROR error)
1700 : {
1701 : MATTER_TRACE_SCOPE("OnCSRFailureResponse", "DeviceCommissioner");
1702 0 : ChipLogProgress(Controller, "Device failed to receive the CSR request Response: %" CHIP_ERROR_FORMAT, error.Format());
1703 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1704 0 : commissioner->CommissioningStageComplete(error);
1705 0 : }
1706 :
1707 0 : void DeviceCommissioner::OnOperationalCertificateSigningRequest(
1708 : void * context, const OperationalCredentials::Commands::CSRResponse::DecodableType & data)
1709 : {
1710 : MATTER_TRACE_SCOPE("OnOperationalCertificateSigningRequest", "DeviceCommissioner");
1711 0 : ChipLogProgress(Controller, "Received certificate signing request from the device");
1712 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1713 :
1714 0 : CommissioningDelegate::CommissioningReport report;
1715 0 : report.Set<CSRResponse>(CSRResponse(data.NOCSRElements, data.attestationSignature));
1716 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
1717 0 : }
1718 :
1719 0 : void DeviceCommissioner::OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const ByteSpan & noc, const ByteSpan & icac,
1720 : const ByteSpan & rcac, Optional<IdentityProtectionKeySpan> ipk,
1721 : Optional<NodeId> adminSubject)
1722 : {
1723 : MATTER_TRACE_SCOPE("OnDeviceNOCChainGeneration", "DeviceCommissioner");
1724 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1725 :
1726 : // The placeholder IPK is not satisfactory, but is there to fill the NocChain struct on error. It will still fail.
1727 0 : const uint8_t placeHolderIpk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1728 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1729 0 : if (status == CHIP_NO_ERROR && !ipk.HasValue())
1730 : {
1731 0 : ChipLogError(Controller, "Did not have an IPK from the OperationalCredentialsIssuer! Cannot commission.");
1732 0 : status = CHIP_ERROR_INVALID_ARGUMENT;
1733 : }
1734 :
1735 0 : ChipLogProgress(Controller, "Received callback from the CA for NOC Chain generation. Status: %" CHIP_ERROR_FORMAT,
1736 : status.Format());
1737 0 : if (status == CHIP_NO_ERROR && commissioner->mState != State::Initialized)
1738 : {
1739 0 : status = CHIP_ERROR_INCORRECT_STATE;
1740 : }
1741 0 : if (status != CHIP_NO_ERROR)
1742 : {
1743 0 : ChipLogError(Controller, "Failed in generating device's operational credentials. Error: %" CHIP_ERROR_FORMAT,
1744 : status.Format());
1745 : }
1746 :
1747 : // TODO - Verify that the generated root cert matches with commissioner's root cert
1748 0 : CommissioningDelegate::CommissioningReport report;
1749 0 : report.Set<NocChain>(NocChain(noc, icac, rcac, ipk.HasValue() ? ipk.Value() : IdentityProtectionKeySpan(placeHolderIpk),
1750 0 : adminSubject.HasValue() ? adminSubject.Value() : commissioner->GetNodeId()));
1751 0 : commissioner->CommissioningStageComplete(status, report);
1752 0 : }
1753 :
1754 0 : CHIP_ERROR DeviceCommissioner::IssueNOCChain(const ByteSpan & NOCSRElements, NodeId nodeId,
1755 : chip::Callback::Callback<OnNOCChainGeneration> * callback)
1756 : {
1757 : MATTER_TRACE_SCOPE("IssueNOCChain", "DeviceCommissioner");
1758 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1759 :
1760 0 : ChipLogProgress(Controller, "Getting certificate chain for the device on fabric idx %u", static_cast<unsigned>(mFabricIndex));
1761 :
1762 0 : mOperationalCredentialsDelegate->SetNodeIdForNextNOCRequest(nodeId);
1763 :
1764 0 : if (mFabricIndex != kUndefinedFabricIndex)
1765 : {
1766 0 : mOperationalCredentialsDelegate->SetFabricIdForNextNOCRequest(GetFabricId());
1767 : }
1768 :
1769 : // Note: we don't have attestationSignature, attestationChallenge, DAC, PAI so we are just providing an empty ByteSpan
1770 : // for those arguments.
1771 0 : return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, ByteSpan(), ByteSpan(), ByteSpan(), ByteSpan(),
1772 0 : ByteSpan(), callback);
1773 : }
1774 :
1775 0 : CHIP_ERROR DeviceCommissioner::ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
1776 : const ByteSpan & AttestationSignature, const ByteSpan & dac, const ByteSpan & pai,
1777 : const ByteSpan & csrNonce)
1778 : {
1779 : MATTER_TRACE_SCOPE("ProcessOpCSR", "DeviceCommissioner");
1780 0 : VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
1781 :
1782 0 : ChipLogProgress(Controller, "Getting certificate chain for the device from the issuer");
1783 :
1784 0 : P256PublicKey dacPubkey;
1785 0 : ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));
1786 :
1787 : // Retrieve attestation challenge
1788 : ByteSpan attestationChallenge =
1789 0 : proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();
1790 :
1791 0 : mOperationalCredentialsDelegate->SetNodeIdForNextNOCRequest(proxy->GetDeviceId());
1792 :
1793 0 : if (mFabricIndex != kUndefinedFabricIndex)
1794 : {
1795 0 : mOperationalCredentialsDelegate->SetFabricIdForNextNOCRequest(GetFabricId());
1796 : }
1797 :
1798 0 : return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, csrNonce, AttestationSignature, attestationChallenge,
1799 0 : dac, pai, &mDeviceNOCChainCallback);
1800 0 : }
1801 :
1802 0 : CHIP_ERROR DeviceCommissioner::SendOperationalCertificate(DeviceProxy * device, const ByteSpan & nocCertBuf,
1803 : const Optional<ByteSpan> & icaCertBuf,
1804 : const IdentityProtectionKeySpan ipk, const NodeId adminSubject,
1805 : Optional<System::Clock::Timeout> timeout)
1806 : {
1807 : MATTER_TRACE_SCOPE("SendOperationalCertificate", "DeviceCommissioner");
1808 :
1809 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1810 :
1811 0 : OperationalCredentials::Commands::AddNOC::Type request;
1812 0 : request.NOCValue = nocCertBuf;
1813 0 : request.ICACValue = icaCertBuf;
1814 0 : request.IPKValue = ipk;
1815 0 : request.caseAdminSubject = adminSubject;
1816 0 : request.adminVendorId = mVendorId;
1817 :
1818 0 : ReturnErrorOnFailure(SendCommissioningCommand(device, request, OnOperationalCertificateAddResponse, OnAddNOCFailureResponse,
1819 : kRootEndpointId, timeout));
1820 :
1821 0 : ChipLogProgress(Controller, "Sent operational certificate to the device");
1822 :
1823 0 : return CHIP_NO_ERROR;
1824 : }
1825 :
1826 0 : CHIP_ERROR DeviceCommissioner::ConvertFromOperationalCertStatus(OperationalCredentials::NodeOperationalCertStatusEnum err)
1827 : {
1828 : using OperationalCredentials::NodeOperationalCertStatusEnum;
1829 0 : switch (err)
1830 : {
1831 0 : case NodeOperationalCertStatusEnum::kOk:
1832 0 : return CHIP_NO_ERROR;
1833 0 : case NodeOperationalCertStatusEnum::kInvalidPublicKey:
1834 0 : return CHIP_ERROR_INVALID_PUBLIC_KEY;
1835 0 : case NodeOperationalCertStatusEnum::kInvalidNodeOpId:
1836 0 : return CHIP_ERROR_WRONG_NODE_ID;
1837 0 : case NodeOperationalCertStatusEnum::kInvalidNOC:
1838 0 : return CHIP_ERROR_UNSUPPORTED_CERT_FORMAT;
1839 0 : case NodeOperationalCertStatusEnum::kMissingCsr:
1840 0 : return CHIP_ERROR_INCORRECT_STATE;
1841 0 : case NodeOperationalCertStatusEnum::kTableFull:
1842 0 : return CHIP_ERROR_NO_MEMORY;
1843 0 : case NodeOperationalCertStatusEnum::kInvalidAdminSubject:
1844 0 : return CHIP_ERROR_INVALID_ADMIN_SUBJECT;
1845 0 : case NodeOperationalCertStatusEnum::kFabricConflict:
1846 0 : return CHIP_ERROR_FABRIC_EXISTS;
1847 0 : case NodeOperationalCertStatusEnum::kLabelConflict:
1848 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1849 0 : case NodeOperationalCertStatusEnum::kInvalidFabricIndex:
1850 0 : return CHIP_ERROR_INVALID_FABRIC_INDEX;
1851 0 : case NodeOperationalCertStatusEnum::kUnknownEnumValue:
1852 : // Is this a reasonable value?
1853 0 : return CHIP_ERROR_CERT_LOAD_FAILED;
1854 : }
1855 :
1856 0 : return CHIP_ERROR_CERT_LOAD_FAILED;
1857 : }
1858 :
1859 0 : void DeviceCommissioner::OnAddNOCFailureResponse(void * context, CHIP_ERROR error)
1860 : {
1861 : MATTER_TRACE_SCOPE("OnAddNOCFailureResponse", "DeviceCommissioner");
1862 0 : ChipLogProgress(Controller, "Device failed to receive the operational certificate Response: %" CHIP_ERROR_FORMAT,
1863 : error.Format());
1864 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1865 0 : commissioner->CommissioningStageComplete(error);
1866 0 : }
1867 :
1868 0 : void DeviceCommissioner::OnOperationalCertificateAddResponse(
1869 : void * context, const OperationalCredentials::Commands::NOCResponse::DecodableType & data)
1870 : {
1871 : MATTER_TRACE_SCOPE("OnOperationalCertificateAddResponse", "DeviceCommissioner");
1872 0 : ChipLogProgress(Controller, "Device returned status %d on receiving the NOC", to_underlying(data.statusCode));
1873 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1874 :
1875 0 : CHIP_ERROR err = CHIP_NO_ERROR;
1876 :
1877 0 : VerifyOrExit(commissioner->mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE);
1878 :
1879 0 : VerifyOrExit(commissioner->mDeviceBeingCommissioned != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1880 :
1881 0 : err = ConvertFromOperationalCertStatus(data.statusCode);
1882 0 : SuccessOrExit(err);
1883 :
1884 0 : err = commissioner->OnOperationalCredentialsProvisioningCompletion(commissioner->mDeviceBeingCommissioned);
1885 :
1886 0 : exit:
1887 0 : if (err != CHIP_NO_ERROR)
1888 : {
1889 0 : ChipLogProgress(Controller, "Add NOC failed with error: %" CHIP_ERROR_FORMAT, err.Format());
1890 : // Preserve the device-reported NodeOperationalCertStatusEnum (kInvalidPublicKey,
1891 : // kInvalidNodeOpId, kInvalidNOC, kFabricConflict, kLabelConflict, kInvalidFabricIndex,
1892 : // kTableFull, etc.) in the report so OnCommissioningFailure consumers can distinguish
1893 : // these without losing fidelity to the generic CHIP_ERROR returned by
1894 : // ConvertFromOperationalCertStatus.
1895 0 : CommissioningDelegate::CommissioningReport report;
1896 : // ConvertFromOperationalCertStatus succeeds on kOk and returns a non-success CHIP_ERROR
1897 : // for any other value, but `err` at this point can also be a downstream local failure
1898 : // (e.g. from OnOperationalCredentialsProvisioningCompletion) while data.statusCode is
1899 : // still kOk. Guard so we never publish a "success enum" alongside a non-success err to
1900 : // OnCommissioningFailure consumers.
1901 0 : if (data.statusCode != OperationalCredentials::NodeOperationalCertStatusEnum::kOk)
1902 : {
1903 0 : report.Set<OperationalCertErrorInfo>(data.statusCode);
1904 : }
1905 0 : commissioner->CommissioningStageComplete(err, report);
1906 0 : }
1907 0 : }
1908 :
1909 0 : CHIP_ERROR DeviceCommissioner::SendTrustedRootCertificate(DeviceProxy * device, const ByteSpan & rcac,
1910 : Optional<System::Clock::Timeout> timeout)
1911 : {
1912 : MATTER_TRACE_SCOPE("SendTrustedRootCertificate", "DeviceCommissioner");
1913 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1914 :
1915 0 : ChipLogProgress(Controller, "Sending root certificate to the device");
1916 :
1917 0 : OperationalCredentials::Commands::AddTrustedRootCertificate::Type request;
1918 0 : request.rootCACertificate = rcac;
1919 0 : ReturnErrorOnFailure(
1920 : SendCommissioningCommand(device, request, OnRootCertSuccessResponse, OnRootCertFailureResponse, kRootEndpointId, timeout));
1921 :
1922 0 : ChipLogProgress(Controller, "Sent root certificate to the device");
1923 :
1924 0 : return CHIP_NO_ERROR;
1925 : }
1926 :
1927 0 : void DeviceCommissioner::OnRootCertSuccessResponse(void * context, const chip::app::DataModel::NullObjectType &)
1928 : {
1929 : MATTER_TRACE_SCOPE("OnRootCertSuccessResponse", "DeviceCommissioner");
1930 0 : ChipLogProgress(Controller, "Device confirmed that it has received the root certificate");
1931 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1932 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
1933 0 : }
1934 :
1935 0 : void DeviceCommissioner::OnRootCertFailureResponse(void * context, CHIP_ERROR error)
1936 : {
1937 : MATTER_TRACE_SCOPE("OnRootCertFailureResponse", "DeviceCommissioner");
1938 0 : ChipLogProgress(Controller, "Device failed to receive the root certificate Response: %" CHIP_ERROR_FORMAT, error.Format());
1939 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1940 0 : commissioner->CommissioningStageComplete(error);
1941 0 : }
1942 :
1943 0 : CHIP_ERROR DeviceCommissioner::OnOperationalCredentialsProvisioningCompletion(DeviceProxy * device)
1944 : {
1945 : MATTER_TRACE_SCOPE("OnOperationalCredentialsProvisioningCompletion", "DeviceCommissioner");
1946 0 : ChipLogProgress(Controller, "Operational credentials provisioned on device %p", device);
1947 0 : VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1948 :
1949 0 : if (mPairingDelegate != nullptr)
1950 : {
1951 0 : mPairingDelegate->OnStatusUpdate(DevicePairingDelegate::SecurePairingSuccess);
1952 : }
1953 0 : CommissioningStageComplete(CHIP_NO_ERROR);
1954 :
1955 0 : return CHIP_NO_ERROR;
1956 : }
1957 :
1958 : #if CONFIG_NETWORK_LAYER_BLE
1959 : #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
1960 : void DeviceCommissioner::ConnectBleTransportToSelf()
1961 : {
1962 : Transport::BLEBase & transport = std::get<Transport::BLE<1>>(mSystemState->TransportMgr()->GetTransport().GetTransports());
1963 : if (!transport.IsBleLayerTransportSetToSelf())
1964 : {
1965 : transport.SetBleLayerTransportToSelf();
1966 : }
1967 : }
1968 : #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
1969 :
1970 0 : void DeviceCommissioner::CloseBleConnection()
1971 : {
1972 : // It is fine since we can only commission one device at the same time.
1973 : // We should be able to distinguish different BLE connections if we want
1974 : // to commission multiple devices at the same time over BLE.
1975 0 : mSystemState->BleLayer()->CloseAllBleConnections();
1976 0 : }
1977 : #endif
1978 :
1979 0 : CHIP_ERROR DeviceCommissioner::DiscoverCommissionableNodes(Dnssd::DiscoveryFilter filter)
1980 : {
1981 0 : ReturnErrorOnFailure(SetUpNodeDiscovery());
1982 0 : return mDNSResolver.DiscoverCommissionableNodes(filter);
1983 : }
1984 :
1985 2 : CHIP_ERROR DeviceCommissioner::StopCommissionableDiscovery()
1986 : {
1987 2 : return mDNSResolver.StopDiscovery();
1988 : }
1989 :
1990 0 : const Dnssd::CommissionNodeData * DeviceCommissioner::GetDiscoveredDevice(int idx)
1991 : {
1992 0 : return GetDiscoveredNode(idx);
1993 : }
1994 :
1995 : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY // make this commissioner discoverable
1996 :
1997 : CHIP_ERROR DeviceCommissioner::SetUdcListenPort(uint16_t listenPort)
1998 : {
1999 : if (mState == State::Initialized)
2000 : {
2001 : return CHIP_ERROR_INCORRECT_STATE;
2002 : }
2003 :
2004 : mUdcListenPort = listenPort;
2005 : return CHIP_NO_ERROR;
2006 : }
2007 :
2008 : void DeviceCommissioner::FindCommissionableNode(const char * instanceName)
2009 : {
2010 : Dnssd::DiscoveryFilter filter(Dnssd::DiscoveryFilterType::kInstanceName, instanceName);
2011 : TEMPORARY_RETURN_IGNORED DiscoverCommissionableNodes(filter);
2012 : }
2013 :
2014 : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
2015 :
2016 0 : void DeviceCommissioner::OnNodeDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData)
2017 : {
2018 : #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
2019 : if (mUdcServer != nullptr)
2020 : {
2021 : mUdcServer->OnCommissionableNodeFound(nodeData);
2022 : }
2023 : #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
2024 0 : if (nodeData.Get<Dnssd::CommissionNodeData>().threadMeshcop)
2025 : {
2026 0 : mAutoCommissioner.SetNetworkSetupNeeded(true);
2027 : }
2028 0 : AbstractDnssdDiscoveryController::OnNodeDiscovered(nodeData);
2029 0 : mSetUpCodePairer.NotifyCommissionableDeviceDiscovered(nodeData);
2030 0 : }
2031 :
2032 0 : void DeviceCommissioner::OnBasicSuccess(void * context, const chip::app::DataModel::NullObjectType &)
2033 : {
2034 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2035 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
2036 0 : }
2037 :
2038 0 : void DeviceCommissioner::OnBasicFailure(void * context, CHIP_ERROR error)
2039 : {
2040 0 : ChipLogProgress(Controller, "Received failure response: %" CHIP_ERROR_FORMAT, error.Format());
2041 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2042 0 : commissioner->CommissioningStageComplete(error);
2043 0 : }
2044 :
2045 0 : static GeneralCommissioning::Commands::ArmFailSafe::Type DisarmFailsafeRequest()
2046 : {
2047 0 : GeneralCommissioning::Commands::ArmFailSafe::Type request;
2048 0 : request.expiryLengthSeconds = 0; // Expire immediately.
2049 0 : request.breadcrumb = 0;
2050 0 : return request;
2051 : }
2052 :
2053 0 : static void MarkForEviction(const Optional<SessionHandle> & session)
2054 : {
2055 0 : if (session.HasValue())
2056 : {
2057 0 : session.Value()->AsSecureSession()->MarkForEviction();
2058 : }
2059 0 : }
2060 :
2061 0 : void DeviceCommissioner::CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus)
2062 : {
2063 : // At this point, proxy == mDeviceBeingCommissioned, nodeId == mDeviceBeingCommissioned->GetDeviceId()
2064 :
2065 0 : mCommissioningCompletionStatus = completionStatus;
2066 :
2067 0 : if (completionStatus.err == CHIP_NO_ERROR)
2068 : {
2069 : // CommissioningStageComplete uses mDeviceBeingCommissioned, which can
2070 : // be commissionee if we are cleaning up before we've gone operational. Normally
2071 : // that would not happen in this non-error case, _except_ if we were told to skip sending
2072 : // CommissioningComplete: in that case we do not have an operational DeviceProxy, so
2073 : // we're using our CommissioneeDeviceProxy to do a successful cleanup.
2074 : //
2075 : // This means we have to call CommissioningStageComplete() before we destroy commissionee.
2076 : //
2077 : // This should be safe, because CommissioningStageComplete() does not call CleanupCommissioning
2078 : // when called in the cleanup stage (which is where we are), and StopPairing does not directly release
2079 : // mDeviceBeingCommissioned.
2080 0 : CommissioningStageComplete(CHIP_NO_ERROR);
2081 :
2082 0 : CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
2083 0 : if (commissionee != nullptr)
2084 : {
2085 0 : ReleaseCommissioneeDevice(commissionee);
2086 : }
2087 : // Send the callbacks, we're done.
2088 0 : SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
2089 : }
2090 0 : else if (completionStatus.err == CHIP_ERROR_CANCELLED)
2091 : {
2092 : // If we're cleaning up because cancellation has been requested via StopPairing(), expire the failsafe
2093 : // in the background and reset our state synchronously, so a new commissioning attempt can be started.
2094 0 : CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
2095 0 : SessionHolder session((commissionee == proxy) ? commissionee->DetachSecureSession().Value()
2096 0 : : proxy->GetSecureSession().Value());
2097 :
2098 0 : auto request = DisarmFailsafeRequest();
2099 0 : auto onSuccessCb = [session](const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatus,
2100 : const decltype(request)::ResponseType & responseData) {
2101 0 : ChipLogProgress(Controller, "Failsafe disarmed");
2102 0 : MarkForEviction(session.Get());
2103 0 : };
2104 0 : auto onFailureCb = [session](CHIP_ERROR aError) {
2105 0 : ChipLogProgress(Controller, "Ignoring failure to disarm failsafe: %" CHIP_ERROR_FORMAT, aError.Format());
2106 0 : MarkForEviction(session.Get());
2107 0 : };
2108 :
2109 0 : ChipLogProgress(Controller, "Disarming failsafe on device %p in background", proxy);
2110 0 : CHIP_ERROR err = InvokeCommandRequest(proxy->GetExchangeManager(), session.Get().Value(), kRootEndpointId, request,
2111 : onSuccessCb, onFailureCb);
2112 0 : if (err != CHIP_NO_ERROR)
2113 : {
2114 0 : ChipLogError(Controller, "Failed to send command to disarm fail-safe: %" CHIP_ERROR_FORMAT, err.Format());
2115 : }
2116 :
2117 0 : CleanupDoneAfterError();
2118 0 : }
2119 0 : else if (completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup)
2120 : {
2121 : // If we were already doing network setup, we need to retain the pase session and start again from network setup stage.
2122 : // We do not need to reset the failsafe here because we want to keep everything on the device up to this point, so just
2123 : // send the completion callbacks (see "Commissioning Flows Error Handling" in the spec).
2124 0 : CommissioningStageComplete(CHIP_NO_ERROR);
2125 0 : SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
2126 : }
2127 : else
2128 : {
2129 : // If we've failed somewhere in the early stages (or we don't have a failedStage specified), we need to start from the
2130 : // beginning. However, because some of the commands can only be sent once per arm-failsafe, we also need to force a reset on
2131 : // the failsafe so we can start fresh on the next attempt.
2132 0 : ChipLogProgress(Controller, "Disarming failsafe on device %p", proxy);
2133 0 : auto request = DisarmFailsafeRequest();
2134 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnDisarmFailsafe, OnDisarmFailsafeFailure, kRootEndpointId);
2135 0 : if (err != CHIP_NO_ERROR)
2136 : {
2137 : // We won't get any async callbacks here, so just pretend like the command errored out async.
2138 0 : ChipLogError(Controller, "Failed to send command to disarm fail-safe: %" CHIP_ERROR_FORMAT, err.Format());
2139 0 : CleanupDoneAfterError();
2140 : }
2141 : }
2142 0 : }
2143 :
2144 0 : void DeviceCommissioner::OnDisarmFailsafe(void * context,
2145 : const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
2146 : {
2147 0 : ChipLogProgress(Controller, "Failsafe disarmed");
2148 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2149 0 : commissioner->CleanupDoneAfterError();
2150 0 : }
2151 :
2152 0 : void DeviceCommissioner::OnDisarmFailsafeFailure(void * context, CHIP_ERROR error)
2153 : {
2154 0 : ChipLogProgress(Controller, "Ignoring failure to disarm failsafe: %" CHIP_ERROR_FORMAT, error.Format());
2155 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2156 0 : commissioner->CleanupDoneAfterError();
2157 0 : }
2158 :
2159 0 : void DeviceCommissioner::CleanupDoneAfterError()
2160 : {
2161 : // If someone nulled out our mDeviceBeingCommissioned, there's nothing else
2162 : // to do here.
2163 0 : VerifyOrReturn(mDeviceBeingCommissioned != nullptr);
2164 :
2165 0 : NodeId nodeId = mDeviceBeingCommissioned->GetDeviceId();
2166 :
2167 : // Signal completion - this will reset mDeviceBeingCommissioned.
2168 0 : CommissioningStageComplete(CHIP_NO_ERROR);
2169 :
2170 : // At this point, we also want to close off the pase session so we need to re-establish
2171 0 : CommissioneeDeviceProxy * commissionee = FindCommissioneeDevice(nodeId);
2172 :
2173 : // If we've disarmed the failsafe, it's because we're starting again, so kill the pase connection.
2174 0 : if (commissionee != nullptr)
2175 : {
2176 0 : ReleaseCommissioneeDevice(commissionee);
2177 : }
2178 :
2179 : // Invoke callbacks last, after we have cleared up all state.
2180 0 : SendCommissioningCompleteCallbacks(nodeId, mCommissioningCompletionStatus);
2181 : }
2182 :
2183 0 : void DeviceCommissioner::SendCommissioningCompleteCallbacks(NodeId nodeId, const CompletionStatus & completionStatus)
2184 : {
2185 : MATTER_LOG_METRIC_END(kMetricDeviceCommissionerCommission, completionStatus.err);
2186 :
2187 0 : ChipLogProgress(Controller, "Commissioning complete for node ID 0x" ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId),
2188 : (completionStatus.err == CHIP_NO_ERROR ? "success" : completionStatus.err.AsString()));
2189 0 : mCommissioningStage = CommissioningStage::kSecurePairing;
2190 :
2191 0 : if (mPairingDelegate == nullptr)
2192 : {
2193 0 : return;
2194 : }
2195 :
2196 0 : mPairingDelegate->OnCommissioningComplete(nodeId, completionStatus.err);
2197 :
2198 0 : PeerId peerId(GetCompressedFabricId(), nodeId);
2199 0 : if (completionStatus.err == CHIP_NO_ERROR)
2200 : {
2201 0 : mPairingDelegate->OnCommissioningSuccess(peerId);
2202 : }
2203 : else
2204 : {
2205 0 : mPairingDelegate->OnCommissioningFailure(peerId, completionStatus);
2206 : }
2207 : }
2208 :
2209 0 : void DeviceCommissioner::CommissioningStageComplete(CHIP_ERROR err, CommissioningDelegate::CommissioningReport report)
2210 : {
2211 : // Once this stage is complete, reset mDeviceBeingCommissioned - this will be reset when the delegate calls the next step.
2212 : MATTER_TRACE_SCOPE("CommissioningStageComplete", "DeviceCommissioner");
2213 : MATTER_LOG_METRIC_END(MetricKeyForCommissioningStage(mCommissioningStage), err);
2214 0 : VerifyOrDie(mDeviceBeingCommissioned);
2215 :
2216 0 : NodeId nodeId = mDeviceBeingCommissioned->GetDeviceId();
2217 0 : DeviceProxy * proxy = mDeviceBeingCommissioned;
2218 0 : mDeviceBeingCommissioned = nullptr;
2219 0 : mInvokeCancelFn = nullptr;
2220 0 : mWriteCancelFn = nullptr;
2221 :
2222 0 : if (mPairingDelegate != nullptr)
2223 : {
2224 0 : mPairingDelegate->OnCommissioningStatusUpdate(PeerId(GetCompressedFabricId(), nodeId), mCommissioningStage, err);
2225 : }
2226 :
2227 0 : if (mCommissioningDelegate == nullptr)
2228 : {
2229 0 : return;
2230 : }
2231 0 : report.stageCompleted = mCommissioningStage;
2232 0 : CHIP_ERROR status = mCommissioningDelegate->CommissioningStepFinished(err, report);
2233 0 : if (status != CHIP_NO_ERROR && mCommissioningStage != CommissioningStage::kCleanup)
2234 : {
2235 : // Commissioning delegate will only return error if it failed to perform the appropriate commissioning step.
2236 : // In this case, we should complete the commissioning for it.
2237 0 : CompletionStatus completionStatus;
2238 0 : completionStatus.err = status;
2239 0 : completionStatus.failedStage = MakeOptional(report.stageCompleted);
2240 0 : mCommissioningStage = CommissioningStage::kCleanup;
2241 0 : mDeviceBeingCommissioned = proxy;
2242 0 : CleanupCommissioning(proxy, nodeId, completionStatus);
2243 0 : }
2244 : }
2245 :
2246 0 : void DeviceCommissioner::OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr,
2247 : const SessionHandle & sessionHandle)
2248 : {
2249 : // CASE session established.
2250 : MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, CHIP_NO_ERROR);
2251 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2252 0 : VerifyOrDie(commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForStayActive ||
2253 : commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForCommissioningComplete);
2254 0 : VerifyOrDie(commissioner->mDeviceBeingCommissioned->GetDeviceId() == sessionHandle->GetPeer().GetNodeId());
2255 0 : commissioner->CancelCASECallbacks(); // ensure all CASE callbacks are unregistered
2256 :
2257 0 : CommissioningDelegate::CommissioningReport report;
2258 0 : report.Set<OperationalNodeFoundData>(OperationalNodeFoundData(OperationalDeviceProxy(&exchangeMgr, sessionHandle)));
2259 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report);
2260 0 : }
2261 :
2262 0 : void DeviceCommissioner::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
2263 : {
2264 : // CASE session establishment failed.
2265 : MATTER_LOG_METRIC_END(kMetricDeviceCommissioningOperationalSetup, error);
2266 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
2267 0 : VerifyOrDie(commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForStayActive ||
2268 : commissioner->mCommissioningStage == CommissioningStage::kFindOperationalForCommissioningComplete);
2269 0 : VerifyOrDie(commissioner->mDeviceBeingCommissioned->GetDeviceId() == peerId.GetNodeId());
2270 0 : commissioner->CancelCASECallbacks(); // ensure all CASE callbacks are unregistered
2271 :
2272 0 : if (error != CHIP_NO_ERROR)
2273 : {
2274 0 : ChipLogProgress(Controller, "Device connection failed. Error %" CHIP_ERROR_FORMAT, error.Format());
2275 : }
2276 : else
2277 : {
2278 : // Ensure that commissioning stage advancement is done based on seeing an error.
2279 0 : ChipLogError(Controller, "Device connection failed without a valid error code.");
2280 0 : error = CHIP_ERROR_INTERNAL;
2281 : }
2282 0 : commissioner->CommissioningStageComplete(error);
2283 0 : }
2284 :
2285 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
2286 : // No specific action to take on either success or failure here; we're just
2287 : // trying to bump the fail-safe, and if that fails it's not clear there's much
2288 : // we can to with that.
2289 0 : static void OnExtendFailsafeForCASERetryFailure(void * context, CHIP_ERROR error)
2290 : {
2291 0 : ChipLogError(Controller, "Failed to extend fail-safe for CASE retry: %" CHIP_ERROR_FORMAT, error.Format());
2292 0 : }
2293 : static void
2294 0 : OnExtendFailsafeForCASERetrySuccess(void * context,
2295 : const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
2296 : {
2297 0 : ChipLogProgress(Controller, "Status of extending fail-safe for CASE retry: %u", to_underlying(data.errorCode));
2298 0 : }
2299 :
2300 0 : void DeviceCommissioner::OnDeviceConnectionRetryFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error,
2301 : System::Clock::Seconds16 retryTimeout)
2302 : {
2303 0 : ChipLogError(Controller,
2304 : "Session establishment failed for " ChipLogFormatScopedNodeId ", error: %" CHIP_ERROR_FORMAT
2305 : ". Next retry expected to get a response to Sigma1 or fail within %d seconds",
2306 : ChipLogValueScopedNodeId(peerId), error.Format(), retryTimeout.count());
2307 :
2308 0 : auto self = static_cast<DeviceCommissioner *>(context);
2309 0 : VerifyOrDie(self->GetCommissioningStage() == CommissioningStage::kFindOperationalForStayActive ||
2310 : self->GetCommissioningStage() == CommissioningStage::kFindOperationalForCommissioningComplete);
2311 0 : VerifyOrDie(self->mDeviceBeingCommissioned->GetDeviceId() == peerId.GetNodeId());
2312 :
2313 : bool supportsConcurrent =
2314 0 : self->mCommissioningDelegate->GetCommissioningParameters().GetSupportsConcurrentConnection().ValueOr(true);
2315 0 : if (!supportsConcurrent)
2316 : {
2317 : // Concurrent mode not supported.
2318 : // We are in operational phase so the commissioning channel is not
2319 : // available anymore and it is not possible to re-arm the fail-safe timer.
2320 0 : return;
2321 : }
2322 :
2323 : // We need to do the fail-safe arming over the PASE session.
2324 0 : auto * commissioneeDevice = self->FindCommissioneeDevice(peerId.GetNodeId());
2325 0 : if (!commissioneeDevice)
2326 : {
2327 : // Commissioning canceled, presumably. Just ignore the notification,
2328 : // not much we can do here.
2329 0 : return;
2330 : }
2331 :
2332 : // Extend by the default failsafe timeout plus our retry timeout, so we can
2333 : // be sure the fail-safe will not expire before we try the next time, if
2334 : // there will be a next time.
2335 : //
2336 : // TODO: Make it possible for our clients to control the exact timeout here?
2337 : uint16_t failsafeTimeout;
2338 0 : if (UINT16_MAX - retryTimeout.count() < kDefaultFailsafeTimeout)
2339 : {
2340 0 : failsafeTimeout = UINT16_MAX;
2341 : }
2342 : else
2343 : {
2344 0 : failsafeTimeout = static_cast<uint16_t>(retryTimeout.count() + kDefaultFailsafeTimeout);
2345 : }
2346 :
2347 : // A false return is fine; we don't want to make the fail-safe shorter here.
2348 0 : self->ExtendArmFailSafeInternal(commissioneeDevice, self->GetCommissioningStage(), failsafeTimeout,
2349 0 : MakeOptional(kMinimumCommissioningStepTimeout), OnExtendFailsafeForCASERetrySuccess,
2350 : OnExtendFailsafeForCASERetryFailure, /* fireAndForget = */ true);
2351 : }
2352 : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
2353 :
2354 : // ClusterStateCache::Callback / ReadClient::Callback
2355 0 : void DeviceCommissioner::OnDone(app::ReadClient * readClient)
2356 : {
2357 0 : VerifyOrDie(readClient != nullptr && readClient == mReadClient.get());
2358 0 : mReadClient.reset();
2359 0 : switch (mCommissioningStage)
2360 : {
2361 0 : case CommissioningStage::kReadCommissioningInfo:
2362 0 : ContinueReadingCommissioningInfo(mCommissioningDelegate->GetCommissioningParameters());
2363 0 : break;
2364 0 : default:
2365 0 : VerifyOrDie(false);
2366 : break;
2367 : }
2368 0 : }
2369 :
2370 : namespace {
2371 : // Helper for grouping attribute paths into read interactions in ContinueReadingCommissioningInfo()
2372 : // below. The logic generates a sequence of calls to AddAttributePath(), stopping when the capacity
2373 : // of the builder is exceeded. When creating subsequent read requests, the same sequence of calls
2374 : // is generated again, but the builder will skip however many attributes were already read in
2375 : // previous requests. This makes it easy to have logic that conditionally reads attributes, without
2376 : // needing to write manual code to work out where subsequent reads need to resume -- the logic that
2377 : // decides which attributes to read simply needs to be repeatable / deterministic.
2378 : class ReadInteractionBuilder
2379 : {
2380 : static constexpr auto kCapacity = InteractionModelEngine::kMinSupportedPathsPerReadRequest;
2381 :
2382 : size_t mSkip = 0;
2383 : size_t mCount = 0;
2384 : app::AttributePathParams mPaths[kCapacity];
2385 :
2386 : public:
2387 0 : ReadInteractionBuilder(size_t skip = 0) : mSkip(skip) {}
2388 :
2389 0 : size_t size() { return std::min(mCount, kCapacity); }
2390 0 : bool exceeded() { return mCount > kCapacity; }
2391 0 : app::AttributePathParams * paths() { return mPaths; }
2392 :
2393 : // Adds an attribute path if within the current window.
2394 : // Returns false if the available space has been exceeded.
2395 : template <typename... Ts>
2396 0 : bool AddAttributePath(Ts &&... args)
2397 : {
2398 0 : if (mSkip > 0)
2399 : {
2400 0 : mSkip--;
2401 0 : return true;
2402 : }
2403 0 : if (mCount >= kCapacity)
2404 : {
2405 : // capacity exceeded
2406 0 : mCount = kCapacity + 1;
2407 0 : return false;
2408 : }
2409 0 : mPaths[mCount++] = app::AttributePathParams(std::forward<Ts>(args)...);
2410 0 : return true;
2411 : }
2412 : };
2413 : } // namespace
2414 :
2415 0 : void DeviceCommissioner::ContinueReadingCommissioningInfo(const CommissioningParameters & params)
2416 : {
2417 0 : VerifyOrDie(mCommissioningStage == CommissioningStage::kReadCommissioningInfo);
2418 :
2419 : // mReadCommissioningInfoProgress starts at 0 and counts the number of paths we have read.
2420 : // A marker value is used to indicate that there are no further attributes to read.
2421 : static constexpr auto kReadProgressNoFurtherAttributes = std::numeric_limits<decltype(mReadCommissioningInfoProgress)>::max();
2422 0 : if (mReadCommissioningInfoProgress == kReadProgressNoFurtherAttributes)
2423 : {
2424 0 : FinishReadingCommissioningInfo(params);
2425 0 : return;
2426 : }
2427 :
2428 : // We can ony read 9 paths per Read Interaction, since that is the minimum a server has to
2429 : // support per spec (see "Interaction Model Limits"), so we generally need to perform more
2430 : // that one interaction. To build the list of attributes for each interaction, we use a
2431 : // builder that skips adding paths that we already handled in a previous interaction, and
2432 : // returns false if the current request is exhausted. This construction avoids allocating
2433 : // memory to hold the complete list of attributes to read up front; however the logic to
2434 : // determine the attributes to include must be deterministic since it runs multiple times.
2435 : // The use of an immediately-invoked lambda is convenient for control flow.
2436 0 : ReadInteractionBuilder builder(mReadCommissioningInfoProgress);
2437 0 : [&]() -> void {
2438 : // General Commissioning
2439 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2440 : Clusters::GeneralCommissioning::Attributes::SupportsConcurrentConnection::Id));
2441 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2442 : Clusters::GeneralCommissioning::Attributes::Breadcrumb::Id));
2443 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2444 : Clusters::GeneralCommissioning::Attributes::BasicCommissioningInfo::Id));
2445 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2446 : Clusters::GeneralCommissioning::Attributes::RegulatoryConfig::Id));
2447 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2448 : Clusters::GeneralCommissioning::Attributes::LocationCapability::Id));
2449 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::GeneralCommissioning::Id,
2450 : Clusters::GeneralCommissioning::Attributes::IsCommissioningWithoutPower::Id));
2451 :
2452 : // Basic Information: VID and PID for device attestation purposes
2453 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::BasicInformation::Id,
2454 : Clusters::BasicInformation::Attributes::VendorID::Id));
2455 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::BasicInformation::Id,
2456 : Clusters::BasicInformation::Attributes::ProductID::Id));
2457 :
2458 : // Time Synchronization: all attributes
2459 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::TimeSynchronization::Id));
2460 :
2461 : // Network Commissioning (all endpoints): Read the feature map and connect time
2462 : // TODO: Expose a flag that disables network setup so we don't need to read this
2463 0 : VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
2464 : Clusters::NetworkCommissioning::Attributes::FeatureMap::Id));
2465 0 : VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
2466 : Clusters::NetworkCommissioning::Attributes::ConnectMaxTimeSeconds::Id));
2467 :
2468 : // If we were asked to do network scans, also read ScanMaxTimeSeconds,
2469 : // so we know how long to wait for those.
2470 0 : if (params.GetAttemptWiFiNetworkScan().ValueOr(false) || params.GetAttemptThreadNetworkScan().ValueOr(false))
2471 : {
2472 0 : VerifyOrReturn(builder.AddAttributePath(Clusters::NetworkCommissioning::Id,
2473 : Clusters::NetworkCommissioning::Attributes::ScanMaxTimeSeconds::Id));
2474 : }
2475 :
2476 : // OperationalCredentials: existing fabrics, if necessary
2477 0 : if (params.GetCheckForMatchingFabric())
2478 : {
2479 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::OperationalCredentials::Id,
2480 : Clusters::OperationalCredentials::Attributes::Fabrics::Id));
2481 : }
2482 :
2483 : // ICD Management
2484 0 : if (params.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore)
2485 : {
2486 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2487 : Clusters::IcdManagement::Attributes::FeatureMap::Id));
2488 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2489 : Clusters::IcdManagement::Attributes::UserActiveModeTriggerHint::Id));
2490 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2491 : Clusters::IcdManagement::Attributes::UserActiveModeTriggerInstruction::Id));
2492 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2493 : Clusters::IcdManagement::Attributes::IdleModeDuration::Id));
2494 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2495 : Clusters::IcdManagement::Attributes::ActiveModeDuration::Id));
2496 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2497 : Clusters::IcdManagement::Attributes::ActiveModeThreshold::Id));
2498 0 : VerifyOrReturn(builder.AddAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
2499 : Clusters::IcdManagement::Attributes::ClusterRevision::Id));
2500 : }
2501 :
2502 : // Extra paths requested via CommissioningParameters
2503 0 : for (auto const & path : params.GetExtraReadPaths())
2504 : {
2505 0 : VerifyOrReturn(builder.AddAttributePath(path));
2506 : }
2507 0 : }();
2508 :
2509 0 : VerifyOrDie(builder.size() > 0); // our logic is broken if there is nothing to read
2510 0 : if (builder.exceeded())
2511 : {
2512 : // Keep track of the number of attributes we have read already so we can resume from there.
2513 0 : auto progress = mReadCommissioningInfoProgress + builder.size();
2514 0 : VerifyOrDie(progress < kReadProgressNoFurtherAttributes);
2515 0 : mReadCommissioningInfoProgress = static_cast<decltype(mReadCommissioningInfoProgress)>(progress);
2516 : }
2517 : else
2518 : {
2519 0 : mReadCommissioningInfoProgress = kReadProgressNoFurtherAttributes;
2520 : }
2521 :
2522 0 : SendCommissioningReadRequest(mDeviceBeingCommissioned, mCommissioningStepTimeout, builder.paths(), builder.size());
2523 : }
2524 :
2525 : namespace {
2526 0 : void AccumulateErrors(CHIP_ERROR & acc, CHIP_ERROR err)
2527 : {
2528 0 : if (acc == CHIP_NO_ERROR && err != CHIP_NO_ERROR)
2529 : {
2530 0 : acc = err;
2531 : }
2532 0 : }
2533 : } // namespace
2534 :
2535 0 : void DeviceCommissioner::FinishReadingCommissioningInfo(const CommissioningParameters & params)
2536 : {
2537 : // We want to parse as much information as possible, even if we eventually end
2538 : // up returning an error (e.g. because some mandatory information was missing).
2539 0 : CHIP_ERROR err = CHIP_NO_ERROR;
2540 0 : ReadCommissioningInfo info;
2541 0 : info.attributes = mAttributeCache.get();
2542 0 : AccumulateErrors(err, ParseGeneralCommissioningInfo(info));
2543 0 : AccumulateErrors(err, ParseBasicInformation(info));
2544 0 : AccumulateErrors(err, ParseNetworkCommissioningInfo(info));
2545 0 : AccumulateErrors(err, ParseTimeSyncInfo(info));
2546 0 : AccumulateErrors(err, ParseFabrics(info));
2547 0 : AccumulateErrors(err, ParseICDInfo(info));
2548 0 : AccumulateErrors(err, ParseExtraCommissioningInfo(info, params));
2549 :
2550 0 : if (mPairingDelegate != nullptr && err == CHIP_NO_ERROR)
2551 : {
2552 0 : mPairingDelegate->OnReadCommissioningInfo(info);
2553 : }
2554 :
2555 0 : CommissioningDelegate::CommissioningReport report;
2556 0 : report.Set<ReadCommissioningInfo>(info);
2557 0 : CommissioningStageComplete(err, report);
2558 :
2559 : // Only release the attribute cache once `info` is no longer needed.
2560 0 : mAttributeCache.reset();
2561 0 : }
2562 :
2563 0 : CHIP_ERROR DeviceCommissioner::ParseGeneralCommissioningInfo(ReadCommissioningInfo & info)
2564 : {
2565 : using namespace GeneralCommissioning::Attributes;
2566 0 : CHIP_ERROR return_err = CHIP_NO_ERROR;
2567 : CHIP_ERROR err;
2568 :
2569 0 : BasicCommissioningInfo::TypeInfo::DecodableType basicInfo;
2570 0 : err = mAttributeCache->Get<BasicCommissioningInfo::TypeInfo>(kRootEndpointId, basicInfo);
2571 0 : if (err == CHIP_NO_ERROR)
2572 : {
2573 0 : info.general.recommendedFailsafe = basicInfo.failSafeExpiryLengthSeconds;
2574 : }
2575 : else
2576 : {
2577 0 : ChipLogError(Controller, "Failed to read BasicCommissioningInfo: %" CHIP_ERROR_FORMAT, err.Format());
2578 0 : return_err = err;
2579 : }
2580 :
2581 0 : err = mAttributeCache->Get<RegulatoryConfig::TypeInfo>(kRootEndpointId, info.general.currentRegulatoryLocation);
2582 0 : if (err != CHIP_NO_ERROR)
2583 : {
2584 0 : ChipLogError(Controller, "Failed to read RegulatoryConfig: %" CHIP_ERROR_FORMAT, err.Format());
2585 0 : return_err = err;
2586 : }
2587 :
2588 0 : err = mAttributeCache->Get<LocationCapability::TypeInfo>(kRootEndpointId, info.general.locationCapability);
2589 0 : if (err != CHIP_NO_ERROR)
2590 : {
2591 0 : ChipLogError(Controller, "Failed to read LocationCapability: %" CHIP_ERROR_FORMAT, err.Format());
2592 0 : return_err = err;
2593 : }
2594 :
2595 0 : err = mAttributeCache->Get<Breadcrumb::TypeInfo>(kRootEndpointId, info.general.breadcrumb);
2596 0 : if (err != CHIP_NO_ERROR)
2597 : {
2598 0 : ChipLogError(Controller, "Failed to read Breadcrumb: %" CHIP_ERROR_FORMAT, err.Format());
2599 0 : return_err = err;
2600 : }
2601 :
2602 0 : err = mAttributeCache->Get<SupportsConcurrentConnection::TypeInfo>(kRootEndpointId, info.supportsConcurrentConnection);
2603 0 : if (err != CHIP_NO_ERROR)
2604 : {
2605 0 : ChipLogError(Controller, "Ignoring failure to read SupportsConcurrentConnection: %" CHIP_ERROR_FORMAT, err.Format());
2606 0 : info.supportsConcurrentConnection = true; // default to true (concurrent), not a fatal error
2607 : }
2608 :
2609 0 : err = mAttributeCache->Get<IsCommissioningWithoutPower::TypeInfo>(kRootEndpointId, info.general.isCommissioningWithoutPower);
2610 0 : if (err != CHIP_NO_ERROR)
2611 : {
2612 : // 'IsCommissioningWithoutPower' is optional. Any failures (likely not present) means default to assuming false.
2613 0 : info.general.isCommissioningWithoutPower = false;
2614 : }
2615 :
2616 0 : return return_err;
2617 : }
2618 :
2619 0 : CHIP_ERROR DeviceCommissioner::ParseBasicInformation(ReadCommissioningInfo & info)
2620 : {
2621 : using namespace BasicInformation::Attributes;
2622 0 : CHIP_ERROR return_err = CHIP_NO_ERROR;
2623 : CHIP_ERROR err;
2624 :
2625 0 : err = mAttributeCache->Get<VendorID::TypeInfo>(kRootEndpointId, info.basic.vendorId);
2626 0 : if (err != CHIP_NO_ERROR)
2627 : {
2628 0 : ChipLogError(Controller, "Failed to read VendorID: %" CHIP_ERROR_FORMAT, err.Format());
2629 0 : return_err = err;
2630 : }
2631 :
2632 0 : err = mAttributeCache->Get<ProductID::TypeInfo>(kRootEndpointId, info.basic.productId);
2633 0 : if (err != CHIP_NO_ERROR)
2634 : {
2635 0 : ChipLogError(Controller, "Failed to read ProductID: %" CHIP_ERROR_FORMAT, err.Format());
2636 0 : return_err = err;
2637 : }
2638 :
2639 0 : return return_err;
2640 : }
2641 :
2642 0 : CHIP_ERROR DeviceCommissioner::ParseNetworkCommissioningInfo(ReadCommissioningInfo & info)
2643 : {
2644 : using namespace NetworkCommissioning::Attributes;
2645 0 : CHIP_ERROR return_err = CHIP_NO_ERROR;
2646 : CHIP_ERROR err;
2647 :
2648 : // Set the network cluster endpoints first so we can match up the connection
2649 : // times. Note that here we don't know what endpoints the network
2650 : // commissioning clusters might be on.
2651 0 : err = mAttributeCache->ForEachAttribute(NetworkCommissioning::Id, [this, &info](const ConcreteAttributePath & path) {
2652 0 : VerifyOrReturnError(path.mAttributeId == FeatureMap::Id, CHIP_NO_ERROR);
2653 0 : BitFlags<NetworkCommissioning::Feature> features;
2654 0 : if (mAttributeCache->Get<FeatureMap::TypeInfo>(path, *features.RawStorage()) == CHIP_NO_ERROR)
2655 : {
2656 0 : if (features.Has(NetworkCommissioning::Feature::kWiFiNetworkInterface))
2657 : {
2658 0 : ChipLogProgress(Controller, "NetworkCommissioning Features: has WiFi. endpointid = %u", path.mEndpointId);
2659 0 : info.network.wifi.endpoint = path.mEndpointId;
2660 : }
2661 0 : else if (features.Has(NetworkCommissioning::Feature::kThreadNetworkInterface))
2662 : {
2663 0 : ChipLogProgress(Controller, "NetworkCommissioning Features: has Thread. endpointid = %u", path.mEndpointId);
2664 0 : info.network.thread.endpoint = path.mEndpointId;
2665 : }
2666 0 : else if (features.Has(NetworkCommissioning::Feature::kEthernetNetworkInterface))
2667 : {
2668 0 : ChipLogProgress(Controller, "NetworkCommissioning Features: has Ethernet. endpointid = %u", path.mEndpointId);
2669 0 : info.network.eth.endpoint = path.mEndpointId;
2670 : }
2671 : }
2672 0 : return CHIP_NO_ERROR;
2673 : });
2674 0 : AccumulateErrors(return_err, err);
2675 :
2676 0 : if (info.network.thread.endpoint != kInvalidEndpointId)
2677 : {
2678 0 : err = ParseNetworkCommissioningTimeouts(info.network.thread, "Thread");
2679 0 : AccumulateErrors(return_err, err);
2680 : }
2681 :
2682 0 : if (info.network.wifi.endpoint != kInvalidEndpointId)
2683 : {
2684 0 : err = ParseNetworkCommissioningTimeouts(info.network.wifi, "Wi-Fi");
2685 0 : AccumulateErrors(return_err, err);
2686 : }
2687 :
2688 0 : if (return_err != CHIP_NO_ERROR)
2689 : {
2690 0 : ChipLogError(Controller, "Failed to parse Network Commissioning information: %" CHIP_ERROR_FORMAT, return_err.Format());
2691 : }
2692 0 : return return_err;
2693 : }
2694 :
2695 0 : CHIP_ERROR DeviceCommissioner::ParseNetworkCommissioningTimeouts(NetworkClusterInfo & networkInfo, const char * networkType)
2696 : {
2697 : using namespace NetworkCommissioning::Attributes;
2698 :
2699 0 : CHIP_ERROR err = mAttributeCache->Get<ConnectMaxTimeSeconds::TypeInfo>(networkInfo.endpoint, networkInfo.minConnectionTime);
2700 0 : if (err != CHIP_NO_ERROR)
2701 : {
2702 0 : ChipLogError(Controller, "Failed to read %s ConnectMaxTimeSeconds (endpoint %u): %" CHIP_ERROR_FORMAT, networkType,
2703 : networkInfo.endpoint, err.Format());
2704 0 : return err;
2705 : }
2706 :
2707 0 : err = mAttributeCache->Get<ScanMaxTimeSeconds::TypeInfo>(networkInfo.endpoint, networkInfo.maxScanTime);
2708 0 : if (err != CHIP_NO_ERROR)
2709 : {
2710 : // We don't always read this attribute, and we read it as a wildcard, so
2711 : // don't treat it as an error simply because it's missing.
2712 0 : if (err != CHIP_ERROR_KEY_NOT_FOUND)
2713 : {
2714 0 : ChipLogError(Controller, "Failed to read %s ScanMaxTimeSeconds (endpoint: %u): %" CHIP_ERROR_FORMAT, networkType,
2715 : networkInfo.endpoint, err.Format());
2716 0 : return err;
2717 : }
2718 :
2719 : // Just flag as "we don't know".
2720 0 : networkInfo.maxScanTime = 0;
2721 : }
2722 :
2723 0 : return CHIP_NO_ERROR;
2724 : }
2725 :
2726 0 : CHIP_ERROR DeviceCommissioner::ParseTimeSyncInfo(ReadCommissioningInfo & info)
2727 : {
2728 : using namespace TimeSynchronization::Attributes;
2729 : CHIP_ERROR err;
2730 :
2731 : // If we fail to get the feature map, there's no viable time cluster, don't set anything.
2732 0 : BitFlags<TimeSynchronization::Feature> featureMap;
2733 0 : err = mAttributeCache->Get<FeatureMap::TypeInfo>(kRootEndpointId, *featureMap.RawStorage());
2734 0 : if (err != CHIP_NO_ERROR)
2735 : {
2736 0 : info.requiresUTC = false;
2737 0 : info.requiresTimeZone = false;
2738 0 : info.requiresDefaultNTP = false;
2739 0 : info.requiresTrustedTimeSource = false;
2740 0 : return CHIP_NO_ERROR;
2741 : }
2742 0 : info.requiresUTC = true;
2743 0 : info.requiresTimeZone = featureMap.Has(TimeSynchronization::Feature::kTimeZone);
2744 0 : info.requiresDefaultNTP = featureMap.Has(TimeSynchronization::Feature::kNTPClient);
2745 0 : info.requiresTrustedTimeSource = featureMap.Has(TimeSynchronization::Feature::kTimeSyncClient);
2746 :
2747 0 : if (info.requiresTimeZone)
2748 : {
2749 0 : err = mAttributeCache->Get<TimeZoneListMaxSize::TypeInfo>(kRootEndpointId, info.maxTimeZoneSize);
2750 0 : if (err != CHIP_NO_ERROR)
2751 : {
2752 : // This information should be available, let's do our best with what we have, but we can't set
2753 : // the time zone without this information
2754 0 : info.requiresTimeZone = false;
2755 : }
2756 0 : err = mAttributeCache->Get<DSTOffsetListMaxSize::TypeInfo>(kRootEndpointId, info.maxDSTSize);
2757 0 : if (err != CHIP_NO_ERROR)
2758 : {
2759 0 : info.requiresTimeZone = false;
2760 : }
2761 : }
2762 0 : if (info.requiresDefaultNTP)
2763 : {
2764 0 : DefaultNTP::TypeInfo::DecodableType defaultNTP;
2765 0 : err = mAttributeCache->Get<DefaultNTP::TypeInfo>(kRootEndpointId, defaultNTP);
2766 0 : if (err == CHIP_NO_ERROR && (!defaultNTP.IsNull()) && (defaultNTP.Value().size() != 0))
2767 : {
2768 0 : info.requiresDefaultNTP = false;
2769 : }
2770 : }
2771 0 : if (info.requiresTrustedTimeSource)
2772 : {
2773 0 : TrustedTimeSource::TypeInfo::DecodableType trustedTimeSource;
2774 0 : err = mAttributeCache->Get<TrustedTimeSource::TypeInfo>(kRootEndpointId, trustedTimeSource);
2775 0 : if (err == CHIP_NO_ERROR && !trustedTimeSource.IsNull())
2776 : {
2777 0 : info.requiresTrustedTimeSource = false;
2778 : }
2779 : }
2780 :
2781 0 : return CHIP_NO_ERROR;
2782 : }
2783 :
2784 0 : CHIP_ERROR DeviceCommissioner::ParseFabrics(ReadCommissioningInfo & info)
2785 : {
2786 : using namespace OperationalCredentials::Attributes;
2787 : CHIP_ERROR err;
2788 0 : CHIP_ERROR return_err = CHIP_NO_ERROR;
2789 :
2790 : // We might not have requested a Fabrics attribute at all, so not having a
2791 : // value for it is not an error.
2792 0 : err = mAttributeCache->ForEachAttribute(OperationalCredentials::Id, [this, &info](const ConcreteAttributePath & path) {
2793 : using namespace chip::app::Clusters::OperationalCredentials::Attributes;
2794 : // this code is checking if the device is already on the commissioner's fabric.
2795 : // if a matching fabric is found, then remember the nodeId so that the commissioner
2796 : // can, if it decides to, cancel commissioning (before it fails in AddNoc) and know
2797 : // the device's nodeId on its fabric.
2798 0 : switch (path.mAttributeId)
2799 : {
2800 0 : case Fabrics::Id: {
2801 0 : Fabrics::TypeInfo::DecodableType fabrics;
2802 0 : ReturnErrorOnFailure(this->mAttributeCache->Get<Fabrics::TypeInfo>(path, fabrics));
2803 : // this is a best effort attempt to find a matching fabric, so no error checking on iter
2804 0 : auto iter = fabrics.begin();
2805 0 : while (iter.Next())
2806 : {
2807 0 : auto & fabricDescriptor = iter.GetValue();
2808 0 : ChipLogProgress(Controller,
2809 : "DeviceCommissioner::OnDone - fabric.vendorId=0x%04X fabric.fabricId=0x" ChipLogFormatX64
2810 : " fabric.nodeId=0x" ChipLogFormatX64,
2811 : fabricDescriptor.vendorID, ChipLogValueX64(fabricDescriptor.fabricID),
2812 : ChipLogValueX64(fabricDescriptor.nodeID));
2813 0 : if (GetFabricId() == fabricDescriptor.fabricID)
2814 : {
2815 0 : ChipLogProgress(Controller, "DeviceCommissioner::OnDone - found a matching fabric id");
2816 0 : chip::ByteSpan rootKeySpan = fabricDescriptor.rootPublicKey;
2817 0 : if (rootKeySpan.size() != Crypto::kP256_PublicKey_Length)
2818 : {
2819 0 : ChipLogError(Controller, "DeviceCommissioner::OnDone - fabric root key size mismatch %u != %u",
2820 : static_cast<unsigned>(rootKeySpan.size()),
2821 : static_cast<unsigned>(Crypto::kP256_PublicKey_Length));
2822 0 : continue;
2823 : }
2824 0 : P256PublicKeySpan rootPubKeySpan(rootKeySpan.data());
2825 0 : Crypto::P256PublicKey deviceRootPublicKey(rootPubKeySpan);
2826 :
2827 0 : Crypto::P256PublicKey commissionerRootPublicKey;
2828 0 : if (CHIP_NO_ERROR != GetRootPublicKey(commissionerRootPublicKey))
2829 : {
2830 0 : ChipLogError(Controller, "DeviceCommissioner::OnDone - error reading commissioner root public key");
2831 : }
2832 0 : else if (commissionerRootPublicKey.Matches(deviceRootPublicKey))
2833 : {
2834 0 : ChipLogProgress(Controller, "DeviceCommissioner::OnDone - fabric root keys match");
2835 0 : info.remoteNodeId = fabricDescriptor.nodeID;
2836 : }
2837 0 : }
2838 : }
2839 :
2840 0 : return CHIP_NO_ERROR;
2841 : }
2842 0 : default:
2843 0 : return CHIP_NO_ERROR;
2844 : }
2845 : });
2846 :
2847 0 : if (mPairingDelegate != nullptr)
2848 : {
2849 0 : mPairingDelegate->OnFabricCheck(info.remoteNodeId);
2850 : }
2851 :
2852 0 : return return_err;
2853 : }
2854 :
2855 2 : CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo & info)
2856 : {
2857 : using namespace IcdManagement::Attributes;
2858 : CHIP_ERROR err;
2859 :
2860 2 : bool hasUserActiveModeTrigger = false;
2861 2 : bool isICD = false;
2862 :
2863 2 : BitFlags<IcdManagement::Feature> featureMap;
2864 2 : err = mAttributeCache->Get<FeatureMap::TypeInfo>(kRootEndpointId, *featureMap.RawStorage());
2865 4 : if (err == CHIP_NO_ERROR)
2866 : {
2867 2 : info.icd.isLIT = featureMap.Has(IcdManagement::Feature::kLongIdleTimeSupport);
2868 2 : info.icd.checkInProtocolSupport = featureMap.Has(IcdManagement::Feature::kCheckInProtocolSupport);
2869 2 : hasUserActiveModeTrigger = featureMap.Has(IcdManagement::Feature::kUserActiveModeTrigger);
2870 2 : isICD = true;
2871 :
2872 : // LIT support was introduced but broken in ICD Management cluster revision 2 (Matter 1.3).
2873 : // Only treat a device as LIT for cluster revisions after 1.3 (i.e., revision > 2).
2874 2 : if (info.icd.isLIT)
2875 : {
2876 2 : uint16_t clusterRevision = 0;
2877 2 : CHIP_ERROR revErr = mAttributeCache->Get<ClusterRevision::TypeInfo>(kRootEndpointId, clusterRevision);
2878 4 : if (revErr != CHIP_NO_ERROR || clusterRevision <= 2)
2879 : {
2880 2 : if (revErr == CHIP_NO_ERROR)
2881 : {
2882 1 : ChipLogProgress(Controller,
2883 : "IcdManagement: Device claims LIT support but cluster revision is %" PRIu16
2884 : " (Matter 1.3). Disabling LIT due to known Matter 1.3 LIT issues.",
2885 : clusterRevision);
2886 : }
2887 : else
2888 : {
2889 0 : ChipLogProgress(Controller,
2890 : "IcdManagement: Device claims LIT support but ClusterRevision attribute is "
2891 : "missing or unreadable (err=%" CHIP_ERROR_FORMAT
2892 : "). Treating as revision <= 2 and disabling LIT.",
2893 : revErr.Format());
2894 : }
2895 1 : info.icd.isLIT = false;
2896 : }
2897 : }
2898 : }
2899 0 : else if (err == CHIP_ERROR_KEY_NOT_FOUND)
2900 : {
2901 : // This key is optional so not an error
2902 0 : info.icd.isLIT = false;
2903 0 : err = CHIP_NO_ERROR;
2904 : }
2905 0 : else if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
2906 : {
2907 0 : app::StatusIB statusIB;
2908 0 : err = mAttributeCache->GetStatus(app::ConcreteAttributePath(kRootEndpointId, IcdManagement::Id, FeatureMap::Id), statusIB);
2909 0 : if (err == CHIP_NO_ERROR)
2910 : {
2911 0 : if (statusIB.mStatus == Protocols::InteractionModel::Status::UnsupportedCluster)
2912 : {
2913 0 : info.icd.isLIT = false;
2914 : }
2915 : else
2916 : {
2917 0 : err = statusIB.ToChipError();
2918 : }
2919 : }
2920 : }
2921 :
2922 2 : ReturnErrorOnFailure(err);
2923 :
2924 2 : info.icd.userActiveModeTriggerHint.ClearAll();
2925 2 : info.icd.userActiveModeTriggerInstruction = CharSpan();
2926 :
2927 2 : if (hasUserActiveModeTrigger)
2928 : {
2929 : // Intentionally ignore errors since they are not mandatory.
2930 0 : bool activeModeTriggerInstructionRequired = false;
2931 :
2932 0 : err = mAttributeCache->Get<UserActiveModeTriggerHint::TypeInfo>(kRootEndpointId, info.icd.userActiveModeTriggerHint);
2933 0 : if (err != CHIP_NO_ERROR)
2934 : {
2935 0 : ChipLogError(Controller, "IcdManagement.UserActiveModeTriggerHint expected, but failed to read.");
2936 0 : return err;
2937 : }
2938 :
2939 : using IcdManagement::UserActiveModeTriggerBitmap;
2940 0 : activeModeTriggerInstructionRequired = info.icd.userActiveModeTriggerHint.HasAny(
2941 0 : UserActiveModeTriggerBitmap::kCustomInstruction, UserActiveModeTriggerBitmap::kActuateSensorSeconds,
2942 0 : UserActiveModeTriggerBitmap::kActuateSensorTimes, UserActiveModeTriggerBitmap::kActuateSensorLightsBlink,
2943 0 : UserActiveModeTriggerBitmap::kResetButtonLightsBlink, UserActiveModeTriggerBitmap::kResetButtonSeconds,
2944 0 : UserActiveModeTriggerBitmap::kResetButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonSeconds,
2945 0 : UserActiveModeTriggerBitmap::kSetupButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonTimes,
2946 0 : UserActiveModeTriggerBitmap::kAppDefinedButton);
2947 :
2948 0 : if (activeModeTriggerInstructionRequired)
2949 : {
2950 0 : err = mAttributeCache->Get<UserActiveModeTriggerInstruction::TypeInfo>(kRootEndpointId,
2951 0 : info.icd.userActiveModeTriggerInstruction);
2952 0 : if (err != CHIP_NO_ERROR)
2953 : {
2954 0 : ChipLogError(Controller,
2955 : "IcdManagement.UserActiveModeTriggerInstruction expected for given active mode trigger hint, but "
2956 : "failed to read.");
2957 0 : return err;
2958 : }
2959 : }
2960 : }
2961 :
2962 2 : if (!isICD)
2963 : {
2964 0 : info.icd.idleModeDuration = 0;
2965 0 : info.icd.activeModeDuration = 0;
2966 0 : info.icd.activeModeThreshold = 0;
2967 0 : return CHIP_NO_ERROR;
2968 : }
2969 :
2970 2 : err = mAttributeCache->Get<IdleModeDuration::TypeInfo>(kRootEndpointId, info.icd.idleModeDuration);
2971 4 : if (err != CHIP_NO_ERROR)
2972 : {
2973 0 : ChipLogError(Controller, "IcdManagement.IdleModeDuration expected, but failed to read: %" CHIP_ERROR_FORMAT, err.Format());
2974 0 : return err;
2975 : }
2976 :
2977 2 : err = mAttributeCache->Get<ActiveModeDuration::TypeInfo>(kRootEndpointId, info.icd.activeModeDuration);
2978 4 : if (err != CHIP_NO_ERROR)
2979 : {
2980 0 : ChipLogError(Controller, "IcdManagement.ActiveModeDuration expected, but failed to read: %" CHIP_ERROR_FORMAT,
2981 : err.Format());
2982 0 : return err;
2983 : }
2984 :
2985 2 : err = mAttributeCache->Get<ActiveModeThreshold::TypeInfo>(kRootEndpointId, info.icd.activeModeThreshold);
2986 4 : if (err != CHIP_NO_ERROR)
2987 : {
2988 0 : ChipLogError(Controller, "IcdManagement.ActiveModeThreshold expected, but failed to read: %" CHIP_ERROR_FORMAT,
2989 : err.Format());
2990 : }
2991 :
2992 2 : return err;
2993 : }
2994 :
2995 0 : void DeviceCommissioner::OnArmFailSafe(void * context,
2996 : const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
2997 : {
2998 0 : CommissioningDelegate::CommissioningReport report;
2999 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3000 :
3001 0 : ChipLogProgress(Controller, "Received ArmFailSafe response errorCode=%u", to_underlying(data.errorCode));
3002 0 : if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
3003 : {
3004 0 : err = CHIP_ERROR_INTERNAL;
3005 : // Preserve the device-supplied debugText so failure consumers can disambiguate
3006 : // ambiguous error codes (e.g. kBusyWithOtherAdmin specifics).
3007 0 : report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
3008 : }
3009 :
3010 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3011 0 : commissioner->CommissioningStageComplete(err, report);
3012 0 : }
3013 :
3014 0 : void DeviceCommissioner::OnSetRegulatoryConfigResponse(
3015 : void * context, const GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data)
3016 : {
3017 0 : CommissioningDelegate::CommissioningReport report;
3018 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3019 :
3020 0 : ChipLogProgress(Controller, "Received SetRegulatoryConfig response errorCode=%u", to_underlying(data.errorCode));
3021 0 : if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
3022 : {
3023 0 : err = CHIP_ERROR_INTERNAL;
3024 0 : report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
3025 : }
3026 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3027 0 : commissioner->CommissioningStageComplete(err, report);
3028 0 : }
3029 :
3030 0 : void DeviceCommissioner::OnSetTCAcknowledgementsResponse(
3031 : void * context, const GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data)
3032 : {
3033 0 : CommissioningDelegate::CommissioningReport report;
3034 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3035 :
3036 0 : ChipLogProgress(Controller, "Received SetTCAcknowledgements response errorCode=%u", to_underlying(data.errorCode));
3037 0 : if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
3038 : {
3039 0 : err = CHIP_ERROR_INTERNAL;
3040 : // SetTCAcknowledgementsResponse has no debugText field per spec.
3041 0 : report.Set<CommissioningErrorInfo>(data.errorCode);
3042 : }
3043 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3044 0 : commissioner->CommissioningStageComplete(err, report);
3045 0 : }
3046 :
3047 0 : void DeviceCommissioner::OnSetTimeZoneResponse(void * context,
3048 : const TimeSynchronization::Commands::SetTimeZoneResponse::DecodableType & data)
3049 : {
3050 0 : CommissioningDelegate::CommissioningReport report;
3051 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3052 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3053 : TimeZoneResponseInfo info;
3054 0 : info.requiresDSTOffsets = data.DSTOffsetRequired;
3055 0 : report.Set<TimeZoneResponseInfo>(info);
3056 0 : commissioner->CommissioningStageComplete(err, report);
3057 0 : }
3058 :
3059 0 : void DeviceCommissioner::OnSetUTCError(void * context, CHIP_ERROR error)
3060 : {
3061 : // For SetUTCTime, we don't actually care if the commissionee didn't want out time, that's its choice
3062 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3063 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
3064 0 : }
3065 :
3066 0 : void DeviceCommissioner::OnScanNetworksFailure(void * context, CHIP_ERROR error)
3067 : {
3068 0 : ChipLogProgress(Controller, "Received ScanNetworks failure response %" CHIP_ERROR_FORMAT, error.Format());
3069 :
3070 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3071 :
3072 : // advance to the kNeedsNetworkCreds waiting step
3073 : // clear error so that we don't abort the commissioning when ScanNetworks fails
3074 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
3075 :
3076 0 : if (commissioner->GetPairingDelegate() != nullptr)
3077 : {
3078 0 : commissioner->GetPairingDelegate()->OnScanNetworksFailure(error);
3079 : }
3080 0 : }
3081 :
3082 0 : void DeviceCommissioner::OnScanNetworksResponse(void * context,
3083 : const NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & data)
3084 : {
3085 0 : CommissioningDelegate::CommissioningReport report;
3086 :
3087 0 : ChipLogProgress(Controller, "Received ScanNetwork response, networkingStatus=%u debugText=%s",
3088 : to_underlying(data.networkingStatus),
3089 : (data.debugText.HasValue() ? std::string(data.debugText.Value().data(), data.debugText.Value().size()).c_str()
3090 : : "none provided"));
3091 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3092 :
3093 : // advance to the kNeedsNetworkCreds waiting step
3094 0 : commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
3095 :
3096 0 : if (commissioner->GetPairingDelegate() != nullptr)
3097 : {
3098 0 : commissioner->GetPairingDelegate()->OnScanNetworksSuccess(data);
3099 : }
3100 0 : }
3101 :
3102 0 : CHIP_ERROR DeviceCommissioner::NetworkCredentialsReady()
3103 : {
3104 0 : VerifyOrReturnError(mCommissioningStage == CommissioningStage::kNeedsNetworkCreds, CHIP_ERROR_INCORRECT_STATE);
3105 :
3106 : // need to advance to next step
3107 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3108 :
3109 0 : return CHIP_NO_ERROR;
3110 : }
3111 :
3112 0 : CHIP_ERROR DeviceCommissioner::ICDRegistrationInfoReady()
3113 : {
3114 0 : VerifyOrReturnError(mCommissioningStage == CommissioningStage::kICDGetRegistrationInfo, CHIP_ERROR_INCORRECT_STATE);
3115 :
3116 : // need to advance to next step
3117 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3118 :
3119 0 : return CHIP_NO_ERROR;
3120 : }
3121 :
3122 0 : void DeviceCommissioner::OnNetworkConfigResponse(void * context,
3123 : const NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data)
3124 : {
3125 0 : CommissioningDelegate::CommissioningReport report;
3126 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3127 :
3128 0 : ChipLogProgress(Controller, "Received NetworkConfig response, networkingStatus=%u", to_underlying(data.networkingStatus));
3129 0 : if (data.networkingStatus != NetworkCommissioning::NetworkCommissioningStatusEnum::kSuccess)
3130 : {
3131 0 : err = CHIP_ERROR_INTERNAL;
3132 : // Preserve debugText alongside the status enum so callers can distinguish
3133 : // ambiguous statuses (e.g. kAuthFailure: "wrong password" vs "regulatory restriction").
3134 0 : report.Set<NetworkCommissioningStatusInfo>(data.networkingStatus, data.debugText.ValueOr(CharSpan{}));
3135 : }
3136 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3137 0 : commissioner->CommissioningStageComplete(err, report);
3138 0 : }
3139 :
3140 0 : void DeviceCommissioner::OnConnectNetworkResponse(
3141 : void * context, const NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data)
3142 : {
3143 0 : CommissioningDelegate::CommissioningReport report;
3144 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3145 :
3146 0 : ChipLogProgress(Controller, "Received ConnectNetwork response, networkingStatus=%u", to_underlying(data.networkingStatus));
3147 0 : if (data.networkingStatus != NetworkCommissioning::NetworkCommissioningStatusEnum::kSuccess)
3148 : {
3149 0 : err = CHIP_ERROR_INTERNAL;
3150 : // Preserve debugText alongside the status enum (see OnNetworkConfigResponse). Also
3151 : // surface the device-specific errorValue which carries driver-level failure detail
3152 : // (TX-power-limited / interference / association-failure code) distinct from the
3153 : // spec-level networkingStatus enum.
3154 0 : Optional<int32_t> errorValue = data.errorValue.IsNull() ? NullOptional : MakeOptional(data.errorValue.Value());
3155 0 : report.Set<NetworkCommissioningStatusInfo>(data.networkingStatus, data.debugText.ValueOr(CharSpan{}), errorValue);
3156 : }
3157 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3158 0 : commissioner->CommissioningStageComplete(err, report);
3159 0 : }
3160 :
3161 0 : void DeviceCommissioner::OnCommissioningCompleteResponse(
3162 : void * context, const GeneralCommissioning::Commands::CommissioningCompleteResponse::DecodableType & data)
3163 : {
3164 0 : CommissioningDelegate::CommissioningReport report;
3165 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3166 :
3167 0 : ChipLogProgress(Controller, "Received CommissioningComplete response, errorCode=%u", to_underlying(data.errorCode));
3168 0 : if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
3169 : {
3170 0 : err = CHIP_ERROR_INTERNAL;
3171 0 : report.Set<CommissioningErrorInfo>(data.errorCode, data.debugText);
3172 : }
3173 0 : DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
3174 0 : commissioner->CommissioningStageComplete(err, report);
3175 0 : }
3176 :
3177 : template <typename RequestObjectT>
3178 : CHIP_ERROR
3179 0 : DeviceCommissioner::SendCommissioningCommand(DeviceProxy * device, const RequestObjectT & request,
3180 : CommandResponseSuccessCallback<typename RequestObjectT::ResponseType> successCb,
3181 : CommandResponseFailureCallback failureCb, EndpointId endpoint,
3182 : Optional<System::Clock::Timeout> timeout, bool fireAndForget)
3183 :
3184 : {
3185 : // Default behavior is to make sequential, cancellable calls tracked via mInvokeCancelFn.
3186 : // Fire-and-forget calls are not cancellable and don't receive `this` as context in callbacks.
3187 0 : VerifyOrDie(fireAndForget || !mInvokeCancelFn); // we don't make parallel (cancellable) calls
3188 :
3189 0 : void * context = (!fireAndForget) ? this : nullptr;
3190 0 : auto onSuccessCb = [context, successCb](const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatus,
3191 : const typename RequestObjectT::ResponseType & responseData) {
3192 0 : successCb(context, responseData);
3193 : };
3194 0 : auto onFailureCb = [context, failureCb](CHIP_ERROR aError) { failureCb(context, aError); };
3195 :
3196 0 : return InvokeCommandRequest(device->GetExchangeManager(), device->GetSecureSession().Value(), endpoint, request, onSuccessCb,
3197 0 : onFailureCb, NullOptional, timeout, (!fireAndForget) ? &mInvokeCancelFn : nullptr);
3198 : }
3199 :
3200 : template <typename AttrType>
3201 : CHIP_ERROR DeviceCommissioner::SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster,
3202 : AttributeId attribute, const AttrType & requestData,
3203 : WriteResponseSuccessCallback successCb,
3204 : WriteResponseFailureCallback failureCb)
3205 : {
3206 : VerifyOrDie(!mWriteCancelFn); // we don't make parallel (cancellable) calls
3207 : auto onSuccessCb = [this, successCb](const app::ConcreteAttributePath & aPath) { successCb(this); };
3208 : auto onFailureCb = [this, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) { failureCb(this, aError); };
3209 : return WriteAttribute(device->GetSecureSession().Value(), endpoint, cluster, attribute, requestData, onSuccessCb, onFailureCb,
3210 : /* aTimedWriteTimeoutMs = */ NullOptional, /* onDoneCb = */ nullptr, /* aDataVersion = */ NullOptional,
3211 : /* outCancelFn = */ &mWriteCancelFn);
3212 : }
3213 :
3214 0 : void DeviceCommissioner::SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
3215 : app::AttributePathParams * readPaths, size_t readPathsSize)
3216 : {
3217 0 : VerifyOrDie(!mReadClient); // we don't perform parallel reads
3218 :
3219 0 : app::InteractionModelEngine * engine = app::InteractionModelEngine::GetInstance();
3220 0 : app::ReadPrepareParams readParams(proxy->GetSecureSession().Value());
3221 0 : readParams.mIsFabricFiltered = false;
3222 0 : if (timeout.HasValue())
3223 : {
3224 0 : readParams.mTimeout = timeout.Value();
3225 : }
3226 0 : readParams.mpAttributePathParamsList = readPaths;
3227 0 : readParams.mAttributePathParamsListSize = readPathsSize;
3228 :
3229 : // Take ownership of the attribute cache, so it can be released if SendRequest fails.
3230 0 : auto attributeCache = std::move(mAttributeCache);
3231 : auto readClient = chip::Platform::MakeUnique<app::ReadClient>(
3232 0 : engine, proxy->GetExchangeManager(), attributeCache->GetBufferedCallback(), app::ReadClient::InteractionType::Read);
3233 0 : CHIP_ERROR err = readClient->SendRequest(readParams);
3234 0 : if (err != CHIP_NO_ERROR)
3235 : {
3236 0 : ChipLogError(Controller, "Failed to send read request: %" CHIP_ERROR_FORMAT, err.Format());
3237 0 : CommissioningStageComplete(err);
3238 0 : return;
3239 : }
3240 0 : mAttributeCache = std::move(attributeCache);
3241 0 : mReadClient = std::move(readClient);
3242 0 : }
3243 :
3244 0 : void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, CommissioningStage step, CommissioningParameters & params,
3245 : CommissioningDelegate * delegate, EndpointId endpoint,
3246 : Optional<System::Clock::Timeout> timeout)
3247 :
3248 : {
3249 : MATTER_LOG_METRIC(kMetricDeviceCommissionerCommissionStage, step);
3250 : MATTER_LOG_METRIC_BEGIN(MetricKeyForCommissioningStage(step));
3251 :
3252 0 : if (params.GetCompletionStatus().err == CHIP_NO_ERROR)
3253 : {
3254 0 : ChipLogProgress(Controller, "Performing next commissioning step '%s'", StageToString(step));
3255 : }
3256 : else
3257 : {
3258 0 : ChipLogProgress(Controller, "Performing next commissioning step '%s' with completion status = '%s'", StageToString(step),
3259 : params.GetCompletionStatus().err.AsString());
3260 : }
3261 :
3262 0 : if (mPairingDelegate)
3263 : {
3264 0 : mPairingDelegate->OnCommissioningStageStart(PeerId(GetCompressedFabricId(), proxy->GetDeviceId()), step);
3265 : }
3266 :
3267 0 : mCommissioningStepTimeout = timeout;
3268 0 : mCommissioningStage = step;
3269 0 : mCommissioningDelegate = delegate;
3270 0 : mDeviceBeingCommissioned = proxy;
3271 :
3272 : // TODO: Extend timeouts to the DAC and Opcert requests.
3273 : // TODO(cecille): We probably want something better than this for breadcrumbs.
3274 0 : uint64_t breadcrumb = static_cast<uint64_t>(step);
3275 :
3276 0 : switch (step)
3277 : {
3278 0 : case CommissioningStage::kArmFailsafe: {
3279 0 : VerifyOrDie(endpoint == kRootEndpointId);
3280 : // Make sure the fail-safe value we set here actually ends up being used
3281 : // no matter what.
3282 0 : proxy->SetFailSafeExpirationTimestamp(System::Clock::kZero);
3283 0 : VerifyOrDie(ExtendArmFailSafeInternal(proxy, step, params.GetFailsafeTimerSeconds().ValueOr(kDefaultFailsafeTimeout),
3284 : timeout, OnArmFailSafe, OnBasicFailure, /* fireAndForget = */ false));
3285 : }
3286 0 : break;
3287 0 : case CommissioningStage::kReadCommissioningInfo: {
3288 0 : VerifyOrDie(endpoint == kRootEndpointId);
3289 0 : ChipLogProgress(Controller, "Sending read requests for commissioning information");
3290 :
3291 : // Allocate a ClusterStateCache to collect the data from our read requests.
3292 : // The cache will be released in:
3293 : // - SendCommissioningReadRequest when failing to send a read request.
3294 : // - FinishReadingCommissioningInfo when the ReadCommissioningInfo stage is completed.
3295 : // - CancelCommissioningInteractions
3296 0 : mAttributeCache = Platform::MakeUnique<app::ClusterStateCache>(*this);
3297 :
3298 : // Generally we need to make more than one read request, because as per spec a server only
3299 : // supports a limited number of paths per Read Interaction. Because the actual number of
3300 : // interactions we end up performing is dynamic, we track all of them within a single
3301 : // commissioning stage.
3302 0 : mReadCommissioningInfoProgress = 0;
3303 0 : ContinueReadingCommissioningInfo(params); // Note: assume params == delegate.GetCommissioningParameters()
3304 0 : break;
3305 : }
3306 0 : case CommissioningStage::kConfigureUTCTime: {
3307 0 : TimeSynchronization::Commands::SetUTCTime::Type request;
3308 0 : uint64_t kChipEpochUsSinceUnixEpoch = static_cast<uint64_t>(kChipEpochSecondsSinceUnixEpoch) * chip::kMicrosecondsPerSecond;
3309 : System::Clock::Microseconds64 utcTime;
3310 0 : if (System::SystemClock().GetClock_RealTime(utcTime) != CHIP_NO_ERROR || utcTime.count() <= kChipEpochUsSinceUnixEpoch)
3311 : {
3312 : // We have no time to give, but that's OK, just complete this stage
3313 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3314 0 : return;
3315 : }
3316 :
3317 0 : request.UTCTime = utcTime.count() - kChipEpochUsSinceUnixEpoch;
3318 : // For now, we assume a seconds granularity
3319 0 : request.granularity = TimeSynchronization::GranularityEnum::kSecondsGranularity;
3320 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnSetUTCError, endpoint, timeout);
3321 0 : if (err != CHIP_NO_ERROR)
3322 : {
3323 : // We won't get any async callbacks here, so just complete our stage.
3324 0 : ChipLogError(Controller, "Failed to send SetUTCTime command: %" CHIP_ERROR_FORMAT, err.Format());
3325 0 : CommissioningStageComplete(err);
3326 0 : return;
3327 : }
3328 0 : break;
3329 : }
3330 0 : case CommissioningStage::kConfigureTimeZone: {
3331 0 : if (!params.GetTimeZone().HasValue())
3332 : {
3333 0 : ChipLogError(Controller, "ConfigureTimeZone stage called with no time zone data");
3334 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3335 0 : return;
3336 : }
3337 0 : TimeSynchronization::Commands::SetTimeZone::Type request;
3338 0 : request.timeZone = params.GetTimeZone().Value();
3339 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnSetTimeZoneResponse, OnBasicFailure, endpoint, timeout);
3340 0 : if (err != CHIP_NO_ERROR)
3341 : {
3342 : // We won't get any async callbacks here, so just complete our stage.
3343 0 : ChipLogError(Controller, "Failed to send SetTimeZone command: %" CHIP_ERROR_FORMAT, err.Format());
3344 0 : CommissioningStageComplete(err);
3345 0 : return;
3346 : }
3347 0 : break;
3348 : }
3349 0 : case CommissioningStage::kConfigureDSTOffset: {
3350 0 : if (!params.GetDSTOffsets().HasValue())
3351 : {
3352 0 : ChipLogError(Controller, "ConfigureDSTOffset stage called with no DST data");
3353 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3354 0 : return;
3355 : }
3356 0 : TimeSynchronization::Commands::SetDSTOffset::Type request;
3357 0 : request.DSTOffset = params.GetDSTOffsets().Value();
3358 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
3359 0 : if (err != CHIP_NO_ERROR)
3360 : {
3361 : // We won't get any async callbacks here, so just complete our stage.
3362 0 : ChipLogError(Controller, "Failed to send SetDSTOffset command: %" CHIP_ERROR_FORMAT, err.Format());
3363 0 : CommissioningStageComplete(err);
3364 0 : return;
3365 : }
3366 0 : break;
3367 : }
3368 0 : case CommissioningStage::kConfigureDefaultNTP: {
3369 0 : if (!params.GetDefaultNTP().HasValue())
3370 : {
3371 0 : ChipLogError(Controller, "ConfigureDefaultNTP stage called with no default NTP data");
3372 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3373 0 : return;
3374 : }
3375 0 : TimeSynchronization::Commands::SetDefaultNTP::Type request;
3376 0 : request.defaultNTP = params.GetDefaultNTP().Value();
3377 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
3378 0 : if (err != CHIP_NO_ERROR)
3379 : {
3380 : // We won't get any async callbacks here, so just complete our stage.
3381 0 : ChipLogError(Controller, "Failed to send SetDefaultNTP command: %" CHIP_ERROR_FORMAT, err.Format());
3382 0 : CommissioningStageComplete(err);
3383 0 : return;
3384 : }
3385 0 : break;
3386 : }
3387 0 : case CommissioningStage::kScanNetworks: {
3388 0 : NetworkCommissioning::Commands::ScanNetworks::Type request;
3389 0 : if (params.GetWiFiCredentials().HasValue())
3390 : {
3391 0 : request.ssid.Emplace(params.GetWiFiCredentials().Value().ssid);
3392 : }
3393 0 : request.breadcrumb.Emplace(breadcrumb);
3394 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnScanNetworksResponse, OnScanNetworksFailure, endpoint, timeout);
3395 0 : if (err != CHIP_NO_ERROR)
3396 : {
3397 : // We won't get any async callbacks here, so just complete our stage.
3398 0 : ChipLogError(Controller, "Failed to send ScanNetworks command: %" CHIP_ERROR_FORMAT, err.Format());
3399 0 : CommissioningStageComplete(err);
3400 0 : return;
3401 : }
3402 0 : break;
3403 : }
3404 0 : case CommissioningStage::kNeedsNetworkCreds: {
3405 : // Nothing to do.
3406 : //
3407 : // Either we did a scan and the OnScanNetworksSuccess and OnScanNetworksFailure
3408 : // callbacks will tell the DevicePairingDelegate that network credentials are
3409 : // needed, or we asked the DevicePairingDelegate for network credentials
3410 : // explicitly, and are waiting for it to get back to us.
3411 0 : break;
3412 : }
3413 0 : case CommissioningStage::kConfigRegulatory: {
3414 : // TODO(cecille): Worthwhile to keep this around as part of the class?
3415 : // TODO(cecille): Where is the country config actually set?
3416 0 : ChipLogProgress(Controller, "Setting Regulatory Config");
3417 : auto capability =
3418 0 : params.GetLocationCapability().ValueOr(app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kOutdoor);
3419 : app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum regulatoryConfig;
3420 : // Value is only switchable on the devices with indoor/outdoor capability
3421 0 : if (capability == app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kIndoorOutdoor)
3422 : {
3423 : // If the device supports indoor and outdoor configs, use the setting from the commissioner, otherwise fall back to
3424 : // the current device setting then to outdoor (most restrictive)
3425 0 : if (params.GetDeviceRegulatoryLocation().HasValue())
3426 : {
3427 0 : regulatoryConfig = params.GetDeviceRegulatoryLocation().Value();
3428 0 : ChipLogProgress(Controller, "Setting regulatory config to %u from commissioner override",
3429 : static_cast<uint8_t>(regulatoryConfig));
3430 : }
3431 0 : else if (params.GetDefaultRegulatoryLocation().HasValue())
3432 : {
3433 0 : regulatoryConfig = params.GetDefaultRegulatoryLocation().Value();
3434 0 : ChipLogProgress(Controller, "No regulatory config supplied by controller, leaving as device default (%u)",
3435 : static_cast<uint8_t>(regulatoryConfig));
3436 : }
3437 : else
3438 : {
3439 0 : regulatoryConfig = app::Clusters::GeneralCommissioning::RegulatoryLocationTypeEnum::kOutdoor;
3440 0 : ChipLogProgress(Controller, "No overrride or device regulatory config supplied, setting to outdoor");
3441 : }
3442 : }
3443 : else
3444 : {
3445 0 : ChipLogProgress(Controller, "Device does not support configurable regulatory location");
3446 0 : regulatoryConfig = capability;
3447 : }
3448 :
3449 0 : CharSpan countryCode;
3450 0 : const auto & providedCountryCode = params.GetCountryCode();
3451 0 : if (providedCountryCode.HasValue())
3452 : {
3453 0 : countryCode = providedCountryCode.Value();
3454 : }
3455 : else
3456 : {
3457 : // Default to "XX", for lack of anything better.
3458 0 : countryCode = "XX"_span;
3459 : }
3460 :
3461 0 : GeneralCommissioning::Commands::SetRegulatoryConfig::Type request;
3462 0 : request.newRegulatoryConfig = regulatoryConfig;
3463 0 : request.countryCode = countryCode;
3464 0 : request.breadcrumb = breadcrumb;
3465 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnSetRegulatoryConfigResponse, OnBasicFailure, endpoint, timeout);
3466 0 : if (err != CHIP_NO_ERROR)
3467 : {
3468 : // We won't get any async callbacks here, so just complete our stage.
3469 0 : ChipLogError(Controller, "Failed to send SetRegulatoryConfig command: %" CHIP_ERROR_FORMAT, err.Format());
3470 0 : CommissioningStageComplete(err);
3471 0 : return;
3472 : }
3473 : }
3474 0 : break;
3475 0 : case CommissioningStage::kConfigureTCAcknowledgments: {
3476 0 : ChipLogProgress(Controller, "Setting Terms and Conditions");
3477 :
3478 0 : if (!params.GetTermsAndConditionsAcknowledgement().HasValue())
3479 : {
3480 0 : ChipLogProgress(Controller, "Setting Terms and Conditions: Skipped");
3481 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3482 0 : return;
3483 : }
3484 :
3485 0 : GeneralCommissioning::Commands::SetTCAcknowledgements::Type request;
3486 0 : TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value();
3487 0 : request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions;
3488 0 : request.TCVersion = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion;
3489 :
3490 0 : ChipLogProgress(Controller, "Setting Terms and Conditions: %hu, %hu", request.TCUserResponse, request.TCVersion);
3491 : CHIP_ERROR err =
3492 0 : SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout);
3493 0 : if (err != CHIP_NO_ERROR)
3494 : {
3495 0 : ChipLogError(Controller, "Failed to send SetTCAcknowledgements command: %" CHIP_ERROR_FORMAT, err.Format());
3496 0 : CommissioningStageComplete(err);
3497 0 : return;
3498 : }
3499 0 : break;
3500 : }
3501 0 : case CommissioningStage::kSendPAICertificateRequest: {
3502 0 : ChipLogProgress(Controller, "Sending request for PAI certificate");
3503 0 : CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kPAI, timeout);
3504 0 : if (err != CHIP_NO_ERROR)
3505 : {
3506 : // We won't get any async callbacks here, so just complete our stage.
3507 0 : ChipLogError(Controller, "Failed to send CertificateChainRequest command to get PAI: %" CHIP_ERROR_FORMAT,
3508 : err.Format());
3509 0 : CommissioningStageComplete(err);
3510 0 : return;
3511 : }
3512 0 : break;
3513 : }
3514 0 : case CommissioningStage::kSendDACCertificateRequest: {
3515 0 : ChipLogProgress(Controller, "Sending request for DAC certificate");
3516 0 : CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kDAC, timeout);
3517 0 : if (err != CHIP_NO_ERROR)
3518 : {
3519 : // We won't get any async callbacks here, so just complete our stage.
3520 0 : ChipLogError(Controller, "Failed to send CertificateChainRequest command to get DAC: %" CHIP_ERROR_FORMAT,
3521 : err.Format());
3522 0 : CommissioningStageComplete(err);
3523 0 : return;
3524 : }
3525 0 : break;
3526 : }
3527 0 : case CommissioningStage::kSendAttestationRequest: {
3528 0 : ChipLogProgress(Controller, "Sending Attestation Request to the device.");
3529 0 : if (!params.GetAttestationNonce().HasValue())
3530 : {
3531 0 : ChipLogError(Controller, "No attestation nonce found");
3532 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3533 0 : return;
3534 : }
3535 0 : CHIP_ERROR err = SendAttestationRequestCommand(proxy, params.GetAttestationNonce().Value(), timeout);
3536 0 : if (err != CHIP_NO_ERROR)
3537 : {
3538 : // We won't get any async callbacks here, so just complete our stage.
3539 0 : ChipLogError(Controller, "Failed to send AttestationRequest command: %" CHIP_ERROR_FORMAT, err.Format());
3540 0 : CommissioningStageComplete(err);
3541 0 : return;
3542 : }
3543 0 : break;
3544 : }
3545 0 : case CommissioningStage::kAttestationVerification: {
3546 0 : ChipLogProgress(Controller, "Verifying Device Attestation information received from the device");
3547 0 : if (IsAttestationInformationMissing(params))
3548 : {
3549 0 : ChipLogError(Controller, "Missing attestation information");
3550 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3551 0 : return;
3552 : }
3553 :
3554 : DeviceAttestationVerifier::AttestationInfo info(
3555 0 : params.GetAttestationElements().Value(),
3556 0 : proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge(),
3557 0 : params.GetAttestationSignature().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
3558 0 : params.GetAttestationNonce().Value(), params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value());
3559 :
3560 0 : CHIP_ERROR err = ValidateAttestationInfo(info);
3561 0 : if (err != CHIP_NO_ERROR)
3562 : {
3563 0 : ChipLogError(Controller, "Error validating attestation information: %" CHIP_ERROR_FORMAT, err.Format());
3564 0 : CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION);
3565 0 : return;
3566 : }
3567 : }
3568 0 : break;
3569 0 : case CommissioningStage::kAttestationRevocationCheck: {
3570 0 : ChipLogProgress(Controller, "Verifying the device's DAC chain revocation status");
3571 0 : if (IsAttestationInformationMissing(params))
3572 : {
3573 0 : ChipLogError(Controller, "Missing attestation information");
3574 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3575 0 : return;
3576 : }
3577 :
3578 : DeviceAttestationVerifier::AttestationInfo info(
3579 0 : params.GetAttestationElements().Value(),
3580 0 : proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge(),
3581 0 : params.GetAttestationSignature().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
3582 0 : params.GetAttestationNonce().Value(), params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value());
3583 :
3584 0 : CHIP_ERROR err = CheckForRevokedDACChain(info);
3585 :
3586 0 : if (err != CHIP_NO_ERROR)
3587 : {
3588 0 : ChipLogError(Controller, "Error validating device's DAC chain revocation status: %" CHIP_ERROR_FORMAT, err.Format());
3589 0 : CommissioningStageComplete(CHIP_ERROR_FAILED_DEVICE_ATTESTATION);
3590 0 : return;
3591 : }
3592 : }
3593 0 : break;
3594 0 : case CommissioningStage::kJCMTrustVerification: {
3595 0 : CHIP_ERROR err = StartJCMTrustVerification(proxy);
3596 0 : if (err != CHIP_NO_ERROR)
3597 : {
3598 0 : ChipLogError(Controller, "Failed to start JCM Trust Verification: %" CHIP_ERROR_FORMAT, err.Format());
3599 0 : CommissioningStageComplete(err);
3600 0 : return;
3601 : }
3602 0 : break;
3603 : }
3604 :
3605 0 : case CommissioningStage::kSendOpCertSigningRequest: {
3606 0 : if (!params.GetCSRNonce().HasValue())
3607 : {
3608 0 : ChipLogError(Controller, "No CSR nonce found");
3609 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3610 0 : return;
3611 : }
3612 0 : CHIP_ERROR err = SendOperationalCertificateSigningRequestCommand(proxy, params.GetCSRNonce().Value(), timeout);
3613 0 : if (err != CHIP_NO_ERROR)
3614 : {
3615 : // We won't get any async callbacks here, so just complete our stage.
3616 0 : ChipLogError(Controller, "Failed to send CSR request: %" CHIP_ERROR_FORMAT, err.Format());
3617 0 : CommissioningStageComplete(err);
3618 0 : return;
3619 : }
3620 0 : break;
3621 : }
3622 0 : case CommissioningStage::kValidateCSR: {
3623 0 : if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetCSRNonce().HasValue())
3624 : {
3625 0 : ChipLogError(Controller, "Unable to validate CSR");
3626 0 : return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3627 : }
3628 : // This is non-blocking, so send the callback immediately.
3629 0 : CHIP_ERROR err = ValidateCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
3630 0 : params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
3631 0 : params.GetCSRNonce().Value());
3632 0 : if (err != CHIP_NO_ERROR)
3633 : {
3634 0 : ChipLogError(Controller, "Failed to validate CSR: %" CHIP_ERROR_FORMAT, err.Format());
3635 : }
3636 0 : CommissioningStageComplete(err);
3637 0 : return;
3638 : }
3639 : break;
3640 0 : case CommissioningStage::kGenerateNOCChain: {
3641 0 : if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetPAI().HasValue() ||
3642 0 : !params.GetCSRNonce().HasValue())
3643 : {
3644 0 : ChipLogError(Controller, "Unable to generate NOC chain parameters");
3645 0 : return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3646 : }
3647 0 : CHIP_ERROR err = ProcessCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
3648 0 : params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
3649 0 : params.GetPAI().Value(), params.GetCSRNonce().Value());
3650 0 : if (err != CHIP_NO_ERROR)
3651 : {
3652 0 : ChipLogError(Controller, "Failed to process Operational Certificate Signing Request (CSR): %" CHIP_ERROR_FORMAT,
3653 : err.Format());
3654 0 : CommissioningStageComplete(err);
3655 0 : return;
3656 : }
3657 : }
3658 0 : break;
3659 0 : case CommissioningStage::kSendTrustedRootCert: {
3660 0 : if (!params.GetRootCert().HasValue() || !params.GetNoc().HasValue())
3661 : {
3662 0 : ChipLogError(Controller, "No trusted root cert or NOC specified");
3663 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3664 0 : return;
3665 : }
3666 0 : CHIP_ERROR err = SendTrustedRootCertificate(proxy, params.GetRootCert().Value(), timeout);
3667 0 : if (err != CHIP_NO_ERROR)
3668 : {
3669 0 : ChipLogError(Controller, "Error sending trusted root certificate: %" CHIP_ERROR_FORMAT, err.Format());
3670 0 : CommissioningStageComplete(err);
3671 0 : return;
3672 : }
3673 :
3674 0 : err = proxy->SetPeerId(params.GetRootCert().Value(), params.GetNoc().Value());
3675 0 : if (err != CHIP_NO_ERROR)
3676 : {
3677 0 : ChipLogError(Controller, "Error setting peer id: %" CHIP_ERROR_FORMAT, err.Format());
3678 0 : CommissioningStageComplete(err);
3679 0 : return;
3680 : }
3681 0 : if (!IsOperationalNodeId(proxy->GetDeviceId()))
3682 : {
3683 0 : ChipLogError(Controller, "Given node ID is not an operational node ID");
3684 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3685 0 : return;
3686 : }
3687 : }
3688 0 : break;
3689 0 : case CommissioningStage::kSendNOC: {
3690 0 : if (!params.GetNoc().HasValue() || !params.GetIpk().HasValue() || !params.GetAdminSubject().HasValue())
3691 : {
3692 0 : ChipLogError(Controller, "AddNOC contents not specified");
3693 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3694 0 : return;
3695 : }
3696 0 : CHIP_ERROR err = SendOperationalCertificate(proxy, params.GetNoc().Value(), params.GetIcac(), params.GetIpk().Value(),
3697 0 : params.GetAdminSubject().Value(), timeout);
3698 0 : if (err != CHIP_NO_ERROR)
3699 : {
3700 : // We won't get any async callbacks here, so just complete our stage.
3701 0 : ChipLogError(Controller, "Error installing operational certificate with AddNOC: %" CHIP_ERROR_FORMAT, err.Format());
3702 0 : CommissioningStageComplete(err);
3703 0 : return;
3704 : }
3705 0 : break;
3706 : }
3707 0 : case CommissioningStage::kConfigureTrustedTimeSource: {
3708 0 : if (!params.GetTrustedTimeSource().HasValue())
3709 : {
3710 0 : ChipLogError(Controller, "ConfigureTrustedTimeSource stage called with no trusted time source data!");
3711 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3712 0 : return;
3713 : }
3714 0 : TimeSynchronization::Commands::SetTrustedTimeSource::Type request;
3715 0 : request.trustedTimeSource = params.GetTrustedTimeSource().Value();
3716 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnBasicSuccess, OnBasicFailure, endpoint, timeout);
3717 0 : if (err != CHIP_NO_ERROR)
3718 : {
3719 : // We won't get any async callbacks here, so just complete our stage.
3720 0 : ChipLogError(Controller, "Failed to send SendTrustedTimeSource command: %" CHIP_ERROR_FORMAT, err.Format());
3721 0 : CommissioningStageComplete(err);
3722 0 : return;
3723 : }
3724 0 : break;
3725 : }
3726 0 : case CommissioningStage::kRequestWiFiCredentials: {
3727 0 : if (!mPairingDelegate)
3728 : {
3729 0 : ChipLogError(Controller, "Unable to request Wi-Fi credentials: no delegate available");
3730 0 : CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
3731 0 : return;
3732 : }
3733 :
3734 0 : CHIP_ERROR err = mPairingDelegate->WiFiCredentialsNeeded(endpoint);
3735 0 : CommissioningStageComplete(err);
3736 0 : return;
3737 : }
3738 0 : case CommissioningStage::kRequestThreadCredentials: {
3739 0 : if (!mPairingDelegate)
3740 : {
3741 0 : ChipLogError(Controller, "Unable to request Thread credentials: no delegate available");
3742 0 : CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
3743 0 : return;
3744 : }
3745 :
3746 0 : CHIP_ERROR err = mPairingDelegate->ThreadCredentialsNeeded(endpoint);
3747 0 : CommissioningStageComplete(err);
3748 0 : return;
3749 : }
3750 0 : case CommissioningStage::kWiFiNetworkSetup: {
3751 0 : if (!params.GetWiFiCredentials().HasValue())
3752 : {
3753 0 : ChipLogError(Controller, "No wifi credentials specified");
3754 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3755 0 : return;
3756 : }
3757 :
3758 0 : NetworkCommissioning::Commands::AddOrUpdateWiFiNetwork::Type request;
3759 0 : request.ssid = params.GetWiFiCredentials().Value().ssid;
3760 0 : request.credentials = params.GetWiFiCredentials().Value().credentials;
3761 0 : request.breadcrumb.Emplace(breadcrumb);
3762 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
3763 0 : if (err != CHIP_NO_ERROR)
3764 : {
3765 : // We won't get any async callbacks here, so just complete our stage.
3766 0 : ChipLogError(Controller, "Failed to send AddOrUpdateWiFiNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3767 0 : CommissioningStageComplete(err);
3768 0 : return;
3769 : }
3770 : }
3771 0 : break;
3772 0 : case CommissioningStage::kThreadNetworkSetup: {
3773 0 : if (!params.GetThreadOperationalDataset().HasValue())
3774 : {
3775 0 : ChipLogError(Controller, "No thread credentials specified");
3776 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3777 0 : return;
3778 : }
3779 0 : NetworkCommissioning::Commands::AddOrUpdateThreadNetwork::Type request;
3780 0 : request.operationalDataset = params.GetThreadOperationalDataset().Value();
3781 0 : request.breadcrumb.Emplace(breadcrumb);
3782 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
3783 0 : if (err != CHIP_NO_ERROR)
3784 : {
3785 : // We won't get any async callbacks here, so just complete our stage.
3786 0 : ChipLogError(Controller, "Failed to send AddOrUpdateThreadNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3787 0 : CommissioningStageComplete(err);
3788 0 : return;
3789 : }
3790 : }
3791 0 : break;
3792 0 : case CommissioningStage::kFailsafeBeforeWiFiEnable:
3793 : FALLTHROUGH;
3794 : case CommissioningStage::kFailsafeBeforeThreadEnable:
3795 : // Before we try to do network enablement, make sure that our fail-safe
3796 : // is set far enough out that we can later try to do operational
3797 : // discovery without it timing out.
3798 0 : ExtendFailsafeBeforeNetworkEnable(proxy, params, step);
3799 0 : break;
3800 0 : case CommissioningStage::kWiFiNetworkEnable: {
3801 0 : if (!params.GetWiFiCredentials().HasValue())
3802 : {
3803 0 : ChipLogError(Controller, "No wifi credentials specified");
3804 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3805 0 : return;
3806 : }
3807 0 : NetworkCommissioning::Commands::ConnectNetwork::Type request;
3808 0 : request.networkID = params.GetWiFiCredentials().Value().ssid;
3809 0 : request.breadcrumb.Emplace(breadcrumb);
3810 :
3811 0 : CHIP_ERROR err = CHIP_NO_ERROR;
3812 0 : ChipLogProgress(Controller, "SendCommand kWiFiNetworkEnable, supportsConcurrentConnection=%s",
3813 : params.GetSupportsConcurrentConnection().HasValue()
3814 : ? (params.GetSupportsConcurrentConnection().Value() ? "true" : "false")
3815 : : "missing");
3816 0 : err = SendCommissioningCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout);
3817 :
3818 0 : if (err != CHIP_NO_ERROR)
3819 : {
3820 : // We won't get any async callbacks here, so just complete our stage.
3821 0 : ChipLogError(Controller, "Failed to send WiFi ConnectNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3822 0 : CommissioningStageComplete(err);
3823 0 : return;
3824 : }
3825 : }
3826 0 : break;
3827 0 : case CommissioningStage::kThreadNetworkEnable: {
3828 0 : ByteSpan extendedPanId;
3829 0 : chip::Thread::OperationalDataset operationalDataset;
3830 0 : if (!params.GetThreadOperationalDataset().HasValue() ||
3831 0 : operationalDataset.Init(params.GetThreadOperationalDataset().Value()) != CHIP_NO_ERROR ||
3832 0 : operationalDataset.GetExtendedPanIdAsByteSpan(extendedPanId) != CHIP_NO_ERROR)
3833 : {
3834 0 : ChipLogError(Controller, "Invalid Thread operational dataset configured at commissioner!");
3835 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3836 0 : return;
3837 : }
3838 0 : NetworkCommissioning::Commands::ConnectNetwork::Type request;
3839 0 : request.networkID = extendedPanId;
3840 0 : request.breadcrumb.Emplace(breadcrumb);
3841 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout);
3842 0 : if (err != CHIP_NO_ERROR)
3843 : {
3844 : // We won't get any async callbacks here, so just complete our stage.
3845 0 : ChipLogError(Controller, "Failed to send Thread ConnectNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3846 0 : CommissioningStageComplete(err);
3847 0 : return;
3848 : }
3849 : }
3850 0 : break;
3851 0 : case CommissioningStage::kICDGetRegistrationInfo: {
3852 0 : GetPairingDelegate()->OnICDRegistrationInfoRequired();
3853 0 : return;
3854 : }
3855 : break;
3856 0 : case CommissioningStage::kICDRegistration: {
3857 0 : IcdManagement::Commands::RegisterClient::Type request;
3858 :
3859 0 : if (!(params.GetICDCheckInNodeId().HasValue() && params.GetICDMonitoredSubject().HasValue() &&
3860 0 : params.GetICDSymmetricKey().HasValue()))
3861 : {
3862 0 : ChipLogError(Controller, "No ICD Registration information provided!");
3863 0 : CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
3864 0 : return;
3865 : }
3866 :
3867 0 : request.checkInNodeID = params.GetICDCheckInNodeId().Value();
3868 0 : request.monitoredSubject = params.GetICDMonitoredSubject().Value();
3869 0 : request.key = params.GetICDSymmetricKey().Value();
3870 :
3871 : CHIP_ERROR err =
3872 0 : SendCommissioningCommand(proxy, request, OnICDManagementRegisterClientResponse, OnBasicFailure, endpoint, timeout);
3873 0 : if (err != CHIP_NO_ERROR)
3874 : {
3875 : // We won't get any async callbacks here, so just complete our stage.
3876 0 : ChipLogError(Controller, "Failed to send IcdManagement.RegisterClient command: %" CHIP_ERROR_FORMAT, err.Format());
3877 0 : CommissioningStageComplete(err);
3878 0 : return;
3879 : }
3880 : }
3881 0 : break;
3882 0 : case CommissioningStage::kEvictPreviousCaseSessions: {
3883 0 : auto scopedPeerId = GetPeerScopedId(proxy->GetDeviceId());
3884 :
3885 : // If we ever had a commissioned device with this node ID before, we may
3886 : // have stale sessions to it. Make sure we don't re-use any of those,
3887 : // because clearly they are not related to this new device we are
3888 : // commissioning. We only care about sessions we might reuse, so just
3889 : // clearing the ones associated with our fabric index is good enough and
3890 : // we don't need to worry about ExpireAllSessionsOnLogicalFabric.
3891 0 : mSystemState->SessionMgr()->ExpireAllSessions(scopedPeerId);
3892 : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
3893 : Transport::Type type = proxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress().GetTransportType();
3894 : // cache address if we are connected over TCP or UDP
3895 : if (type == Transport::Type::kTcp || type == Transport::Type::kUdp)
3896 : {
3897 : // Store the address we are using for PASE as a fallback for operational discovery
3898 : ResolveResult result;
3899 : result.address = proxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress();
3900 : result.mrpRemoteConfig = proxy->GetSecureSession().Value()->GetRemoteMRPConfig();
3901 : // Note: supportsTcpClient and supportsTcpServer are device capabilities from DNS-SD TXT records,
3902 : // not derivable from the transport type. They remain false (default) here.
3903 : // TODO: Consider passing these through RendezvousParameters if available from SetUpCodePairer.
3904 : mFallbackOperationalResolveResult.SetValue(result);
3905 : }
3906 : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
3907 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3908 0 : return;
3909 : }
3910 0 : case CommissioningStage::kFindOperationalForStayActive:
3911 : case CommissioningStage::kFindOperationalForCommissioningComplete: {
3912 : // If there is an error, CommissioningStageComplete will be called from OnDeviceConnectionFailureFn.
3913 0 : auto scopedPeerId = GetPeerScopedId(proxy->GetDeviceId());
3914 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCommissioningOperationalSetup);
3915 0 : mSystemState->CASESessionMgr()->FindOrEstablishSession(
3916 : scopedPeerId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback,
3917 : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
3918 : /* attemptCount = */ 3, &mOnDeviceConnectionRetryCallback,
3919 : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
3920 0 : TransportPayloadCapability::kMRPPayload, mFallbackOperationalResolveResult);
3921 : }
3922 0 : break;
3923 0 : case CommissioningStage::kPrimaryOperationalNetworkFailed: {
3924 : // nothing to do. This stage indicates that the primary operational network failed and the network config should be
3925 : // removed later.
3926 0 : break;
3927 : }
3928 0 : case CommissioningStage::kRemoveWiFiNetworkConfig: {
3929 0 : NetworkCommissioning::Commands::RemoveNetwork::Type request;
3930 0 : request.networkID = params.GetWiFiCredentials().Value().ssid;
3931 0 : request.breadcrumb.Emplace(breadcrumb);
3932 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
3933 0 : if (err != CHIP_NO_ERROR)
3934 : {
3935 : // We won't get any async callbacks here, so just complete our stage.
3936 0 : ChipLogError(Controller, "Failed to send RemoveNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3937 0 : CommissioningStageComplete(err);
3938 0 : return;
3939 : }
3940 0 : break;
3941 : }
3942 0 : case CommissioningStage::kRemoveThreadNetworkConfig: {
3943 0 : ByteSpan extendedPanId;
3944 0 : chip::Thread::OperationalDataset operationalDataset;
3945 0 : if (!params.GetThreadOperationalDataset().HasValue() ||
3946 0 : operationalDataset.Init(params.GetThreadOperationalDataset().Value()) != CHIP_NO_ERROR ||
3947 0 : operationalDataset.GetExtendedPanIdAsByteSpan(extendedPanId) != CHIP_NO_ERROR)
3948 : {
3949 0 : ChipLogError(Controller, "Invalid Thread operational dataset configured at commissioner!");
3950 0 : CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
3951 0 : return;
3952 : }
3953 0 : NetworkCommissioning::Commands::RemoveNetwork::Type request;
3954 0 : request.networkID = extendedPanId;
3955 0 : request.breadcrumb.Emplace(breadcrumb);
3956 0 : CHIP_ERROR err = SendCommissioningCommand(proxy, request, OnNetworkConfigResponse, OnBasicFailure, endpoint, timeout);
3957 0 : if (err != CHIP_NO_ERROR)
3958 : {
3959 : // We won't get any async callbacks here, so just complete our stage.
3960 0 : ChipLogError(Controller, "Failed to send RemoveNetwork command: %" CHIP_ERROR_FORMAT, err.Format());
3961 0 : CommissioningStageComplete(err);
3962 0 : return;
3963 : }
3964 0 : break;
3965 : }
3966 0 : case CommissioningStage::kICDSendStayActive: {
3967 0 : if (!(params.GetICDStayActiveDurationMsec().HasValue()))
3968 : {
3969 0 : ChipLogProgress(Controller, "Skipping kICDSendStayActive");
3970 0 : CommissioningStageComplete(CHIP_NO_ERROR);
3971 0 : return;
3972 : }
3973 :
3974 : // StayActive Command happens over CASE Connection
3975 0 : IcdManagement::Commands::StayActiveRequest::Type request;
3976 0 : request.stayActiveDuration = params.GetICDStayActiveDurationMsec().Value();
3977 0 : ChipLogError(Controller, "Send ICD StayActive with Duration %u", request.stayActiveDuration);
3978 : CHIP_ERROR err =
3979 0 : SendCommissioningCommand(proxy, request, OnICDManagementStayActiveResponse, OnBasicFailure, endpoint, timeout);
3980 0 : if (err != CHIP_NO_ERROR)
3981 : {
3982 : // We won't get any async callbacks here, so just complete our stage.
3983 0 : ChipLogError(Controller, "Failed to send IcdManagement.StayActive command: %" CHIP_ERROR_FORMAT, err.Format());
3984 0 : CommissioningStageComplete(err);
3985 0 : return;
3986 : }
3987 : }
3988 0 : break;
3989 0 : case CommissioningStage::kSendComplete: {
3990 : // CommissioningComplete command happens over the CASE connection.
3991 : GeneralCommissioning::Commands::CommissioningComplete::Type request;
3992 : CHIP_ERROR err =
3993 0 : SendCommissioningCommand(proxy, request, OnCommissioningCompleteResponse, OnBasicFailure, endpoint, timeout);
3994 0 : if (err != CHIP_NO_ERROR)
3995 : {
3996 : // We won't get any async callbacks here, so just complete our stage.
3997 0 : ChipLogError(Controller, "Failed to send CommissioningComplete command: %" CHIP_ERROR_FORMAT, err.Format());
3998 0 : CommissioningStageComplete(err);
3999 0 : return;
4000 : }
4001 : }
4002 0 : break;
4003 : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
4004 : case CommissioningStage::kUnpoweredPhaseComplete:
4005 : ChipLogProgress(Controller, "Completed unpowered commissioning phase, marking commissioning as complete");
4006 : CommissioningStageComplete(CHIP_NO_ERROR);
4007 : break;
4008 : #endif
4009 0 : case CommissioningStage::kCleanup:
4010 0 : CleanupCommissioning(proxy, proxy->GetDeviceId(), params.GetCompletionStatus());
4011 0 : break;
4012 0 : case CommissioningStage::kError:
4013 0 : mCommissioningStage = CommissioningStage::kSecurePairing;
4014 0 : break;
4015 0 : case CommissioningStage::kSecurePairing:
4016 0 : break;
4017 : }
4018 : }
4019 :
4020 0 : void DeviceCommissioner::ExtendFailsafeBeforeNetworkEnable(DeviceProxy * device, CommissioningParameters & params,
4021 : CommissioningStage step)
4022 : {
4023 0 : auto * commissioneeDevice = FindCommissioneeDevice(device->GetDeviceId());
4024 0 : if (device != commissioneeDevice)
4025 : {
4026 : // Not a commissionee device; just return.
4027 0 : ChipLogError(Controller, "Trying to extend fail-safe for an unknown commissionee with device id " ChipLogFormatX64,
4028 : ChipLogValueX64(device->GetDeviceId()));
4029 0 : CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE, CommissioningDelegate::CommissioningReport());
4030 0 : return;
4031 : }
4032 :
4033 : // Try to make sure we have at least enough time for our expected
4034 : // commissioning bits plus the MRP retries for a Sigma1.
4035 0 : uint16_t failSafeTimeoutSecs = params.GetFailsafeTimerSeconds().ValueOr(kDefaultFailsafeTimeout);
4036 0 : auto sigma1Timeout = CASESession::ComputeSigma1ResponseTimeout(commissioneeDevice->GetPairing().GetRemoteMRPConfig());
4037 0 : uint16_t sigma1TimeoutSecs = std::chrono::duration_cast<System::Clock::Seconds16>(sigma1Timeout).count();
4038 0 : if (UINT16_MAX - failSafeTimeoutSecs < sigma1TimeoutSecs)
4039 : {
4040 0 : failSafeTimeoutSecs = UINT16_MAX;
4041 : }
4042 : else
4043 : {
4044 0 : failSafeTimeoutSecs = static_cast<uint16_t>(failSafeTimeoutSecs + sigma1TimeoutSecs);
4045 : }
4046 :
4047 0 : if (!ExtendArmFailSafeInternal(commissioneeDevice, step, failSafeTimeoutSecs, MakeOptional(kMinimumCommissioningStepTimeout),
4048 : OnArmFailSafe, OnBasicFailure, /* fireAndForget = */ false))
4049 : {
4050 : // A false return is fine; we don't want to make the fail-safe shorter here.
4051 0 : CommissioningStageComplete(CHIP_NO_ERROR, CommissioningDelegate::CommissioningReport());
4052 : }
4053 : }
4054 :
4055 0 : bool DeviceCommissioner::IsAttestationInformationMissing(const CommissioningParameters & params)
4056 : {
4057 0 : if (!params.GetAttestationElements().HasValue() || !params.GetAttestationSignature().HasValue() ||
4058 0 : !params.GetAttestationNonce().HasValue() || !params.GetDAC().HasValue() || !params.GetPAI().HasValue() ||
4059 0 : !params.GetRemoteVendorId().HasValue() || !params.GetRemoteProductId().HasValue())
4060 : {
4061 0 : return true;
4062 : }
4063 :
4064 0 : return false;
4065 : }
4066 :
4067 0 : CHIP_ERROR DeviceController::GetCompressedFabricIdBytes(MutableByteSpan & outBytes) const
4068 : {
4069 0 : const auto * fabricInfo = GetFabricInfo();
4070 0 : VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
4071 0 : return fabricInfo->GetCompressedFabricIdBytes(outBytes);
4072 : }
4073 :
4074 0 : CHIP_ERROR DeviceController::GetRootPublicKey(Crypto::P256PublicKey & outRootPublicKey) const
4075 : {
4076 0 : const auto * fabricTable = GetFabricTable();
4077 0 : VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
4078 0 : return fabricTable->FetchRootPubkey(mFabricIndex, outRootPublicKey);
4079 : }
4080 :
4081 0 : bool DeviceCommissioner::HasValidCommissioningMode(const Dnssd::CommissionNodeData & nodeData)
4082 : {
4083 0 : if (nodeData.commissioningMode == to_underlying(Dnssd::CommissioningMode::kDisabled))
4084 : {
4085 0 : ChipLogProgress(Controller, "Discovered device does not have an open commissioning window.");
4086 0 : return false;
4087 : }
4088 0 : return true;
4089 : }
4090 :
4091 : } // namespace Controller
4092 : } // namespace chip
|