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