| /* |
| * |
| * 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 <app/codegen-data-model-provider/Instance.h> |
| #include <controller/CHIPDeviceController.h> |
| #include <controller/CHIPDeviceControllerFactory.h> |
| #include <controller/ExampleOperationalCredentialsIssuer.h> |
| #include <controller/python/chip/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 <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"); |
| chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore)); |
| |
| factoryParams.fabricIndependentStorage = &gServerStorage; |
| factoryParams.sessionKeystore = &gSessionKeystore; |
| factoryParams.dataModelProvider = chip::app::CodegenDataModelProviderInstance(); |
| |
| // 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: %s", chip::ErrorStr(err)); |
| 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; |
| |
| 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: %s", chip::ErrorStr(err)); |
| }); |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(Controller, "Commissioner initialization failed: %s", chip::ErrorStr(err)); |
| 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); |
| } |