|  | /* | 
|  | * | 
|  | *    Copyright (c) 2021-2022 Project CHIP Authors | 
|  | * | 
|  | *    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 <memory> | 
|  |  | 
|  | #include <controller/CHIPDeviceController.h> | 
|  | #include <controller/CHIPDeviceControllerFactory.h> | 
|  | #include <controller/ExampleOperationalCredentialsIssuer.h> | 
|  | #include <controller/python/matter/native/PyChipError.h> | 
|  | #include <credentials/GroupDataProviderImpl.h> | 
|  | #include <credentials/PersistentStorageOpCertStore.h> | 
|  | #include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h> | 
|  | #include <credentials/attestation_verifier/DeviceAttestationVerifier.h> | 
|  | #include <credentials/attestation_verifier/FileAttestationTrustStore.h> | 
|  | #include <crypto/RawKeySessionKeystore.h> | 
|  | #include <data-model-providers/codegen/Instance.h> | 
|  | #include <lib/support/CodeUtils.h> | 
|  | #include <lib/support/ScopedBuffer.h> | 
|  | #include <lib/support/TestGroupData.h> | 
|  | #include <lib/support/ThreadOperationalDataset.h> | 
|  | #include <lib/support/logging/CHIPLogging.h> | 
|  | #include <platform/CHIPDeviceLayer.h> | 
|  | #include <platform/KeyValueStoreManager.h> | 
|  |  | 
|  | #include "ChipThreadWork.h" | 
|  |  | 
|  | using DeviceControllerFactory = chip::Controller::DeviceControllerFactory; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const chip::Credentials::AttestationTrustStore * GetTestFileAttestationTrustStore(const char * paaTrustStorePath) | 
|  | { | 
|  | static chip::Credentials::FileAttestationTrustStore attestationTrustStore{ paaTrustStorePath }; | 
|  |  | 
|  | return &attestationTrustStore; | 
|  | } | 
|  |  | 
|  | class ServerStorageDelegate : public chip::PersistentStorageDelegate | 
|  | { | 
|  | public: | 
|  | CHIP_ERROR | 
|  | SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override | 
|  | { | 
|  | size_t bytesRead = 0; | 
|  | CHIP_ERROR err   = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size, &bytesRead); | 
|  | size             = static_cast<uint16_t>(bytesRead); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override | 
|  | { | 
|  | return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(key, value, size); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR SyncDeleteKeyValue(const char * key) override | 
|  | { | 
|  | return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(key); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // FIXME: implement this class | 
|  | class ScriptDevicePairingDelegate final : public chip::Controller::DevicePairingDelegate | 
|  | { | 
|  | public: | 
|  | using OnPairingCompleteCallback = void (*)(CHIP_ERROR err); | 
|  |  | 
|  | ~ScriptDevicePairingDelegate() = default; | 
|  |  | 
|  | void OnPairingComplete(CHIP_ERROR error) override | 
|  | { | 
|  | if (mPairingComplete == nullptr) | 
|  | { | 
|  | ChipLogError(Controller, "Callback for pairing coomplete is not defined."); | 
|  | return; | 
|  | } | 
|  | mPairingComplete(error); | 
|  | } | 
|  |  | 
|  | void SetPairingCompleteCallback(OnPairingCompleteCallback callback) { mPairingComplete = callback; } | 
|  |  | 
|  | private: | 
|  | OnPairingCompleteCallback mPairingComplete = nullptr; | 
|  | }; | 
|  |  | 
|  | ServerStorageDelegate gServerStorage; | 
|  | ScriptDevicePairingDelegate gPairingDelegate; | 
|  | chip::Credentials::GroupDataProviderImpl gGroupDataProvider; | 
|  | chip::Credentials::PersistentStorageOpCertStore gPersistentStorageOpCertStore; | 
|  | chip::Controller::ExampleOperationalCredentialsIssuer gOperationalCredentialsIssuer; | 
|  | chip::Crypto::RawKeySessionKeystore gSessionKeystore; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | extern "C" void | 
|  | pychip_internal_PairingDelegate_SetPairingCompleteCallback(ScriptDevicePairingDelegate::OnPairingCompleteCallback callback) | 
|  | { | 
|  | gPairingDelegate.SetPairingCompleteCallback(callback); | 
|  | } | 
|  |  | 
|  | extern "C" chip::Controller::DeviceCommissioner * pychip_internal_Commissioner_New(uint64_t localDeviceId, | 
|  | uint32_t localCommissionerCAT) | 
|  | { | 
|  | std::unique_ptr<chip::Controller::DeviceCommissioner> result; | 
|  | CHIP_ERROR err; | 
|  |  | 
|  | chip::python::ChipMainThreadScheduleAndWait([&]() { | 
|  | result = std::make_unique<chip::Controller::DeviceCommissioner>(); | 
|  |  | 
|  | // System and Inet layers explicitly passed to indicate that the CHIP stack is | 
|  | // already assumed initialized | 
|  | chip::Controller::SetupParams commissionerParams; | 
|  | chip::Controller::FactoryInitParams factoryParams; | 
|  | chip::Platform::ScopedMemoryBuffer<uint8_t> noc; | 
|  | chip::Platform::ScopedMemoryBuffer<uint8_t> icac; | 
|  | chip::Platform::ScopedMemoryBuffer<uint8_t> rcac; | 
|  | chip::Crypto::P256Keypair ephemeralKey; | 
|  |  | 
|  | // Initialize device attestation verifier | 
|  | // TODO: add option to pass in custom PAA Trust Store path to the python controller app | 
|  | const chip::Credentials::AttestationTrustStore * testingRootStore = | 
|  | GetTestFileAttestationTrustStore("./credentials/development/paa-root-certs"); | 
|  | // TODO: Ensure that attestation revocation data is actually provided. | 
|  | chip::Credentials::DeviceAttestationRevocationDelegate * kDeviceAttestationRevocationNotChecked = nullptr; | 
|  | chip::Credentials::DeviceAttestationVerifier * dacVerifier = | 
|  | chip::Credentials::GetDefaultDACVerifier(testingRootStore, kDeviceAttestationRevocationNotChecked); | 
|  | VerifyOrDie(dacVerifier != nullptr); | 
|  | dacVerifier->EnableVerboseLogs(true); | 
|  | chip::Credentials::SetDeviceAttestationVerifier(dacVerifier); | 
|  |  | 
|  | factoryParams.fabricIndependentStorage = &gServerStorage; | 
|  | factoryParams.sessionKeystore          = &gSessionKeystore; | 
|  | factoryParams.dataModelProvider        = chip::app::CodegenDataModelProviderInstance(&gServerStorage); | 
|  |  | 
|  | // Initialize group data provider for local group key state and IPKs | 
|  | gGroupDataProvider.SetStorageDelegate(&gServerStorage); | 
|  | gGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore); | 
|  | err = gGroupDataProvider.Init(); | 
|  | SuccessOrExit(err); | 
|  | factoryParams.groupDataProvider = &gGroupDataProvider; | 
|  |  | 
|  | err = gPersistentStorageOpCertStore.Init(&gServerStorage); | 
|  | SuccessOrExit(err); | 
|  | factoryParams.opCertStore = &gPersistentStorageOpCertStore; | 
|  |  | 
|  | commissionerParams.pairingDelegate = &gPairingDelegate; | 
|  |  | 
|  | err = ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA); | 
|  | SuccessOrExit(err); | 
|  |  | 
|  | err = gOperationalCredentialsIssuer.Initialize(gServerStorage); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(Controller, "Operational credentials issuer initialization failed: %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | ExitNow(); | 
|  | } | 
|  |  | 
|  | VerifyOrExit(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); | 
|  | VerifyOrExit(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); | 
|  | VerifyOrExit(rcac.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); | 
|  |  | 
|  | { | 
|  | uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; | 
|  | chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); | 
|  | chip::ByteSpan defaultIpk; | 
|  |  | 
|  | chip::MutableByteSpan nocSpan(noc.Get(), chip::Controller::kMaxCHIPDERCertLength); | 
|  | chip::MutableByteSpan icacSpan(icac.Get(), chip::Controller::kMaxCHIPDERCertLength); | 
|  | chip::MutableByteSpan rcacSpan(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength); | 
|  |  | 
|  | err = gOperationalCredentialsIssuer.GenerateNOCChainAfterValidation( | 
|  | localDeviceId, /* fabricId = */ 1, { { localCommissionerCAT, chip::kUndefinedCAT, chip::kUndefinedCAT } }, | 
|  | ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan); | 
|  | SuccessOrExit(err); | 
|  |  | 
|  | commissionerParams.operationalCredentialsDelegate = &gOperationalCredentialsIssuer; | 
|  | commissionerParams.operationalKeypair             = &ephemeralKey; | 
|  | commissionerParams.controllerRCAC                 = rcacSpan; | 
|  | commissionerParams.controllerICAC                 = icacSpan; | 
|  | commissionerParams.controllerNOC                  = nocSpan; | 
|  | commissionerParams.deviceAttestationVerifier      = dacVerifier; | 
|  |  | 
|  | SuccessOrExit(err = DeviceControllerFactory::GetInstance().Init(factoryParams)); | 
|  | SuccessOrExit(err = DeviceControllerFactory::GetInstance().SetupCommissioner(commissionerParams, *result)); | 
|  |  | 
|  | SuccessOrExit(err = result->GetCompressedFabricIdBytes(compressedFabricIdSpan)); | 
|  | ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", | 
|  | static_cast<unsigned>(result->GetFabricIndex())); | 
|  | ChipLogByteSpan(Support, compressedFabricIdSpan); | 
|  |  | 
|  | defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); | 
|  | SuccessOrExit(err = chip::Credentials::SetSingleIpkEpochKey(&gGroupDataProvider, result->GetFabricIndex(), defaultIpk, | 
|  | compressedFabricIdSpan)); | 
|  | } | 
|  | exit: | 
|  | ChipLogProgress(Controller, "Commissioner initialization status: %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | }); | 
|  |  | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(Controller, "Commissioner initialization failed: %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return result.release(); | 
|  | } | 
|  |  | 
|  | /// Returns CHIP_ERROR corresponding to an UnpairDevice call | 
|  | extern "C" PyChipError pychip_internal_Commissioner_Unpair(chip::Controller::DeviceCommissioner * commissioner, | 
|  | uint64_t remoteDeviceId) | 
|  | { | 
|  | CHIP_ERROR err; | 
|  |  | 
|  | chip::python::ChipMainThreadScheduleAndWait([&]() { err = commissioner->UnpairDevice(remoteDeviceId); }); | 
|  |  | 
|  | return ToPyChipError(err); | 
|  | } | 
|  |  | 
|  | extern "C" PyChipError pychip_internal_Commissioner_BleConnectForPairing(chip::Controller::DeviceCommissioner * commissioner, | 
|  | uint64_t remoteNodeId, uint32_t pinCode, | 
|  | uint16_t discriminator) | 
|  | { | 
|  |  | 
|  | CHIP_ERROR err; | 
|  |  | 
|  | chip::python::ChipMainThreadScheduleAndWait([&]() { | 
|  | chip::RendezvousParameters params; | 
|  |  | 
|  | params.SetDiscriminator(discriminator).SetSetupPINCode(pinCode); | 
|  | #if CONFIG_NETWORK_LAYER_BLE | 
|  | params.SetBleLayer(chip::DeviceLayer::ConnectivityMgr().GetBleLayer()).SetPeerAddress(chip::Transport::PeerAddress::BLE()); | 
|  | #endif | 
|  |  | 
|  | err = commissioner->PairDevice(remoteNodeId, params); | 
|  | }); | 
|  |  | 
|  | return ToPyChipError(err); | 
|  | } |