blob: d5cc06aee8e0bbb33313ff1960c5ab7ff243e2ac [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 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 <type_traits>
#include "ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h"
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include "ChipDeviceController-StorageDelegate.h"
#include "controller/python/chip/interaction_model/Delegate.h"
#include <controller/CHIPDeviceController.h>
#include <controller/CHIPDeviceControllerFactory.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/DLLUtil.h>
#include <lib/support/ScopedBuffer.h>
#include <lib/support/logging/CHIPLogging.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
using namespace chip;
static_assert(std::is_same<uint32_t, ChipError::StorageType>::value, "python assumes CHIP_ERROR maps to c_uint32");
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 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 Crypto::P256PublicKey & pubKey, MutableByteSpan & rcac,
MutableByteSpan & icac, MutableByteSpan & noc)
{
return mExampleOpCredsIssuer.GenerateNOCChainAfterValidation(nodeId, fabricId, pubKey, rcac, icac, noc);
}
private:
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override
{
return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, attestationSignature, DAC, PAI, PAA, 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::Controller::Python::StorageAdapter * pychip_Storage_GetStorageAdapter();
extern chip::Controller::Python::StorageAdapter * sStorageAdapter;
extern chip::Controller::ScriptDeviceAddressUpdateDelegate sDeviceAddressUpdateDelegate;
extern chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;
bool sTestCommissionerUsed = false;
class TestCommissioner : public chip::Controller::AutoCommissioner
{
public:
TestCommissioner() : AutoCommissioner() {}
~TestCommissioner() {}
CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err,
chip::Controller::CommissioningDelegate::CommissioningReport report) override
{
sTestCommissionerUsed = true;
return chip::Controller::AutoCommissioner::CommissioningStepFinished(err, report);
}
};
TestCommissioner sTestCommissioner;
extern "C" {
struct OpCredsContext
{
Platform::UniquePtr<Controller::Python::OperationalCredentialsAdapter> mAdapter;
void * mPyContext;
};
void * pychip_OpCreds_InitializeDelegate(void * pyContext, uint32_t fabricCredentialsIndex)
{
auto context = Platform::MakeUnique<OpCredsContext>();
context->mAdapter = Platform::MakeUnique<Controller::Python::OperationalCredentialsAdapter>(fabricCredentialsIndex);
if (pychip_Storage_GetStorageAdapter() == nullptr)
{
return nullptr;
}
if (context->mAdapter->Initialize(*pychip_Storage_GetStorageAdapter()) != CHIP_NO_ERROR)
{
return nullptr;
}
return context.release();
}
ChipError::StorageType pychip_OpCreds_AllocateController(OpCredsContext * context,
chip::Controller::DeviceCommissioner ** outDevCtrl, uint8_t fabricIndex,
FabricId fabricId, chip::NodeId nodeId, bool useTestCommissioner)
{
ChipLogDetail(Controller, "Creating New Device Controller");
VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT.AsInteger());
auto devCtrl = std::make_unique<chip::Controller::DeviceCommissioner>();
VerifyOrReturnError(devCtrl != nullptr, CHIP_ERROR_NO_MEMORY.AsInteger());
// Initialize device attestation verifier
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
chip::Crypto::P256Keypair ephemeralKey;
CHIP_ERROR err = ephemeralKey.Initialize();
VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger());
chip::Platform::ScopedMemoryBuffer<uint8_t> noc;
ReturnErrorCodeIf(!noc.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY.AsInteger());
MutableByteSpan nocSpan(noc.Get(), Controller::kMaxCHIPDERCertLength);
chip::Platform::ScopedMemoryBuffer<uint8_t> icac;
ReturnErrorCodeIf(!icac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY.AsInteger());
MutableByteSpan icacSpan(icac.Get(), Controller::kMaxCHIPDERCertLength);
chip::Platform::ScopedMemoryBuffer<uint8_t> rcac;
ReturnErrorCodeIf(!rcac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY.AsInteger());
MutableByteSpan rcacSpan(rcac.Get(), Controller::kMaxCHIPDERCertLength);
err = context->mAdapter->GenerateNOCChain(nodeId, fabricId, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan);
VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger());
Controller::SetupParams initParams;
initParams.storageDelegate = sStorageAdapter;
initParams.deviceAddressUpdateDelegate = &sDeviceAddressUpdateDelegate;
initParams.pairingDelegate = &sPairingDelegate;
initParams.operationalCredentialsDelegate = context->mAdapter.get();
initParams.operationalKeypair = &ephemeralKey;
initParams.controllerRCAC = rcacSpan;
initParams.controllerICAC = icacSpan;
initParams.controllerNOC = nocSpan;
if (useTestCommissioner)
{
initParams.defaultCommissioner = &sTestCommissioner;
}
err = Controller::DeviceControllerFactory::GetInstance().SetupCommissioner(initParams, *devCtrl);
VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger());
*outDevCtrl = devCtrl.release();
return CHIP_NO_ERROR.AsInteger();
}
void pychip_OpCreds_FreeDelegate(OpCredsContext * context)
{
Platform::Delete(context);
}
ChipError::StorageType pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl)
{
if (devCtrl != NULL)
{
devCtrl->Shutdown();
delete devCtrl;
}
return CHIP_NO_ERROR.AsInteger();
}
bool pychip_TestCommissionerUsed()
{
return sTestCommissionerUsed;
}
} // extern "C"