Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Python] Add Python commissioning flow #25119

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/tests/cirque_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ CIRQUE_TESTS=(
"SplitCommissioningTest"
"CommissioningFailureTest"
"CommissioningFailureOnReportTest"
"PythonCommissioningTest"
"CommissioningWindowTest"
)

Expand Down
11 changes: 11 additions & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ shared_library("ChipDeviceCtrl") {
"OpCredsBinding.cpp",
"chip/clusters/attribute.cpp",
"chip/clusters/command.cpp",
"chip/credentials/cert.cpp",
"chip/crypto/p256keypair.cpp",
"chip/discovery/NodeResolution.cpp",
"chip/interaction_model/Delegate.cpp",
"chip/interaction_model/Delegate.h",
Expand Down Expand Up @@ -213,7 +215,13 @@ chip_python_wheel_action("chip-core") {
"chip/clusters/Command.py",
"chip/clusters/__init__.py",
"chip/clusters/enum.py",
"chip/commissioning/__init__.py",
"chip/commissioning/commissioning_flow_blocks.py",
"chip/commissioning/pase.py",
"chip/configuration/__init__.py",
"chip/credentials/cert.py",
"chip/crypto/fabric.py",
"chip/crypto/p256keypair.py",
"chip/discovery/__init__.py",
"chip/discovery/library_handle.py",
"chip/discovery/types.py",
Expand Down Expand Up @@ -270,7 +278,10 @@ chip_python_wheel_action("chip-core") {
"chip.ble",
"chip.ble.commissioning",
"chip.configuration",
"chip.commissioning",
"chip.clusters",
"chip.credentials",
"chip.crypto",
"chip.utils",
"chip.discovery",
"chip.exceptions",
Expand Down
121 changes: 108 additions & 13 deletions src/controller/python/OpCredsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include "ChipDeviceController-StorageDelegate.h"

#include "controller/python/chip/crypto/p256keypair.h"
#include "controller/python/chip/interaction_model/Delegate.h"

#include <controller/CHIPDeviceController.h>
Expand All @@ -36,6 +37,7 @@
#include <lib/support/TestGroupData.h>
#include <lib/support/logging/CHIPLogging.h>

#include <controller/python/chip/commissioning/PlaceholderOperationalCredentialsIssuer.h>
#include <controller/python/chip/native/PyChipError.h>
#include <credentials/GroupDataProviderImpl.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
Expand All @@ -57,6 +59,8 @@ const chip::Credentials::AttestationTrustStore * GetTestFileAttestationTrustStor

return &attestationTrustStore;
}

chip::Python::PlaceholderOperationalCredentialsIssuer sPlaceholderOperationalCredentialsIssuer;
} // namespace

namespace chip {
Expand Down Expand Up @@ -369,11 +373,74 @@ void pychip_OnCommissioningStatusUpdate(chip::PeerId peerId, chip::Controller::C
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,
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
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)
{
ReturnErrorCodeIf(nocLen > Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY));
ReturnErrorCodeIf(icacLen > Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY));
ReturnErrorCodeIf(rcacLen > Controller::kMaxCHIPDERCertLength, ToPyChipError(CHIP_ERROR_NO_MEMORY));

ChipLogDetail(Controller, "Creating New Device Controller");

auto devCtrl = std::make_unique<chip::Controller::DeviceCommissioner>();
VerifyOrReturnError(devCtrl != nullptr, ToPyChipError(CHIP_ERROR_NO_MEMORY));

Controller::SetupParams initParams;
initParams.pairingDelegate = &sPairingDelegate;
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<unsigned>(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();

return ToPyChipError(CHIP_NO_ERROR);
}

// TODO(#25214): Need clean up API
PyChipError pychip_OpCreds_AllocateController(OpCredsContext * context, chip::Controller::DeviceCommissioner ** outDevCtrl,
FabricId fabricId, chip::NodeId nodeId, chip::VendorId adminVendorId,
const char * paaTrustStorePath, bool useTestCommissioner,
bool enableServerInteractions, CASEAuthTag * caseAuthTags, uint32_t caseAuthTagLen)
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));
Expand All @@ -393,8 +460,18 @@ PyChipError pychip_OpCreds_AllocateController(OpCredsContext * context, chip::Co
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));

chip::Crypto::P256Keypair ephemeralKey;
CHIP_ERROR err = ephemeralKey.Initialize(chip::Crypto::ECPKeyTarget::ECDSA);
VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err));
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<uint8_t> noc;
ReturnErrorCodeIf(!noc.Alloc(Controller::kMaxCHIPDERCertLength), ToPyChipError(CHIP_ERROR_NO_MEMORY));
Expand All @@ -419,19 +496,21 @@ PyChipError pychip_OpCreds_AllocateController(OpCredsContext * context, chip::Co

memcpy(catValues.values.data(), caseAuthTags, caseAuthTagLen * sizeof(CASEAuthTag));

err = context->mAdapter->GenerateNOCChain(nodeId, fabricId, catValues, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan);
err =
context->mAdapter->GenerateNOCChain(nodeId, fabricId, catValues, controllerKeyPair->Pubkey(), rcacSpan, icacSpan, nocSpan);
VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err));

Controller::SetupParams initParams;
initParams.pairingDelegate = &sPairingDelegate;
initParams.operationalCredentialsDelegate = context->mAdapter.get();
initParams.operationalKeypair = &ephemeralKey;
initParams.controllerRCAC = rcacSpan;
initParams.controllerICAC = icacSpan;
initParams.controllerNOC = nocSpan;
initParams.enableServerInteractions = enableServerInteractions;
initParams.controllerVendorId = adminVendorId;
initParams.permitMultiControllerFabrics = true;
initParams.pairingDelegate = &sPairingDelegate;
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)
{
Expand Down Expand Up @@ -505,6 +584,22 @@ PyChipError pychip_DeviceController_DeleteDeviceController(chip::Controller::Dev
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();
Expand Down
Loading