Matter SDK Coverage Report
Current view: top level - controller - AutoCommissioner.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 0.0 % 540 0
Test Date: 2025-01-17 19:00:11 Functions: 0.0 % 28 0

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

Generated by: LCOV version 2.0-1