Matter SDK Coverage Report
Current view: top level - controller - AutoCommissioner.cpp (source / functions) Coverage Total Hit
Test: SHA:09f6fdf93a7e847a42518c076e487f336877a722 Lines: 16.7 % 498 83
Test Date: 2025-06-07 07:10:33 Functions: 23.8 % 21 5

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2024 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : #include <controller/AutoCommissioner.h>
      20              : 
      21              : #include <app/InteractionModelTimeout.h>
      22              : #include <controller/CHIPDeviceController.h>
      23              : #include <credentials/CHIPCert.h>
      24              : #include <lib/support/SafeInt.h>
      25              : 
      26              : #include <cstring>
      27              : #include <type_traits>
      28              : 
      29              : namespace chip {
      30              : namespace Controller {
      31              : 
      32              : using namespace chip::app::Clusters;
      33              : using namespace chip::Crypto;
      34              : using chip::app::DataModel::MakeNullable;
      35              : using chip::app::DataModel::NullNullable;
      36              : 
      37           30 : AutoCommissioner::AutoCommissioner()
      38              : {
      39           10 :     SetCommissioningParameters(CommissioningParameters());
      40           10 : }
      41              : 
      42           10 : AutoCommissioner::~AutoCommissioner() {}
      43              : 
      44            0 : void AutoCommissioner::SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate)
      45              : {
      46            0 :     mOperationalCredentialsDelegate = operationalCredentialsDelegate;
      47            0 : }
      48              : 
      49            1 : CHIP_ERROR AutoCommissioner::VerifyICDRegistrationInfo(const CommissioningParameters & params)
      50              : {
      51            1 :     ChipLogProgress(Controller, "Checking ICD registration parameters");
      52            1 :     if (!params.GetICDSymmetricKey().HasValue())
      53              :     {
      54            0 :         ChipLogError(Controller, "Missing ICD symmetric key!");
      55            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      56              :     }
      57            1 :     if (params.GetICDSymmetricKey().Value().size() != sizeof(mICDSymmetricKey))
      58              :     {
      59            0 :         ChipLogError(Controller, "Invalid ICD symmetric key length!");
      60            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      61              :     }
      62            1 :     if (!params.GetICDCheckInNodeId().HasValue())
      63              :     {
      64            0 :         ChipLogError(Controller, "Missing ICD check-in node id!");
      65            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      66              :     }
      67            1 :     if (!params.GetICDMonitoredSubject().HasValue())
      68              :     {
      69            0 :         ChipLogError(Controller, "Missing ICD monitored subject!");
      70            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      71              :     }
      72            1 :     if (!params.GetICDClientType().HasValue())
      73              :     {
      74            0 :         ChipLogError(Controller, "Missing ICD Client Type!");
      75            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
      76              :     }
      77            1 :     return CHIP_NO_ERROR;
      78              : }
      79              : 
      80           19 : CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParameters & params)
      81              : {
      82              :     // Our logic below assumes that we can modify mParams without affecting params.
      83           19 :     VerifyOrReturnError(&params != &mParams, CHIP_NO_ERROR);
      84              : 
      85              :     // Copy the whole struct (scalars and pointers), but clear any members that might point to
      86              :     // external buffers. For those members we have to copy the data over into our own buffers below.
      87              :     // Note that all of the copy operations use memmove() instead of memcpy(), because the caller
      88              :     // may be passing a modified shallow copy of our CommissioningParmeters, i.e. where various spans
      89              :     // already point into the buffers we're copying into, and memcpy() with overlapping buffers is UB.
      90           19 :     mParams = params;
      91           19 :     mParams.ClearExternalBufferDependentValues();
      92              : 
      93           19 :     if (params.GetThreadOperationalDataset().HasValue())
      94              :     {
      95            1 :         ByteSpan dataset = params.GetThreadOperationalDataset().Value();
      96            1 :         if (dataset.size() > CommissioningParameters::kMaxThreadDatasetLen)
      97              :         {
      98            1 :             ChipLogError(Controller, "Thread operational data set is too large");
      99            1 :             return CHIP_ERROR_INVALID_ARGUMENT;
     100              :         }
     101            0 :         memmove(mThreadOperationalDataset, dataset.data(), dataset.size());
     102            0 :         ChipLogProgress(Controller, "Setting thread operational dataset from parameters");
     103            0 :         mParams.SetThreadOperationalDataset(ByteSpan(mThreadOperationalDataset, dataset.size()));
     104              :     }
     105              : 
     106           18 :     if (params.GetWiFiCredentials().HasValue())
     107              :     {
     108            1 :         WiFiCredentials creds = params.GetWiFiCredentials().Value();
     109            1 :         if (creds.ssid.size() > CommissioningParameters::kMaxSsidLen ||
     110            0 :             creds.credentials.size() > CommissioningParameters::kMaxCredentialsLen)
     111              :         {
     112            1 :             ChipLogError(Controller, "Wifi credentials are too large");
     113            1 :             return CHIP_ERROR_INVALID_ARGUMENT;
     114              :         }
     115            0 :         memmove(mSsid, creds.ssid.data(), creds.ssid.size());
     116            0 :         memmove(mCredentials, creds.credentials.data(), creds.credentials.size());
     117            0 :         ChipLogProgress(Controller, "Setting wifi credentials from parameters");
     118            0 :         mParams.SetWiFiCredentials(
     119            0 :             WiFiCredentials(ByteSpan(mSsid, creds.ssid.size()), ByteSpan(mCredentials, creds.credentials.size())));
     120              :     }
     121              : 
     122           17 :     if (params.GetCountryCode().HasValue())
     123              :     {
     124            1 :         auto code = params.GetCountryCode().Value();
     125            1 :         MutableCharSpan copiedCode(mCountryCode);
     126            1 :         if (CopyCharSpanToMutableCharSpan(code, copiedCode) == CHIP_NO_ERROR)
     127              :         {
     128            0 :             mParams.SetCountryCode(copiedCode);
     129              :         }
     130              :         else
     131              :         {
     132            1 :             ChipLogError(Controller, "Country code is too large: %u", static_cast<unsigned>(code.size()));
     133            1 :             return CHIP_ERROR_INVALID_ARGUMENT;
     134              :         }
     135              :     }
     136              : 
     137              :     // If the AttestationNonce is passed in, using that else using a random one..
     138           16 :     if (params.GetAttestationNonce().HasValue())
     139              :     {
     140            1 :         ChipLogProgress(Controller, "Setting attestation nonce from parameters");
     141            1 :         VerifyOrReturnError(params.GetAttestationNonce().Value().size() == sizeof(mAttestationNonce), CHIP_ERROR_INVALID_ARGUMENT);
     142            0 :         memmove(mAttestationNonce, params.GetAttestationNonce().Value().data(), params.GetAttestationNonce().Value().size());
     143              :     }
     144              :     else
     145              :     {
     146           15 :         ChipLogProgress(Controller, "Setting attestation nonce to random value");
     147           15 :         Crypto::DRBG_get_bytes(mAttestationNonce, sizeof(mAttestationNonce));
     148              :     }
     149           15 :     mParams.SetAttestationNonce(ByteSpan(mAttestationNonce, sizeof(mAttestationNonce)));
     150              : 
     151           15 :     if (params.GetCSRNonce().HasValue())
     152              :     {
     153            1 :         ChipLogProgress(Controller, "Setting CSR nonce from parameters");
     154            1 :         VerifyOrReturnError(params.GetCSRNonce().Value().size() == sizeof(mCSRNonce), CHIP_ERROR_INVALID_ARGUMENT);
     155            0 :         memmove(mCSRNonce, params.GetCSRNonce().Value().data(), params.GetCSRNonce().Value().size());
     156              :     }
     157              :     else
     158              :     {
     159           14 :         ChipLogProgress(Controller, "Setting CSR nonce to random value");
     160           14 :         Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
     161              :     }
     162           14 :     mParams.SetCSRNonce(ByteSpan(mCSRNonce, sizeof(mCSRNonce)));
     163              : 
     164           14 :     if (params.GetDSTOffsets().HasValue())
     165              :     {
     166            1 :         ChipLogProgress(Controller, "Setting DST offsets from parameters");
     167            1 :         size_t size = std::min(params.GetDSTOffsets().Value().size(), kMaxSupportedDstStructs);
     168            2 :         for (size_t i = 0; i < size; ++i)
     169              :         {
     170            1 :             mDstOffsetsBuf[i] = params.GetDSTOffsets().Value()[i];
     171              :         }
     172            1 :         auto list = app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>(mDstOffsetsBuf, size);
     173            1 :         mParams.SetDSTOffsets(list);
     174              :     }
     175           14 :     if (params.GetTimeZone().HasValue())
     176              :     {
     177            1 :         ChipLogProgress(Controller, "Setting Time Zone from parameters");
     178            1 :         size_t size = std::min(params.GetTimeZone().Value().size(), kMaxSupportedTimeZones);
     179            2 :         for (size_t i = 0; i < size; ++i)
     180              :         {
     181            1 :             mTimeZoneBuf[i] = params.GetTimeZone().Value()[i];
     182            2 :             if (params.GetTimeZone().Value()[i].name.HasValue() &&
     183            2 :                 params.GetTimeZone().Value()[i].name.Value().size() <= kMaxTimeZoneNameLen)
     184              :             {
     185            1 :                 auto span = MutableCharSpan(mTimeZoneNames[i], kMaxTimeZoneNameLen);
     186              :                 // The buffer backing "span" is statically allocated and is of size kMaxSupportedTimeZones, so this should never
     187              :                 // fail.
     188            1 :                 CopyCharSpanToMutableCharSpan(params.GetTimeZone().Value()[i].name.Value(), span);
     189            1 :                 mTimeZoneBuf[i].name.SetValue(span);
     190              :             }
     191              :             else
     192              :             {
     193            0 :                 mTimeZoneBuf[i].name.ClearValue();
     194              :             }
     195              :         }
     196            1 :         auto list = app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>(mTimeZoneBuf, size);
     197            1 :         mParams.SetTimeZone(list);
     198              :     }
     199           14 :     if (params.GetDefaultNTP().HasValue())
     200              :     {
     201            1 :         ChipLogProgress(Controller, "Setting Default NTP from parameters");
     202              :         // This parameter is an optional nullable, so we need to go two levels deep here.
     203            1 :         if (!params.GetDefaultNTP().Value().IsNull() && params.GetDefaultNTP().Value().Value().size() <= kMaxDefaultNtpSize)
     204              :         {
     205              :             // The buffer backing "span" is statically allocated and is of size kMaxDefaultNtpSize.
     206            1 :             auto span = MutableCharSpan(mDefaultNtp, kMaxDefaultNtpSize);
     207            1 :             CopyCharSpanToMutableCharSpan(params.GetDefaultNTP().Value().Value(), span);
     208            1 :             auto default_ntp = MakeNullable(CharSpan(mDefaultNtp, params.GetDefaultNTP().Value().Value().size()));
     209            1 :             mParams.SetDefaultNTP(default_ntp);
     210              :         }
     211              :     }
     212              : 
     213           14 :     if (params.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore && params.GetICDSymmetricKey().HasValue())
     214              :     {
     215            1 :         ReturnErrorOnFailure(VerifyICDRegistrationInfo(params));
     216              : 
     217              :         // The values must be valid now.
     218            1 :         memmove(mICDSymmetricKey, params.GetICDSymmetricKey().Value().data(), params.GetICDSymmetricKey().Value().size());
     219            1 :         mParams.SetICDSymmetricKey(ByteSpan(mICDSymmetricKey));
     220            1 :         mParams.SetICDCheckInNodeId(params.GetICDCheckInNodeId().Value());
     221            1 :         mParams.SetICDMonitoredSubject(params.GetICDMonitoredSubject().Value());
     222            1 :         mParams.SetICDClientType(params.GetICDClientType().Value());
     223              :     }
     224              : 
     225           14 :     auto extraReadPaths = params.GetExtraReadPaths();
     226           14 :     if (extraReadPaths.size() > 0)
     227              :     {
     228              :         using ReadPath = std::remove_pointer_t<decltype(extraReadPaths.data())>;
     229              :         static_assert(std::is_trivially_copyable_v<ReadPath>, "can't use memmove / memcpy, not trivially copyable");
     230              : 
     231            0 :         if (mExtraReadPaths.AllocatedSize() == extraReadPaths.size())
     232              :         {
     233            0 :             memmove(mExtraReadPaths.Get(), extraReadPaths.data(), extraReadPaths.size() * sizeof(ReadPath));
     234              :         }
     235              :         else
     236              :         {
     237              :             // We can't reallocate mExtraReadPaths yet as this would free the old buffer,
     238              :             // and the caller might be passing a sub-span of the old paths.
     239            0 :             decltype(mExtraReadPaths) oldReadPaths(std::move(mExtraReadPaths));
     240            0 :             VerifyOrReturnError(mExtraReadPaths.Alloc(extraReadPaths.size()), CHIP_ERROR_NO_MEMORY);
     241            0 :             memcpy(mExtraReadPaths.Get(), extraReadPaths.data(), extraReadPaths.size() * sizeof(ReadPath));
     242            0 :         }
     243              : 
     244            0 :         mParams.SetExtraReadPaths(mExtraReadPaths.Span());
     245              :     }
     246              :     else
     247              :     {
     248           14 :         mExtraReadPaths.Free();
     249              :     }
     250              : 
     251           14 :     return CHIP_NO_ERROR;
     252              : }
     253              : 
     254            4 : const CommissioningParameters & AutoCommissioner::GetCommissioningParameters() const
     255              : {
     256            4 :     return mParams;
     257              : }
     258              : 
     259            0 : CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     260              : {
     261            0 :     auto nextStage = GetNextCommissioningStageInternal(currentStage, lastErr);
     262            0 :     if (lastErr == CHIP_NO_ERROR)
     263              :     {
     264            0 :         ChipLogProgress(Controller, "Commissioning stage next step: '%s' -> '%s'", StageToString(currentStage),
     265              :                         StageToString(nextStage));
     266              :     }
     267              :     else
     268              :     {
     269            0 :         ChipLogProgress(Controller, "Going from commissioning step '%s' with lastErr = '%s' -> '%s'", StageToString(currentStage),
     270              :                         lastErr.AsString(), StageToString(nextStage));
     271              :     }
     272            0 :     return nextStage;
     273              : }
     274              : 
     275            0 : CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     276              : {
     277            0 :     if (IsSecondaryNetworkSupported())
     278              :     {
     279            0 :         if (TryingSecondaryNetwork())
     280              :         {
     281              :             // Try secondary network interface.
     282            0 :             return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kThreadNetworkSetup
     283            0 :                                                                                      : CommissioningStage::kWiFiNetworkSetup;
     284              :         }
     285              :         // Try primary network interface
     286            0 :         return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kWiFiNetworkSetup
     287            0 :                                                                                  : CommissioningStage::kThreadNetworkSetup;
     288              :     }
     289              : 
     290            0 :     if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
     291              :     {
     292            0 :         return CommissioningStage::kWiFiNetworkSetup;
     293              :     }
     294            0 :     if (mParams.GetThreadOperationalDataset().HasValue() && mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
     295              :     {
     296            0 :         return CommissioningStage::kThreadNetworkSetup;
     297              :     }
     298              : 
     299            0 :     ChipLogError(Controller, "Required network information not provided in commissioning parameters");
     300            0 :     ChipLogError(Controller, "Parameters supplied: wifi (%s) thread (%s)", mParams.GetWiFiCredentials().HasValue() ? "yes" : "no",
     301              :                  mParams.GetThreadOperationalDataset().HasValue() ? "yes" : "no");
     302            0 :     ChipLogError(Controller, "Device supports: wifi (%s) thread(%s)",
     303              :                  mDeviceCommissioningInfo.network.wifi.endpoint == kInvalidEndpointId ? "no" : "yes",
     304              :                  mDeviceCommissioningInfo.network.thread.endpoint == kInvalidEndpointId ? "no" : "yes");
     305            0 :     lastErr = CHIP_ERROR_INVALID_ARGUMENT;
     306            0 :     return CommissioningStage::kCleanup;
     307              : }
     308              : 
     309            0 : CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(CommissioningStage currentStage, CHIP_ERROR & lastErr)
     310              : {
     311            0 :     if (mStopCommissioning)
     312              :     {
     313            0 :         return CommissioningStage::kCleanup;
     314              :     }
     315            0 :     if (lastErr != CHIP_NO_ERROR)
     316              :     {
     317            0 :         return CommissioningStage::kCleanup;
     318              :     }
     319              : 
     320            0 :     switch (currentStage)
     321              :     {
     322            0 :     case CommissioningStage::kSecurePairing:
     323            0 :         return CommissioningStage::kReadCommissioningInfo;
     324            0 :     case CommissioningStage::kReadCommissioningInfo:
     325            0 :         if (mDeviceCommissioningInfo.general.breadcrumb > 0)
     326              :         {
     327              :             // If the breadcrumb is 0, the failsafe was disarmed.
     328              :             // We failed on network setup or later, the node failsafe has not been re-armed and the breadcrumb has not been reset.
     329              :             // Per the spec, we restart from after adding the NOC.
     330            0 :             return GetNextCommissioningStage(CommissioningStage::kSendNOC, lastErr);
     331              :         }
     332            0 :         return CommissioningStage::kArmFailsafe;
     333            0 :     case CommissioningStage::kArmFailsafe:
     334            0 :         return CommissioningStage::kConfigRegulatory;
     335            0 :     case CommissioningStage::kConfigRegulatory:
     336            0 :         return CommissioningStage::kConfigureTCAcknowledgments;
     337            0 :     case CommissioningStage::kConfigureTCAcknowledgments:
     338            0 :         if (mDeviceCommissioningInfo.requiresUTC)
     339              :         {
     340            0 :             return CommissioningStage::kConfigureUTCTime;
     341              :         }
     342              :         else
     343              :         {
     344              :             // Time cluster is not supported, move right to DA
     345            0 :             return CommissioningStage::kSendPAICertificateRequest;
     346              :         }
     347            0 :     case CommissioningStage::kConfigureUTCTime:
     348            0 :         if (mDeviceCommissioningInfo.requiresTimeZone && mParams.GetTimeZone().HasValue())
     349              :         {
     350            0 :             return kConfigureTimeZone;
     351              :         }
     352              :         else
     353              :         {
     354            0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureTimeZone, lastErr);
     355              :         }
     356            0 :     case CommissioningStage::kConfigureTimeZone:
     357            0 :         if (mNeedsDST && mParams.GetDSTOffsets().HasValue())
     358              :         {
     359            0 :             return CommissioningStage::kConfigureDSTOffset;
     360              :         }
     361              :         else
     362              :         {
     363            0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureDSTOffset, lastErr);
     364              :         }
     365            0 :     case CommissioningStage::kConfigureDSTOffset:
     366            0 :         if (mDeviceCommissioningInfo.requiresDefaultNTP && mParams.GetDefaultNTP().HasValue())
     367              :         {
     368            0 :             return CommissioningStage::kConfigureDefaultNTP;
     369              :         }
     370              :         else
     371              :         {
     372            0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureDefaultNTP, lastErr);
     373              :         }
     374            0 :     case CommissioningStage::kConfigureDefaultNTP:
     375            0 :         return CommissioningStage::kSendPAICertificateRequest;
     376            0 :     case CommissioningStage::kSendPAICertificateRequest:
     377            0 :         return CommissioningStage::kSendDACCertificateRequest;
     378            0 :     case CommissioningStage::kSendDACCertificateRequest:
     379            0 :         return CommissioningStage::kSendAttestationRequest;
     380            0 :     case CommissioningStage::kSendAttestationRequest:
     381            0 :         return CommissioningStage::kAttestationVerification;
     382            0 :     case CommissioningStage::kAttestationVerification:
     383            0 :         return CommissioningStage::kAttestationRevocationCheck;
     384            0 :     case CommissioningStage::kAttestationRevocationCheck:
     385              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     386              :         if (mParams.GetExecuteJCM().ValueOr(false))
     387              :         {
     388              :             return CommissioningStage::kJFValidateNOC;
     389              :         }
     390              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     391            0 :         return CommissioningStage::kSendOpCertSigningRequest;
     392            0 :     case CommissioningStage::kJFValidateNOC:
     393            0 :         return CommissioningStage::kSendVIDVerificationRequest;
     394            0 :     case CommissioningStage::kSendVIDVerificationRequest:
     395            0 :         return CommissioningStage::kSendOpCertSigningRequest;
     396            0 :     case CommissioningStage::kSendOpCertSigningRequest:
     397            0 :         return CommissioningStage::kValidateCSR;
     398            0 :     case CommissioningStage::kValidateCSR:
     399            0 :         return CommissioningStage::kGenerateNOCChain;
     400            0 :     case CommissioningStage::kGenerateNOCChain:
     401            0 :         return CommissioningStage::kSendTrustedRootCert;
     402            0 :     case CommissioningStage::kSendTrustedRootCert:
     403            0 :         return CommissioningStage::kSendNOC;
     404            0 :     case CommissioningStage::kSendNOC:
     405            0 :         if (mDeviceCommissioningInfo.requiresTrustedTimeSource && mParams.GetTrustedTimeSource().HasValue())
     406              :         {
     407            0 :             return CommissioningStage::kConfigureTrustedTimeSource;
     408              :         }
     409              :         else
     410              :         {
     411            0 :             return GetNextCommissioningStageInternal(CommissioningStage::kConfigureTrustedTimeSource, lastErr);
     412              :         }
     413            0 :     case CommissioningStage::kConfigureTrustedTimeSource:
     414            0 :         if (mNeedIcdRegistration)
     415              :         {
     416            0 :             if (mParams.GetICDCheckInNodeId().HasValue() && mParams.GetICDMonitoredSubject().HasValue() &&
     417            0 :                 mParams.GetICDSymmetricKey().HasValue())
     418              :             {
     419            0 :                 return CommissioningStage::kICDRegistration;
     420              :             }
     421            0 :             return CommissioningStage::kICDGetRegistrationInfo;
     422              :         }
     423            0 :         return GetNextCommissioningStageInternal(CommissioningStage::kICDRegistration, lastErr);
     424            0 :     case CommissioningStage::kICDGetRegistrationInfo:
     425            0 :         return CommissioningStage::kICDRegistration;
     426            0 :     case CommissioningStage::kICDRegistration:
     427              :         // TODO(cecille): device attestation casues operational cert provisioning to happen, This should be a separate stage.
     428              :         // For thread and wifi, this should go to network setup then enable. For on-network we can skip right to finding the
     429              :         // operational network because the provisioning of certificates will trigger the device to start operational advertising.
     430            0 :         if (mNeedsNetworkSetup)
     431              :         {
     432              :             // if there is a WiFi or a Thread endpoint, then perform scan
     433            0 :             if (IsScanNeeded())
     434              :             {
     435              :                 // Perform Scan (kScanNetworks) and collect credentials (kNeedsNetworkCreds) right before configuring network.
     436              :                 // This order of steps allows the workflow to return to collect credentials again if network enablement fails.
     437            0 :                 return CommissioningStage::kScanNetworks;
     438              :             }
     439            0 :             ChipLogProgress(Controller, "No NetworkScan enabled or WiFi/Thread endpoint not specified, skipping ScanNetworks");
     440              : 
     441            0 :             return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
     442              :         }
     443              :         else
     444              :         {
     445            0 :             SetCASEFailsafeTimerIfNeeded();
     446            0 :             if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     447              :             {
     448            0 :                 return CommissioningStage::kCleanup;
     449              :             }
     450            0 :             return CommissioningStage::kEvictPreviousCaseSessions;
     451              :         }
     452            0 :     case CommissioningStage::kScanNetworks:
     453            0 :         return CommissioningStage::kNeedsNetworkCreds;
     454            0 :     case CommissioningStage::kNeedsNetworkCreds:
     455            0 :         return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
     456            0 :     case CommissioningStage::kWiFiNetworkSetup:
     457            0 :         return CommissioningStage::kFailsafeBeforeWiFiEnable;
     458            0 :     case CommissioningStage::kThreadNetworkSetup:
     459            0 :         return CommissioningStage::kFailsafeBeforeThreadEnable;
     460            0 :     case CommissioningStage::kFailsafeBeforeWiFiEnable:
     461            0 :         return CommissioningStage::kWiFiNetworkEnable;
     462            0 :     case CommissioningStage::kFailsafeBeforeThreadEnable:
     463            0 :         return CommissioningStage::kThreadNetworkEnable;
     464            0 :     case CommissioningStage::kWiFiNetworkEnable:
     465            0 :         if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     466              :         {
     467            0 :             SetCASEFailsafeTimerIfNeeded();
     468            0 :             return CommissioningStage::kCleanup;
     469              :         }
     470              :         else
     471              :         {
     472            0 :             SetCASEFailsafeTimerIfNeeded();
     473            0 :             return CommissioningStage::kEvictPreviousCaseSessions;
     474              :         }
     475            0 :     case CommissioningStage::kThreadNetworkEnable:
     476            0 :         SetCASEFailsafeTimerIfNeeded();
     477            0 :         if (mParams.GetSkipCommissioningComplete().ValueOr(false))
     478              :         {
     479            0 :             return CommissioningStage::kCleanup;
     480              :         }
     481            0 :         return CommissioningStage::kEvictPreviousCaseSessions;
     482            0 :     case CommissioningStage::kEvictPreviousCaseSessions:
     483            0 :         return CommissioningStage::kFindOperationalForStayActive;
     484            0 :     case CommissioningStage::kPrimaryOperationalNetworkFailed:
     485            0 :         if (mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId)
     486              :         {
     487            0 :             return CommissioningStage::kRemoveWiFiNetworkConfig;
     488              :         }
     489              :         else
     490              :         {
     491            0 :             return CommissioningStage::kRemoveThreadNetworkConfig;
     492              :         }
     493            0 :     case CommissioningStage::kRemoveWiFiNetworkConfig:
     494              :     case CommissioningStage::kRemoveThreadNetworkConfig:
     495            0 :         return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
     496            0 :     case CommissioningStage::kFindOperationalForStayActive:
     497            0 :         return CommissioningStage::kICDSendStayActive;
     498            0 :     case CommissioningStage::kICDSendStayActive:
     499            0 :         return CommissioningStage::kFindOperationalForCommissioningComplete;
     500            0 :     case CommissioningStage::kFindOperationalForCommissioningComplete:
     501            0 :         return CommissioningStage::kSendComplete;
     502            0 :     case CommissioningStage::kSendComplete:
     503            0 :         return CommissioningStage::kCleanup;
     504              : 
     505              :     // Neither of these have a next stage so return kError;
     506            0 :     case CommissioningStage::kCleanup:
     507              :     case CommissioningStage::kError:
     508            0 :         return CommissioningStage::kError;
     509              :     }
     510            0 :     return CommissioningStage::kError;
     511              : }
     512              : 
     513              : // No specific actions to take when an error happens since this command can fail and commissioning can still succeed.
     514            0 : static void OnFailsafeFailureForCASE(void * context, CHIP_ERROR error)
     515              : {
     516            0 :     ChipLogProgress(Controller, "ExtendFailsafe received failure response %s\n", chip::ErrorStr(error));
     517            0 : }
     518              : 
     519              : // No specific actions to take upon success.
     520              : static void
     521            0 : OnExtendFailsafeSuccessForCASE(void * context,
     522              :                                const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
     523              : {
     524            0 :     ChipLogProgress(Controller, "ExtendFailsafe received ArmFailSafe response errorCode=%u", to_underlying(data.errorCode));
     525            0 : }
     526              : 
     527            0 : void AutoCommissioner::SetCASEFailsafeTimerIfNeeded()
     528              : {
     529              :     // if there is a final fail-safe timer configured then, send it
     530            0 :     if (mParams.GetCASEFailsafeTimerSeconds().HasValue() && mCommissioneeDeviceProxy != nullptr)
     531              :     {
     532              :         // send the command via the PASE session (mCommissioneeDeviceProxy) since the CASE portion of commissioning
     533              :         // might be done by a different service (ex. PASE is done by a phone app and CASE is done by a Hub).
     534              :         // Also, we want the CASE failsafe timer to apply for the time it takes the Hub to perform operational discovery,
     535              :         // CASE establishment, and receipt of the commissioning complete command.
     536              :         // We know that the mCommissioneeDeviceProxy is still valid at this point since it gets cleared during cleanup
     537              :         // and SetCASEFailsafeTimerIfNeeded is always called before that stage.
     538              :         //
     539              :         // A false return from ExtendArmFailSafe is fine; we don't want to make
     540              :         // the fail-safe shorter here.
     541            0 :         mCommissioner->ExtendArmFailSafe(mCommissioneeDeviceProxy, mCommissioner->GetCommissioningStage(),
     542            0 :                                          mParams.GetCASEFailsafeTimerSeconds().Value(),
     543            0 :                                          GetCommandTimeout(mCommissioneeDeviceProxy, CommissioningStage::kArmFailsafe),
     544              :                                          OnExtendFailsafeSuccessForCASE, OnFailsafeFailureForCASE);
     545              :     }
     546            0 : }
     547              : 
     548            0 : EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) const
     549              : {
     550            0 :     switch (stage)
     551              :     {
     552            0 :     case CommissioningStage::kWiFiNetworkSetup:
     553              :     case CommissioningStage::kWiFiNetworkEnable:
     554            0 :         return mDeviceCommissioningInfo.network.wifi.endpoint;
     555            0 :     case CommissioningStage::kThreadNetworkSetup:
     556              :     case CommissioningStage::kThreadNetworkEnable:
     557            0 :         return mDeviceCommissioningInfo.network.thread.endpoint;
     558            0 :     case CommissioningStage::kRemoveWiFiNetworkConfig:
     559              :     case CommissioningStage::kRemoveThreadNetworkConfig:
     560            0 :         return kRootEndpointId;
     561            0 :     default:
     562            0 :         return kRootEndpointId;
     563              :     }
     564              : }
     565              : 
     566            0 : CHIP_ERROR AutoCommissioner::StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy)
     567              : {
     568            0 :     if (commissioner == nullptr)
     569              :     {
     570            0 :         ChipLogError(Controller, "Invalid DeviceCommissioner");
     571            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     572              :     }
     573              : 
     574            0 :     if (proxy == nullptr || !proxy->GetSecureSession().HasValue())
     575              :     {
     576            0 :         ChipLogError(Controller, "Device proxy secure session error");
     577            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     578              :     }
     579            0 :     mStopCommissioning       = false;
     580            0 :     mCommissioner            = commissioner;
     581            0 :     mCommissioneeDeviceProxy = proxy;
     582              : 
     583              :     auto transportType =
     584            0 :         mCommissioneeDeviceProxy->GetSecureSession().Value()->AsSecureSession()->GetPeerAddress().GetTransportType();
     585            0 :     mNeedsNetworkSetup = (transportType == Transport::Type::kBle);
     586              : #if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
     587              :     mNeedsNetworkSetup = mNeedsNetworkSetup || (transportType == Transport::Type::kNfc);
     588              : #endif
     589              : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
     590            0 :     mNeedsNetworkSetup = mNeedsNetworkSetup || (transportType == Transport::Type::kWiFiPAF);
     591              : #endif
     592            0 :     CHIP_ERROR err               = CHIP_NO_ERROR;
     593            0 :     CommissioningStage nextStage = GetNextCommissioningStage(CommissioningStage::kSecurePairing, err);
     594              : 
     595            0 :     mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, GetEndpoint(nextStage),
     596            0 :                                             GetCommandTimeout(mCommissioneeDeviceProxy, nextStage));
     597            0 :     return CHIP_NO_ERROR;
     598              : }
     599              : 
     600            0 : Optional<System::Clock::Timeout> AutoCommissioner::GetCommandTimeout(DeviceProxy * device, CommissioningStage stage) const
     601              : {
     602              :     // Network clusters can indicate the time required to connect, so if we are
     603              :     // connecting, use that time as our "how long it takes to process server
     604              :     // side" time.  Otherwise pick a time that should be enough for the command
     605              :     // processing: 7s for slow steps that can involve crypto, the default IM
     606              :     // timeout otherwise.
     607              :     // TODO: is this a reasonable estimate for the slow-crypto cases?
     608            0 :     constexpr System::Clock::Timeout kSlowCryptoProcessingTime = System::Clock::Seconds16(7);
     609              : 
     610              :     System::Clock::Timeout timeout;
     611            0 :     switch (stage)
     612              :     {
     613            0 :     case CommissioningStage::kWiFiNetworkEnable:
     614            0 :         ChipLogProgress(Controller, "Setting wifi connection time min = %u",
     615              :                         mDeviceCommissioningInfo.network.wifi.minConnectionTime);
     616            0 :         timeout = System::Clock::Seconds16(mDeviceCommissioningInfo.network.wifi.minConnectionTime);
     617            0 :         break;
     618            0 :     case CommissioningStage::kThreadNetworkEnable:
     619            0 :         timeout = System::Clock::Seconds16(mDeviceCommissioningInfo.network.thread.minConnectionTime);
     620            0 :         break;
     621            0 :     case CommissioningStage::kSendNOC:
     622              :     case CommissioningStage::kSendOpCertSigningRequest:
     623            0 :         timeout = kSlowCryptoProcessingTime;
     624            0 :         break;
     625            0 :     default:
     626            0 :         timeout = app::kExpectedIMProcessingTime;
     627            0 :         break;
     628              :     }
     629              : 
     630              :     // Adjust the timeout for our session transport latency, if we have access
     631              :     // to a session.
     632            0 :     auto sessionHandle = device->GetSecureSession();
     633            0 :     if (sessionHandle.HasValue())
     634              :     {
     635            0 :         timeout = sessionHandle.Value()->ComputeRoundTripTimeout(timeout, true /*isFirstMessageOnExchange*/);
     636              :     }
     637              : 
     638              :     // Enforce the spec minimal timeout.  Maybe this enforcement should live in
     639              :     // the DeviceCommissioner?
     640            0 :     if (timeout < kMinimumCommissioningStepTimeout)
     641              :     {
     642            0 :         timeout = kMinimumCommissioningStepTimeout;
     643              :     }
     644              : 
     645            0 :     return MakeOptional(timeout);
     646            0 : }
     647              : 
     648            0 : CHIP_ERROR AutoCommissioner::NOCChainGenerated(ByteSpan noc, ByteSpan icac, ByteSpan rcac, IdentityProtectionKeySpan ipk,
     649              :                                                NodeId adminSubject)
     650              : {
     651              :     // Reuse ICA Cert buffer for temporary store Root Cert.
     652            0 :     MutableByteSpan rootCert = MutableByteSpan(mICACertBuffer);
     653            0 :     ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(rcac, rootCert));
     654            0 :     mParams.SetRootCert(rootCert);
     655              : 
     656            0 :     MutableByteSpan noCert = MutableByteSpan(mNOCertBuffer);
     657            0 :     ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(noc, noCert));
     658            0 :     mParams.SetNoc(noCert);
     659              : 
     660            0 :     CommissioningStage nextStage = CommissioningStage::kSendTrustedRootCert;
     661            0 :     mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, 0,
     662            0 :                                             GetCommandTimeout(mCommissioneeDeviceProxy, nextStage));
     663              : 
     664              :     // Trusted root cert has been sent, so we can re-use the icac buffer for the icac.
     665            0 :     if (!icac.empty())
     666              :     {
     667            0 :         MutableByteSpan icaCert = MutableByteSpan(mICACertBuffer);
     668            0 :         ReturnErrorOnFailure(Credentials::ConvertX509CertToChipCert(icac, icaCert));
     669            0 :         mParams.SetIcac(icaCert);
     670              :     }
     671              :     else
     672              :     {
     673            0 :         mParams.SetIcac(ByteSpan());
     674              :     }
     675              : 
     676            0 :     mParams.SetIpk(ipk);
     677            0 :     mParams.SetAdminSubject(adminSubject);
     678              : 
     679            0 :     return CHIP_NO_ERROR;
     680              : }
     681              : 
     682            0 : CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, CommissioningDelegate::CommissioningReport report)
     683              : {
     684            0 :     CompletionStatus completionStatus;
     685            0 :     completionStatus.err = err;
     686            0 :     if (err != CHIP_NO_ERROR)
     687              :     {
     688            0 :         ChipLogError(Controller, "Error on commissioning step '%s': '%s'", StageToString(report.stageCompleted), err.AsString());
     689            0 :         completionStatus.failedStage = MakeOptional(report.stageCompleted);
     690            0 :         if (report.Is<AttestationErrorInfo>())
     691              :         {
     692            0 :             completionStatus.attestationResult = MakeOptional(report.Get<AttestationErrorInfo>().attestationResult);
     693            0 :             if ((report.Get<AttestationErrorInfo>().attestationResult ==
     694            0 :                  Credentials::AttestationVerificationResult::kDacProductIdMismatch) ||
     695            0 :                 (report.Get<AttestationErrorInfo>().attestationResult ==
     696              :                  Credentials::AttestationVerificationResult::kDacVendorIdMismatch))
     697              :             {
     698            0 :                 ChipLogError(Controller,
     699              :                              "Failed device attestation. Device vendor and/or product ID do not match the IDs expected. "
     700              :                              "Verify DAC certificate chain and certification declaration to ensure spec rules followed.");
     701              :             }
     702              : 
     703            0 :             if (report.stageCompleted == CommissioningStage::kAttestationVerification)
     704              :             {
     705            0 :                 ChipLogError(Controller, "Failed verifying attestation information. Now checking DAC chain revoked status.");
     706              :                 // don't error out until we check for DAC chain revocation status
     707            0 :                 err = CHIP_NO_ERROR;
     708              :             }
     709              :         }
     710            0 :         else if (report.Is<CommissioningErrorInfo>())
     711              :         {
     712            0 :             completionStatus.commissioningError = MakeOptional(report.Get<CommissioningErrorInfo>().commissioningError);
     713              :         }
     714            0 :         else if (report.Is<NetworkCommissioningStatusInfo>())
     715              :         {
     716              :             // This report type is used when an error happens in either NetworkConfig or ConnectNetwork commands
     717              :             completionStatus.networkCommissioningStatus =
     718            0 :                 MakeOptional(report.Get<NetworkCommissioningStatusInfo>().networkCommissioningStatus);
     719              : 
     720              :             // If we are configured to scan networks, then don't error out.
     721              :             // Instead, allow the app to try another network.
     722            0 :             if (IsScanNeeded())
     723              :             {
     724            0 :                 if (completionStatus.err == CHIP_NO_ERROR)
     725              :                 {
     726            0 :                     completionStatus.err = err;
     727              :                 }
     728            0 :                 err = CHIP_NO_ERROR;
     729              :                 // Walk back the completed stage to kScanNetworks.
     730              :                 // This will allow the app to try another network.
     731            0 :                 report.stageCompleted = CommissioningStage::kScanNetworks;
     732              :             }
     733              :         }
     734              : 
     735            0 :         if (err != CHIP_NO_ERROR && IsSecondaryNetworkSupported() && !TryingSecondaryNetwork() &&
     736            0 :             completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup &&
     737            0 :             completionStatus.failedStage.Value() <= kICDSendStayActive)
     738              :         {
     739              :             // Primary network failed, disable primary network interface and try secondary network interface.
     740            0 :             TrySecondaryNetwork();
     741            0 :             err                   = CHIP_NO_ERROR;
     742            0 :             report.stageCompleted = CommissioningStage::kPrimaryOperationalNetworkFailed;
     743              :         }
     744              :     }
     745              :     else
     746              :     {
     747            0 :         ChipLogProgress(Controller, "Successfully finished commissioning step '%s'", StageToString(report.stageCompleted));
     748            0 :         switch (report.stageCompleted)
     749              :         {
     750            0 :         case CommissioningStage::kReadCommissioningInfo: {
     751            0 :             mDeviceCommissioningInfo = report.Get<ReadCommissioningInfo>();
     752              : 
     753            0 :             if (!mParams.GetFailsafeTimerSeconds().HasValue() && mDeviceCommissioningInfo.general.recommendedFailsafe > 0)
     754              :             {
     755            0 :                 mParams.SetFailsafeTimerSeconds(mDeviceCommissioningInfo.general.recommendedFailsafe);
     756              :             }
     757            0 :             mParams.SetRemoteVendorId(mDeviceCommissioningInfo.basic.vendorId)
     758            0 :                 .SetRemoteProductId(mDeviceCommissioningInfo.basic.productId)
     759            0 :                 .SetDefaultRegulatoryLocation(mDeviceCommissioningInfo.general.currentRegulatoryLocation)
     760            0 :                 .SetLocationCapability(mDeviceCommissioningInfo.general.locationCapability);
     761              :             // Don't send DST unless the device says it needs it
     762            0 :             mNeedsDST = false;
     763              : 
     764            0 :             mParams.SetSupportsConcurrentConnection(mDeviceCommissioningInfo.supportsConcurrentConnection);
     765              : 
     766            0 :             if (mParams.GetCheckForMatchingFabric())
     767              :             {
     768            0 :                 NodeId nodeId = mDeviceCommissioningInfo.remoteNodeId;
     769            0 :                 if (nodeId != kUndefinedNodeId)
     770              :                 {
     771            0 :                     mParams.SetRemoteNodeId(nodeId);
     772              :                 }
     773              :             }
     774              : 
     775            0 :             mNeedIcdRegistration = false;
     776            0 :             if (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore)
     777              :             {
     778            0 :                 if (mDeviceCommissioningInfo.icd.isLIT && mDeviceCommissioningInfo.icd.checkInProtocolSupport)
     779              :                 {
     780            0 :                     mNeedIcdRegistration = true;
     781            0 :                     ChipLogDetail(Controller, "AutoCommissioner: ICD supports the check-in protocol.");
     782              :                 }
     783            0 :                 else if (mParams.GetICDStayActiveDurationMsec().HasValue())
     784              :                 {
     785            0 :                     ChipLogDetail(Controller, "AutoCommissioner: Clear ICD StayActiveDurationMsec");
     786            0 :                     mParams.ClearICDStayActiveDurationMsec();
     787              :                 }
     788              :             }
     789              : 
     790              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     791              :             if (mParams.GetExecuteJCM().ValueOr(false) &&
     792              :                 (mDeviceCommissioningInfo.JFAdministratorFabricIndex != kUndefinedFabricIndex))
     793              :             {
     794              :                 ReturnErrorOnFailure(AllocateMemoryAndCopySpan(mJFAdminRCAC, mDeviceCommissioningInfo.JFAdminRCAC));
     795              :                 mParams.SetJFAdminRCAC(mJFAdminRCAC.Span());
     796              : 
     797              :                 ReturnErrorOnFailure(AllocateMemoryAndCopySpan(mJFAdminICAC, mDeviceCommissioningInfo.JFAdminICAC));
     798              :                 mParams.SetJFAdminICAC(mJFAdminICAC.Span());
     799              : 
     800              :                 ReturnErrorOnFailure(AllocateMemoryAndCopySpan(mJFAdminNOC, mDeviceCommissioningInfo.JFAdminNOC));
     801              :                 mParams.SetJFAdminNOC(mJFAdminNOC.Span());
     802              : 
     803              :                 mParams.SetJFAdminEndpointId(mDeviceCommissioningInfo.JFAdminEndpointId)
     804              :                     .SetJFAdministratorFabricIndex(mDeviceCommissioningInfo.JFAdministratorFabricIndex)
     805              :                     .SetJFAdminFabricId(mDeviceCommissioningInfo.JFAdminFabricTable.fabricId)
     806              :                     .SetJFAdminVendorId(mDeviceCommissioningInfo.JFAdminFabricTable.vendorId);
     807              :             }
     808              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     809              : 
     810            0 :             break;
     811              :         }
     812            0 :         case CommissioningStage::kConfigureTimeZone:
     813            0 :             mNeedsDST = report.Get<TimeZoneResponseInfo>().requiresDSTOffsets;
     814            0 :             break;
     815            0 :         case CommissioningStage::kSendPAICertificateRequest: {
     816            0 :             auto reportPAISpan = report.Get<RequestedCertificate>().certificate;
     817              : 
     818            0 :             ReturnErrorOnFailure(AllocateMemoryAndCopySpan(mPAI, reportPAISpan));
     819            0 :             mParams.SetPAI(mPAI.Span());
     820            0 :             break;
     821              :         }
     822            0 :         case CommissioningStage::kSendDACCertificateRequest: {
     823            0 :             auto reportDACSpan = report.Get<RequestedCertificate>().certificate;
     824              : 
     825            0 :             ReturnErrorOnFailure(AllocateMemoryAndCopySpan(mDAC, reportDACSpan));
     826            0 :             mParams.SetDAC(ByteSpan(mDAC.Span()));
     827            0 :             break;
     828              :         }
     829            0 :         case CommissioningStage::kSendAttestationRequest: {
     830            0 :             auto & elements  = report.Get<AttestationResponse>().attestationElements;
     831            0 :             auto & signature = report.Get<AttestationResponse>().signature;
     832            0 :             if (elements.size() > sizeof(mAttestationElements))
     833              :             {
     834            0 :                 ChipLogError(Controller, "AutoCommissioner attestationElements buffer size %u larger than cache size %u",
     835              :                              static_cast<unsigned>(elements.size()), static_cast<unsigned>(sizeof(mAttestationElements)));
     836            0 :                 return CHIP_ERROR_MESSAGE_TOO_LONG;
     837              :             }
     838            0 :             memcpy(mAttestationElements, elements.data(), elements.size());
     839            0 :             mAttestationElementsLen = static_cast<uint16_t>(elements.size());
     840            0 :             mParams.SetAttestationElements(ByteSpan(mAttestationElements, elements.size()));
     841            0 :             ChipLogDetail(Controller, "AutoCommissioner setting attestationElements buffer size %u/%u",
     842              :                           static_cast<unsigned>(elements.size()),
     843              :                           static_cast<unsigned>(mParams.GetAttestationElements().Value().size()));
     844              : 
     845            0 :             if (signature.size() > sizeof(mAttestationSignature))
     846              :             {
     847            0 :                 ChipLogError(Controller,
     848              :                              "AutoCommissioner attestationSignature buffer size %u larger than "
     849              :                              "cache size %u",
     850              :                              static_cast<unsigned>(signature.size()), static_cast<unsigned>(sizeof(mAttestationSignature)));
     851            0 :                 return CHIP_ERROR_MESSAGE_TOO_LONG;
     852              :             }
     853            0 :             memcpy(mAttestationSignature, signature.data(), signature.size());
     854            0 :             mAttestationSignatureLen = static_cast<uint16_t>(signature.size());
     855            0 :             mParams.SetAttestationSignature(ByteSpan(mAttestationSignature, signature.size()));
     856              : 
     857              :             // TODO: Does this need to be done at runtime? Seems like this could be done earlier and we wouldn't need to hold a
     858              :             // reference to the operational credential delegate here
     859            0 :             if (mOperationalCredentialsDelegate != nullptr)
     860              :             {
     861            0 :                 MutableByteSpan nonce(mCSRNonce);
     862            0 :                 ReturnErrorOnFailure(mOperationalCredentialsDelegate->ObtainCsrNonce(nonce));
     863            0 :                 mParams.SetCSRNonce(ByteSpan(mCSRNonce, sizeof(mCSRNonce)));
     864              :             }
     865            0 :             break;
     866              :         }
     867            0 :         case CommissioningStage::kSendOpCertSigningRequest: {
     868            0 :             NOCChainGenerationParameters nocParams;
     869            0 :             nocParams.nocsrElements = report.Get<CSRResponse>().nocsrElements;
     870            0 :             nocParams.signature     = report.Get<CSRResponse>().signature;
     871            0 :             mParams.SetNOCChainGenerationParameters(nocParams);
     872              :         }
     873            0 :         break;
     874            0 :         case CommissioningStage::kGenerateNOCChain:
     875              :             // For NOC chain generation, we re-use the buffers. NOCChainGenerated triggers the next stage before
     876              :             // storing the returned certs, so just return here without triggering the next stage.
     877            0 :             return NOCChainGenerated(report.Get<NocChain>().noc, report.Get<NocChain>().icac, report.Get<NocChain>().rcac,
     878            0 :                                      report.Get<NocChain>().ipk, report.Get<NocChain>().adminSubject);
     879            0 :         case CommissioningStage::kICDGetRegistrationInfo:
     880              :             // Noting to do. The ICD registation info is handled elsewhere.
     881            0 :             break;
     882            0 :         case CommissioningStage::kICDRegistration:
     883              :             // Noting to do. DevicePairingDelegate will handle this.
     884            0 :             break;
     885            0 :         case CommissioningStage::kFindOperationalForStayActive:
     886              :         case CommissioningStage::kFindOperationalForCommissioningComplete:
     887            0 :             mOperationalDeviceProxy = report.Get<OperationalNodeFoundData>().operationalProxy;
     888            0 :             break;
     889            0 :         case CommissioningStage::kCleanup:
     890            0 :             if (IsSecondaryNetworkSupported() && TryingSecondaryNetwork())
     891              :             {
     892            0 :                 ResetTryingSecondaryNetwork();
     893              :             }
     894            0 :             mPAI.Free();
     895            0 :             mDAC.Free();
     896              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     897              :             mJFAdminRCAC.Free();
     898              :             mJFAdminICAC.Free();
     899              :             mJFAdminNOC.Free();
     900              : #endif
     901            0 :             mCommissioneeDeviceProxy = nullptr;
     902            0 :             mOperationalDeviceProxy  = OperationalDeviceProxy();
     903            0 :             mDeviceCommissioningInfo = ReadCommissioningInfo();
     904            0 :             mNeedsDST                = false;
     905            0 :             return CHIP_NO_ERROR;
     906            0 :         default:
     907            0 :             break;
     908              :         }
     909              :     }
     910              : 
     911            0 :     CommissioningStage nextStage = GetNextCommissioningStage(report.stageCompleted, err);
     912            0 :     if (nextStage == CommissioningStage::kError)
     913              :     {
     914            0 :         return CHIP_ERROR_INCORRECT_STATE;
     915              :     }
     916              : 
     917              :     // If GetNextCommissioningStage indicated a failure, don't lose track of
     918              :     // that.  But don't overwrite any existing failures we had hanging
     919              :     // around.
     920            0 :     if (completionStatus.err == CHIP_NO_ERROR)
     921              :     {
     922            0 :         completionStatus.err = err;
     923              :     }
     924            0 :     mParams.SetCompletionStatus(completionStatus);
     925              : 
     926            0 :     return PerformStep(nextStage);
     927              : }
     928              : 
     929            0 : DeviceProxy * AutoCommissioner::GetDeviceProxyForStep(CommissioningStage nextStage)
     930              : {
     931            0 :     if (nextStage == CommissioningStage::kSendComplete || nextStage == CommissioningStage::kICDSendStayActive ||
     932            0 :         (nextStage == CommissioningStage::kCleanup && mOperationalDeviceProxy.GetDeviceId() != kUndefinedNodeId))
     933              :     {
     934            0 :         return &mOperationalDeviceProxy;
     935              :     }
     936            0 :     return mCommissioneeDeviceProxy;
     937              : }
     938              : 
     939            0 : CHIP_ERROR AutoCommissioner::PerformStep(CommissioningStage nextStage)
     940              : {
     941            0 :     DeviceProxy * proxy = GetDeviceProxyForStep(nextStage);
     942            0 :     if (proxy == nullptr)
     943              :     {
     944            0 :         ChipLogError(Controller, "Invalid device for commissioning");
     945            0 :         return CHIP_ERROR_INCORRECT_STATE;
     946              :     }
     947              :     // Perform any last minute parameter adjustments before calling the commissioner object
     948            0 :     switch (nextStage)
     949              :     {
     950            0 :     case CommissioningStage::kConfigureTimeZone:
     951            0 :         if (mParams.GetTimeZone().Value().size() > mDeviceCommissioningInfo.maxTimeZoneSize)
     952              :         {
     953            0 :             mParams.SetTimeZone(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>(
     954            0 :                 mParams.GetTimeZone().Value().SubSpan(0, mDeviceCommissioningInfo.maxTimeZoneSize)));
     955              :         }
     956            0 :         break;
     957            0 :     case CommissioningStage::kConfigureDSTOffset:
     958            0 :         if (mParams.GetDSTOffsets().Value().size() > mDeviceCommissioningInfo.maxDSTSize)
     959              :         {
     960            0 :             mParams.SetDSTOffsets(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type>(
     961            0 :                 mParams.GetDSTOffsets().Value().SubSpan(0, mDeviceCommissioningInfo.maxDSTSize)));
     962              :         }
     963            0 :         break;
     964            0 :     default:
     965            0 :         break;
     966              :     }
     967              : 
     968            0 :     mCommissioner->PerformCommissioningStep(proxy, nextStage, mParams, this, GetEndpoint(nextStage),
     969            0 :                                             GetCommandTimeout(proxy, nextStage));
     970            0 :     return CHIP_NO_ERROR;
     971              : }
     972              : 
     973            0 : CHIP_ERROR AutoCommissioner::AllocateMemoryAndCopySpan(Platform::ScopedMemoryBufferWithSize<uint8_t> & scopedBuffer, ByteSpan span)
     974              : {
     975            0 :     if (!span.size())
     976              :     {
     977            0 :         return CHIP_ERROR_INVALID_MESSAGE_LENGTH;
     978              :     }
     979              : 
     980            0 :     if (!scopedBuffer.Alloc(span.size()))
     981              :     {
     982            0 :         ChipLogError(Controller, "AutoCommissioner: AllocateMemoryAndCopySpan failed");
     983            0 :         return CHIP_ERROR_NO_MEMORY;
     984              :     }
     985            0 :     memcpy(scopedBuffer.Get(), span.data(), scopedBuffer.AllocatedSize());
     986            0 :     return CHIP_NO_ERROR;
     987              : }
     988              : 
     989              : } // namespace Controller
     990              : } // namespace chip
        

Generated by: LCOV version 2.0-1