/* * * Copyright (c) 2020-2022 Project CHIP Authors * Copyright (c) 2019-2020 Google LLC. * Copyright (c) 2013-2018 Nest Labs, Inc. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "ChipDeviceController-ScriptDevicePairingDelegate.h" #include "ChipDeviceController-StorageDelegate.h" #include "controller/python/chip/crypto/p256keypair.h" #include "controller/python/chip/interaction_model/Delegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace chip; using Py_GenerateNOCChainFunc = void (*)(void * pyContext, const char * csrElements, const char * attestationSignature, const char * dac, const char * pai, const char * paa, Controller::OnNOCChainGeneration onNocChainGenerationFunc); using Py_SetNodeIdForNextNOCRequest = void (*)(void * pyContext, NodeId nodeId); using Py_SetFabricIdForNextNOCRequest = void (*)(void * pyContext, FabricId fabricId); namespace { const chip::Credentials::AttestationTrustStore * GetTestFileAttestationTrustStore(const char * paaTrustStorePath) { static chip::Credentials::FileAttestationTrustStore attestationTrustStore{ paaTrustStorePath }; return &attestationTrustStore; } chip::Python::PlaceholderOperationalCredentialsIssuer sPlaceholderOperationalCredentialsIssuer; } // namespace namespace chip { namespace Controller { namespace Python { class OperationalCredentialsAdapter : public OperationalCredentialsDelegate { public: OperationalCredentialsAdapter(uint32_t fabricCredentialsIndex) : mExampleOpCredsIssuer(fabricCredentialsIndex) {} CHIP_ERROR Initialize(PersistentStorageDelegate & storageDelegate) { return mExampleOpCredsIssuer.Initialize(storageDelegate); } CHIP_ERROR GenerateNOCChain(NodeId nodeId, FabricId fabricId, const CATValues & cats, const Crypto::P256PublicKey & pubKey, MutableByteSpan & rcac, MutableByteSpan & icac, MutableByteSpan & noc) { return mExampleOpCredsIssuer.GenerateNOCChainAfterValidation(nodeId, fabricId, cats, pubKey, rcac, icac, noc); } void SetMaximallyLargeCertsUsed(bool enabled) { mExampleOpCredsIssuer.SetMaximallyLargeCertsUsed(enabled); } private: CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature, const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI, Callback::Callback * onCompletion) override { return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI, onCompletion); } void SetNodeIdForNextNOCRequest(NodeId nodeId) override { mExampleOpCredsIssuer.SetNodeIdForNextNOCRequest(nodeId); } void SetFabricIdForNextNOCRequest(FabricId fabricId) override { mExampleOpCredsIssuer.SetFabricIdForNextNOCRequest(fabricId); } ExampleOperationalCredentialsIssuer mExampleOpCredsIssuer; }; } // namespace Python } // namespace Controller } // namespace chip extern chip::Credentials::GroupDataProviderImpl sGroupDataProvider; extern chip::Controller::ScriptDevicePairingDelegate sPairingDelegate; extern chip::app::DefaultICDClientStorage sICDClientStorage; class TestCommissioner : public chip::Controller::AutoCommissioner { public: TestCommissioner() { Reset(); } ~TestCommissioner() {} CHIP_ERROR SetCommissioningParameters(const chip::Controller::CommissioningParameters & params) override { mIsWifi = false; mIsThread = false; if (params.GetWiFiCredentials().HasValue()) { mIsWifi = true; } else if (params.GetThreadOperationalDataset().HasValue()) { mIsThread = true; } return chip::Controller::AutoCommissioner::SetCommissioningParameters(params); } CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err, chip::Controller::CommissioningDelegate::CommissioningReport report) override { mTestCommissionerUsed = true; if (mFailOnReportAfterStage == report.stageCompleted) { return CHIP_ERROR_INTERNAL; } if (mSimulateFailureOnStage == report.stageCompleted) { // Pretend we received an error from the device during this stage err = CHIP_ERROR_INTERNAL; } if (mPrematureCompleteAfter == report.stageCompleted) { auto commissioner = chip::Controller::AutoCommissioner::GetCommissioner(); auto proxy = chip::Controller::AutoCommissioner::GetCommissioneeDeviceProxy(); auto stage = chip::Controller::CommissioningStage::kSendComplete; auto params = chip::Controller::CommissioningParameters(); commissioner->PerformCommissioningStep(proxy, stage, params, this, 0, GetCommandTimeout(proxy, stage)); return CHIP_NO_ERROR; } if (mPrematureCompleteAfter != chip::Controller::CommissioningStage::kError && report.stageCompleted == chip::Controller::CommissioningStage::kSendComplete) { if (report.Is()) { uint8_t code = chip::to_underlying(report.Get().commissioningError); mCompletionError = chip::ChipError(chip::ChipError::SdkPart::kIMClusterStatus, code); } else { mCompletionError = err; } } if (report.stageCompleted == chip::Controller::CommissioningStage::kReadCommissioningInfo2) { mReadCommissioningInfo = report.Get(); } if (report.stageCompleted == chip::Controller::CommissioningStage::kConfigureTimeZone) { mNeedsDST = report.Get().requiresDSTOffsets; } return chip::Controller::AutoCommissioner::CommissioningStepFinished(err, report); } // This will cause the COMMISSIONER to fail after the given stage. Setting this to kSecurePairing will cause the // StartCommissioning call to fail. bool SimulateFailAfter(chip::Controller::CommissioningStage stage) { ChipLogProgress(Controller, "setting simulate fail after stage %s", chip::Controller::StageToString(stage)); if (!ValidStage(stage) && stage != chip::Controller::CommissioningStage::kError) { return false; } mSimulateFailureOnStage = stage; return true; } bool SimulateFailOnReport(chip::Controller::CommissioningStage stage) { if (!ValidStage(stage) && stage != chip::Controller::CommissioningStage::kError) { return false; } mFailOnReportAfterStage = stage; return true; } bool PrematureCompleteAfter(chip::Controller::CommissioningStage stage) { if (!ValidStage(stage) && stage != chip::Controller::CommissioningStage::kError) { return false; } mPrematureCompleteAfter = stage; return true; } bool CheckCallbacks() { bool successFailureOk; bool updatesOk; if (mFailOnReportAfterStage != chip::Controller::CommissioningStage::kError) { successFailureOk = mReceivedCommissioningFailureStage == mFailOnReportAfterStage && !mReceivedCommissioningSuccess; updatesOk = StatusUpdatesOk(mFailOnReportAfterStage); } else if (mSimulateFailureOnStage != chip::Controller::CommissioningStage::kError) { successFailureOk = mReceivedCommissioningFailureStage == mSimulateFailureOnStage && !mReceivedCommissioningSuccess; updatesOk = StatusUpdatesOk(mSimulateFailureOnStage); } else { successFailureOk = mReceivedCommissioningSuccess; updatesOk = StatusUpdatesOk(chip::Controller::CommissioningStage::kError); } ChipLogProgress(Controller, "Checking callbacks: success failure ok? %d updates ok? %d", successFailureOk, updatesOk); return successFailureOk && updatesOk; } bool CheckPaseConnection(NodeId nodeId) { bool paseShouldBeOpen = false; if (chip::to_underlying(mFailOnReportAfterStage) >= chip::to_underlying(chip::Controller::CommissioningStage::kWiFiNetworkSetup) || chip::to_underlying(mSimulateFailureOnStage) >= chip::to_underlying(chip::Controller::CommissioningStage::kWiFiNetworkSetup)) { // Pase should be open still paseShouldBeOpen = true; } CommissioneeDeviceProxy * proxy; bool paseIsOpen = (chip::Controller::AutoCommissioner::GetCommissioner()->GetDeviceBeingCommissioned(nodeId, &proxy) == CHIP_NO_ERROR); ChipLogProgress(Controller, "Checking pase connection state: Should be open? %d is open? %d", paseShouldBeOpen, paseIsOpen); return paseShouldBeOpen == paseIsOpen; } bool CheckStageSuccessful(uint8_t stage) { return mReceivedStageSuccess[stage]; } void Reset() { mTestCommissionerUsed = false; mReceivedCommissioningSuccess = false; mReceivedCommissioningFailureStage = chip::Controller::CommissioningStage::kError; for (size_t i = 0; i < kNumCommissioningStages; ++i) { mReceivedStageSuccess[i] = false; mReceivedStageFailure[i] = false; } mSimulateFailureOnStage = chip::Controller::CommissioningStage::kError; mFailOnReportAfterStage = chip::Controller::CommissioningStage::kError; mPrematureCompleteAfter = chip::Controller::CommissioningStage::kError; mReadCommissioningInfo = chip::Controller::ReadCommissioningInfo(); mNeedsDST = false; mCompletionError = CHIP_NO_ERROR; } bool GetTestCommissionerUsed() { return mTestCommissionerUsed; } void OnCommissioningSuccess(chip::PeerId peerId) { mReceivedCommissioningSuccess = true; } void OnCommissioningFailure(chip::PeerId peerId, CHIP_ERROR error, chip::Controller::CommissioningStage stageFailed, chip::Optional additionalErrorInfo) { mReceivedCommissioningFailureStage = stageFailed; } void OnCommissioningStatusUpdate(chip::PeerId peerId, chip::Controller::CommissioningStage stageCompleted, CHIP_ERROR error) { if (error == CHIP_NO_ERROR) { mReceivedStageSuccess[chip::to_underlying(stageCompleted)] = true; } else { mReceivedStageFailure[chip::to_underlying(stageCompleted)] = true; } if (stageCompleted == chip::Controller::CommissioningStage::kCleanup && mPrematureCompleteAfter != chip::Controller::CommissioningStage::kError) { // We need to manually clean up the proxy here because we're doing bad things in the name of testing ChipLogProgress(Controller, "Cleaning up dangling proxies"); auto commissioner = chip::Controller::AutoCommissioner::GetCommissioner(); auto proxy = chip::Controller::AutoCommissioner::GetCommissioneeDeviceProxy(); if (proxy != nullptr) { commissioner->StopPairing(proxy->GetDeviceId()); } } } CHIP_ERROR GetCompletionError() { return mCompletionError; } private: static constexpr uint8_t kNumCommissioningStages = chip::to_underlying(chip::Controller::CommissioningStage::kCleanup) + 1; chip::Controller::CommissioningStage mSimulateFailureOnStage = chip::Controller::CommissioningStage::kError; chip::Controller::CommissioningStage mFailOnReportAfterStage = chip::Controller::CommissioningStage::kError; chip::Controller::CommissioningStage mPrematureCompleteAfter = chip::Controller::CommissioningStage::kError; bool mTestCommissionerUsed = false; bool mReceivedCommissioningSuccess = false; chip::Controller::CommissioningStage mReceivedCommissioningFailureStage = chip::Controller::CommissioningStage::kError; bool mReceivedStageSuccess[kNumCommissioningStages]; bool mReceivedStageFailure[kNumCommissioningStages]; bool mIsWifi = false; bool mIsThread = false; CHIP_ERROR mCompletionError = CHIP_NO_ERROR; // Contains information about whether the device needs time sync chip::Controller::ReadCommissioningInfo mReadCommissioningInfo; bool mNeedsDST = false; bool ValidStage(chip::Controller::CommissioningStage stage) { switch (stage) { case chip::Controller::CommissioningStage::kWiFiNetworkEnable: case chip::Controller::CommissioningStage::kFailsafeBeforeWiFiEnable: case chip::Controller::CommissioningStage::kWiFiNetworkSetup: return mIsWifi; case chip::Controller::CommissioningStage::kThreadNetworkEnable: case chip::Controller::CommissioningStage::kFailsafeBeforeThreadEnable: case chip::Controller::CommissioningStage::kThreadNetworkSetup: return mIsThread; case chip::Controller::CommissioningStage::kConfigureUTCTime: return mReadCommissioningInfo.requiresUTC; case chip::Controller::CommissioningStage::kConfigureTimeZone: return mReadCommissioningInfo.requiresTimeZone && mParams.GetTimeZone().HasValue(); case chip::Controller::CommissioningStage::kConfigureTrustedTimeSource: return mReadCommissioningInfo.requiresTrustedTimeSource && mParams.GetTrustedTimeSource().HasValue(); case chip::Controller::CommissioningStage::kConfigureDefaultNTP: return mReadCommissioningInfo.requiresDefaultNTP && mParams.GetDefaultNTP().HasValue(); case chip::Controller::CommissioningStage::kConfigureDSTOffset: return mNeedsDST && mParams.GetDSTOffsets().HasValue(); case chip::Controller::CommissioningStage::kError: case chip::Controller::CommissioningStage::kSecurePairing: // "not valid" because attestation verification always fails after entering revocation check step case chip::Controller::CommissioningStage::kAttestationVerification: return false; default: return true; } } bool StatusUpdatesOk(chip::Controller::CommissioningStage failedStage) { // Because we're just simulating a failure here, we will have received a success callback even for the failed stage. for (uint8_t i = 0; i < kNumCommissioningStages; ++i) { if (mReceivedStageFailure[i]) { return false; } if (!ValidStage(static_cast(i))) { continue; } // Anything above our current stage we won't have received a callback for. We also expect that the "failed" stage will // have a success callback because we're just faking the failure here and overwriting error. if (i == chip::to_underlying(failedStage)) { break; } } return true; } }; TestCommissioner sTestCommissioner; extern "C" { struct OpCredsContext { Platform::UniquePtr mAdapter; void * mPyContext; }; void * pychip_OpCreds_InitializeDelegate(void * pyContext, uint32_t fabricCredentialsIndex, Controller::Python::StorageAdapter * storageAdapter) { auto context = Platform::MakeUnique(); context->mAdapter = Platform::MakeUnique(fabricCredentialsIndex); if (context->mAdapter->Initialize(*storageAdapter) != CHIP_NO_ERROR) { return nullptr; } return context.release(); } void pychip_OnCommissioningSuccess(PeerId peerId) { sTestCommissioner.OnCommissioningSuccess(peerId); } void pychip_OnCommissioningFailure(chip::PeerId peerId, CHIP_ERROR error, chip::Controller::CommissioningStage stageFailed, chip::Optional additionalErrorInfo) { sTestCommissioner.OnCommissioningFailure(peerId, error, stageFailed, additionalErrorInfo); } void pychip_OnCommissioningStatusUpdate(chip::PeerId peerId, chip::Controller::CommissioningStage stageCompleted, CHIP_ERROR err) { return sTestCommissioner.OnCommissioningStatusUpdate(peerId, stageCompleted, err); } /** * Allocates a controller that does not use auto-commisioning. * * TODO(#25214): Need clean up API * */ PyChipError pychip_OpCreds_AllocateControllerForPythonCommissioningFLow( chip::Controller::DeviceCommissioner ** outDevCtrl, chip::Controller::ScriptDevicePairingDelegate ** outPairingDelegate, chip::python::pychip_P256Keypair * operationalKey, uint8_t * noc, uint32_t nocLen, uint8_t * icac, uint32_t icacLen, uint8_t * rcac, uint32_t rcacLen, const uint8_t * ipk, uint32_t ipkLen, chip::VendorId adminVendorId, bool enableServerInteractions) { VerifyOrReturnError(nocLen <= Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY)); VerifyOrReturnError(icacLen <= Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY)); VerifyOrReturnError(rcacLen <= Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY)); ChipLogDetail(Controller, "Creating New Device Controller"); auto pairingDelegate = std::make_unique(); VerifyOrReturnError(pairingDelegate != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY)); auto devCtrl = std::make_unique(); VerifyOrReturnError(devCtrl != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY)); Controller::SetupParams initParams; initParams.pairingDelegate = pairingDelegate.get(); initParams.operationalCredentialsDelegate = &sPlaceholderOperationalCredentialsIssuer; initParams.operationalKeypair = operationalKey; initParams.controllerRCAC = ByteSpan(rcac, rcacLen); initParams.controllerICAC = ByteSpan(icac, icacLen); initParams.controllerNOC = ByteSpan(noc, nocLen); initParams.enableServerInteractions = enableServerInteractions; initParams.controllerVendorId = adminVendorId; initParams.permitMultiControllerFabrics = true; initParams.hasExternallyOwnedOperationalKeypair = true; CHIP_ERROR err = Controller::DeviceControllerFactory::GetInstance().SetupCommissioner(initParams, *devCtrl); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); // Setup IPK in Group Data Provider for controller after Commissioner init which sets-up the fabric table entry uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); err = devCtrl->GetCompressedFabricIdBytes(compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", static_cast(devCtrl->GetFabricIndex())); ChipLogByteSpan(Support, compressedFabricIdSpan); chip::ByteSpan fabricIpk = (ipk == nullptr) ? chip::GroupTesting::DefaultIpkValue::GetDefaultIpk() : chip::ByteSpan(ipk, ipkLen); err = chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, devCtrl->GetFabricIndex(), fabricIpk, compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); *outDevCtrl = devCtrl.release(); *outPairingDelegate = pairingDelegate.release(); return ToPyChipError(CHIP_NO_ERROR); } // TODO(#25214): Need clean up API PyChipError pychip_OpCreds_AllocateController(OpCredsContext * context, chip::Controller::DeviceCommissioner ** outDevCtrl, chip::Controller::ScriptDevicePairingDelegate ** outPairingDelegate, FabricId fabricId, chip::NodeId nodeId, chip::VendorId adminVendorId, const char * paaTrustStorePath, bool useTestCommissioner, bool enableServerInteractions, CASEAuthTag * caseAuthTags, uint32_t caseAuthTagLen, chip::python::pychip_P256Keypair * operationalKey) { CHIP_ERROR err = CHIP_NO_ERROR; ChipLogDetail(Controller, "Creating New Device Controller"); VerifyOrReturnError(context != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); auto pairingDelegate = std::make_unique(); VerifyOrReturnError(pairingDelegate != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY)); auto devCtrl = std::make_unique(); VerifyOrReturnError(devCtrl != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY)); if (paaTrustStorePath == nullptr) { paaTrustStorePath = "./credentials/development/paa-root-certs"; } ChipLogProgress(Support, "Using device attestation PAA trust store path %s.", paaTrustStorePath); // Initialize device attestation verifier const chip::Credentials::AttestationTrustStore * testingRootStore = GetTestFileAttestationTrustStore(paaTrustStorePath); SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); chip::Crypto::P256Keypair ephemeralKey; chip::Crypto::P256Keypair * controllerKeyPair; if (operationalKey == nullptr) { err = ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); controllerKeyPair = &ephemeralKey; } else { controllerKeyPair = operationalKey; } chip::Platform::ScopedMemoryBuffer noc; VerifyOrReturnError(noc.Alloc(Controller::kMaxCHIPDERCertLength), ToPyChipError(CHIP_ERROR_NO_MEMORY)); MutableByteSpan nocSpan(noc.Get(), Controller::kMaxCHIPDERCertLength); chip::Platform::ScopedMemoryBuffer icac; VerifyOrReturnError(icac.Alloc(Controller::kMaxCHIPDERCertLength), ToPyChipError(CHIP_ERROR_NO_MEMORY)); MutableByteSpan icacSpan(icac.Get(), Controller::kMaxCHIPDERCertLength); chip::Platform::ScopedMemoryBuffer rcac; VerifyOrReturnError(rcac.Alloc(Controller::kMaxCHIPDERCertLength), ToPyChipError(CHIP_ERROR_NO_MEMORY)); MutableByteSpan rcacSpan(rcac.Get(), Controller::kMaxCHIPDERCertLength); CATValues catValues; if (caseAuthTagLen > kMaxSubjectCATAttributeCount) { ChipLogError(Controller, "Too many of CASE Tags (%u) exceeds kMaxSubjectCATAttributeCount", static_cast(caseAuthTagLen)); return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); } memcpy(catValues.values.data(), caseAuthTags, caseAuthTagLen * sizeof(CASEAuthTag)); err = context->mAdapter->GenerateNOCChain(nodeId, fabricId, catValues, controllerKeyPair->Pubkey(), rcacSpan, icacSpan, nocSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); Controller::SetupParams initParams; initParams.pairingDelegate = pairingDelegate.get(); initParams.operationalCredentialsDelegate = context->mAdapter.get(); initParams.operationalKeypair = controllerKeyPair; initParams.controllerRCAC = rcacSpan; initParams.controllerICAC = icacSpan; initParams.controllerNOC = nocSpan; initParams.enableServerInteractions = enableServerInteractions; initParams.controllerVendorId = adminVendorId; initParams.permitMultiControllerFabrics = true; initParams.hasExternallyOwnedOperationalKeypair = operationalKey != nullptr; if (useTestCommissioner) { initParams.defaultCommissioner = &sTestCommissioner; pairingDelegate->SetCommissioningSuccessCallback(pychip_OnCommissioningSuccess); pairingDelegate->SetCommissioningFailureCallback(pychip_OnCommissioningFailure); pairingDelegate->SetCommissioningStatusUpdateCallback(pychip_OnCommissioningStatusUpdate); } err = Controller::DeviceControllerFactory::GetInstance().SetupCommissioner(initParams, *devCtrl); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); // Setup IPK in Group Data Provider for controller after Commissioner init which sets-up the fabric table entry uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); err = devCtrl->GetCompressedFabricIdBytes(compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", static_cast(devCtrl->GetFabricIndex())); ChipLogByteSpan(Support, compressedFabricIdSpan); chip::ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); err = chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, devCtrl->GetFabricIndex(), defaultIpk, compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); sICDClientStorage.UpdateFabricList(devCtrl->GetFabricIndex()); pairingDelegate->SetFabricIndex(devCtrl->GetFabricIndex()); *outDevCtrl = devCtrl.release(); *outPairingDelegate = pairingDelegate.release(); return ToPyChipError(CHIP_NO_ERROR); } PyChipError pychip_OpCreds_InitGroupTestingData(chip::Controller::DeviceCommissioner * devCtrl) { VerifyOrReturnError(devCtrl != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); CHIP_ERROR err = devCtrl->GetCompressedFabricIdBytes(compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); err = chip::GroupTesting::InitData(&sGroupDataProvider, devCtrl->GetFabricIndex(), compressedFabricIdSpan); return ToPyChipError(err); } PyChipError pychip_OpCreds_SetMaximallyLargeCertsUsed(OpCredsContext * context, bool enabled) { VerifyOrReturnError(context != nullptr && context->mAdapter != nullptr, ToPyChipError(CHIP_ERROR_INCORRECT_STATE)); context->mAdapter->SetMaximallyLargeCertsUsed(enabled); return ToPyChipError(CHIP_NO_ERROR); } void pychip_OpCreds_FreeDelegate(OpCredsContext * context) { Platform::Delete(context); } PyChipError pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl, chip::Controller::ScriptDevicePairingDelegate * pairingDelegate) { if (devCtrl != nullptr) { devCtrl->Shutdown(); delete devCtrl; } if (pairingDelegate != nullptr) { delete pairingDelegate; } return ToPyChipError(CHIP_NO_ERROR); } PyChipError pychip_DeviceController_SetIpk(chip::Controller::DeviceCommissioner * devCtrl, const uint8_t * ipk, size_t ipkLen) { VerifyOrReturnError(ipk != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); CHIP_ERROR err = devCtrl->GetCompressedFabricIdBytes(compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); err = chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, devCtrl->GetFabricIndex(), ByteSpan(ipk, ipkLen), compressedFabricIdSpan); return ToPyChipError(err); } bool pychip_TestCommissionerUsed() { return sTestCommissioner.GetTestCommissionerUsed(); } bool pychip_TestCommissioningCallbacks() { return sTestCommissioner.CheckCallbacks(); } bool pychip_TestCommissioningStageSuccessful(uint8_t stage) { return sTestCommissioner.CheckStageSuccessful(stage); } bool pychip_TestPaseConnection(NodeId nodeId) { return sTestCommissioner.CheckPaseConnection(nodeId); } void pychip_ResetCommissioningTests() { sTestCommissioner.Reset(); } // Returns True if this is a valid test, false otherwise bool pychip_SetTestCommissionerSimulateFailureOnStage(uint8_t failStage) { return sTestCommissioner.SimulateFailAfter(static_cast(failStage)); } bool pychip_SetTestCommissionerSimulateFailureOnReport(uint8_t failStage) { return sTestCommissioner.SimulateFailOnReport(static_cast(failStage)); } bool pychip_SetTestCommissionerPrematureCompleteAfter(uint8_t stage) { return sTestCommissioner.PrematureCompleteAfter(static_cast(stage)); } PyChipError pychip_GetCompletionError() { return ToPyChipError(sTestCommissioner.GetCompletionError()); } } // extern "C"