Skip to content

Commit

Permalink
CertificateAuthority + Manager support in Python (#21981)
Browse files Browse the repository at this point in the history
* CertificateAuthority + Manager support in Python

This shifts the logic in the existing FabricAdmin that manages a given
Root CA to its own CertificateAuthority class. This now permits a more
spec-aligned structure that has a CertificateAuthorityManager that
manages a set of CertificateAuthority instances, each associated with a
single Root PK. Each of those manages a list of FabricAdmins
adminstering a fabric within that CA, which in turn manage a list of
ChipDeviceController instances within that fabric.

These now permit passing in separate PersistentStorage instances so that
it is more flexible/easier to sand-box each CA's storage constructs,
which makes it easier to integrate with chip-tool's INI files.

The PersistentStorage construct has been updated to permit both storage
to file as well as just a 'soft' cache.

* Review feedback
  • Loading branch information
mrjerryjohns authored and pull[bot] committed Aug 2, 2023
1 parent bfd0f84 commit 1894465
Show file tree
Hide file tree
Showing 13 changed files with 610 additions and 327 deletions.
70 changes: 44 additions & 26 deletions scripts/tools/convert_ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import click
import typing
import re
from os.path import exists
import logging


def convert_ini_to_json(ini_dir: str, json_path: str):
Expand All @@ -32,39 +34,55 @@ def convert_ini_to_json(ini_dir: str, json_path: str):
"""
python_json_store = {}

python_json_store['repl-config'] = {
'fabricAdmins': {
'1': {
'fabricId': 1,
'vendorId': 65521
},
'2': {
'fabricId': 2,
'vendorId': 65521
},
'3': {
'fabricId': 3,
'vendorId': 65521
}
}
}

python_json_store['sdk-config'] = {}

load_ini_into_dict(ini_file=ini_dir + '/chip_tool_config.alpha.ini',
json_dict=python_json_store['sdk-config'], replace_suffix='1')
load_ini_into_dict(ini_file=ini_dir + '/chip_tool_config.beta.ini',
json_dict=python_json_store['sdk-config'], replace_suffix='2')
load_ini_into_dict(ini_file=ini_dir + '/chip_tool_config.gamma.ini',
json_dict=python_json_store['sdk-config'], replace_suffix='3')
ini_file_paths = ['/chip_tool_config.alpha.ini', '/chip_tool_config.beta.ini', '/chip_tool_config.gamma.ini']
counter = 1

for path in ini_file_paths:
full_path = ini_dir + path
if (exists(full_path)):
logging.critical(f"Found chip tool INI file at: {full_path} - Converting...")
create_repl_config_from_init(ini_file=full_path,
json_dict=python_json_store, replace_suffix=str(counter))
counter = counter + 1

json_file = open(json_path, 'w')
json.dump(python_json_store, json_file, ensure_ascii=True, indent=4)


def create_repl_config_from_init(ini_file: str, json_dict: typing.Dict, replace_suffix: str):
''' This updates a provided JSON dictionary to create a REPL compliant configuration store that
contains the correct 'repl-config' and 'sdk-config' keys built from the provided chip-tool
INI file that contains the root public keys. The INI file will typically be named
with the word 'alpha', 'beta' or 'gamma' in the name.
ini_file: Path to source INI file
json_dict: JSON dictionary to be updated. Multiple passes through this function using
the same dictionary is possible.
replace_suffix: The credentials in the INI file typically have keys that end with 0. This suffix
can be replaced with a different number.
'''
if ('repl-config' not in json_dict):
json_dict['repl-config'] = {}

if ('caList' not in json_dict['repl-config']):
json_dict['repl-config']['caList'] = {}

json_dict['repl-config']['caList'][replace_suffix] = [
{'fabricId': int(replace_suffix), 'vendorId': 0XFFF1}
]

if ('sdk-config' not in json_dict):
json_dict['sdk-config'] = {}

load_ini_into_dict(ini_file=ini_file, json_dict=json_dict['sdk-config'], replace_suffix=replace_suffix)


def load_ini_into_dict(ini_file: str, json_dict: typing.Dict, replace_suffix: str):
""" Loads the specific INI file into the provided dictionary. A 'replace_suffix' string
""" Loads the specific INI file containing CA credential information into the provided dictionary. A 'replace_suffix' string
has to be provided to convert the existing numerical suffix to a different value.
NOTE: This does not do any conversion of the keys into a format acceptable by the Python REPL environment. Please see
create_repl_config_from_init above if that is desired.
"""
config = ConfigParser()

Expand Down
1 change: 1 addition & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ chip_python_wheel_action("chip-core") {
{
src_dir = "."
sources = [
"chip/CertificateAuthority.py",
"chip/ChipBleBase.py",
"chip/ChipBleUtility.py",
"chip/ChipBluezMgr.py",
Expand Down
44 changes: 20 additions & 24 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ chip::Controller::CommissioningParameters sCommissioningParameters;

chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;
chip::Controller::ScriptPairingDeviceDiscoveryDelegate sPairingDeviceDiscoveryDelegate;
chip::Controller::Python::StorageAdapter * sStorageAdapter = nullptr;
chip::Credentials::GroupDataProviderImpl sGroupDataProvider;
chip::Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore;

Expand All @@ -111,7 +110,7 @@ chip::NodeId kDefaultLocalDeviceId = chip::kTestControllerNodeId;
chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId;

extern "C" {
ChipError::StorageType pychip_DeviceController_StackInit();
ChipError::StorageType pychip_DeviceController_StackInit(Controller::Python::StorageAdapter * storageAdapter);
ChipError::StorageType pychip_DeviceController_StackShutdown();

ChipError::StorageType pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
Expand Down Expand Up @@ -205,43 +204,40 @@ chip::ChipError::StorageType pychip_InteractionModel_ShutdownSubscription(Subscr
//
// Storage
//
void pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context,
chip::Controller::Python::SyncSetKeyValueCb setCb,
chip::Controller::Python::SetGetKeyValueCb getCb,
chip::Controller::Python::SyncDeleteKeyValueCb deleteCb);
void pychip_Storage_ShutdownAdapter();
void * pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context,
chip::Controller::Python::SyncSetKeyValueCb setCb,
chip::Controller::Python::SetGetKeyValueCb getCb,
chip::Controller::Python::SyncDeleteKeyValueCb deleteCb);
void pychip_Storage_ShutdownAdapter(chip::Controller::Python::StorageAdapter * storageAdapter);
}

void pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context,
chip::Controller::Python::SyncSetKeyValueCb setCb,
chip::Controller::Python::SetGetKeyValueCb getCb,
chip::Controller::Python::SyncDeleteKeyValueCb deleteCb)
void * pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context,
chip::Controller::Python::SyncSetKeyValueCb setCb,
chip::Controller::Python::SetGetKeyValueCb getCb,
chip::Controller::Python::SyncDeleteKeyValueCb deleteCb)
{
sStorageAdapter = new chip::Controller::Python::StorageAdapter(context, setCb, getCb, deleteCb);
auto ptr = new chip::Controller::Python::StorageAdapter(context, setCb, getCb, deleteCb);
return ptr;
}

void pychip_Storage_ShutdownAdapter()
void pychip_Storage_ShutdownAdapter(chip::Controller::Python::StorageAdapter * storageAdapter)
{
delete sStorageAdapter;
delete storageAdapter;
}

chip::Controller::Python::StorageAdapter * pychip_Storage_GetStorageAdapter()
ChipError::StorageType pychip_DeviceController_StackInit(Controller::Python::StorageAdapter * storageAdapter)
{
return sStorageAdapter;
}

ChipError::StorageType pychip_DeviceController_StackInit()
{
VerifyOrDie(sStorageAdapter != nullptr);
VerifyOrDie(storageAdapter != nullptr);

FactoryInitParams factoryParams;
factoryParams.fabricIndependentStorage = sStorageAdapter;

sGroupDataProvider.SetStorageDelegate(sStorageAdapter);
factoryParams.fabricIndependentStorage = storageAdapter;

sGroupDataProvider.SetStorageDelegate(storageAdapter);
ReturnErrorOnFailure(sGroupDataProvider.Init().AsInteger());
factoryParams.groupDataProvider = &sGroupDataProvider;

ReturnErrorOnFailure(sPersistentStorageOpCertStore.Init(sStorageAdapter).AsInteger());
ReturnErrorOnFailure(sPersistentStorageOpCertStore.Init(storageAdapter).AsInteger());
factoryParams.opCertStore = &sPersistentStorageOpCertStore;

factoryParams.enableServerInteractions = true;
Expand Down
12 changes: 4 additions & 8 deletions src/controller/python/OpCredsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ class OperationalCredentialsAdapter : public OperationalCredentialsDelegate
} // namespace Controller
} // namespace chip

extern chip::Controller::Python::StorageAdapter * pychip_Storage_GetStorageAdapter();
extern chip::Credentials::GroupDataProviderImpl sGroupDataProvider;
extern chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;

Expand Down Expand Up @@ -291,17 +290,13 @@ struct OpCredsContext
void * mPyContext;
};

void * pychip_OpCreds_InitializeDelegate(void * pyContext, uint32_t fabricCredentialsIndex)
void * pychip_OpCreds_InitializeDelegate(void * pyContext, uint32_t fabricCredentialsIndex,
Controller::Python::StorageAdapter * storageAdapter)
{
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)
if (context->mAdapter->Initialize(*storageAdapter) != CHIP_NO_ERROR)
{
return nullptr;
}
Expand Down Expand Up @@ -339,6 +334,7 @@ ChipError::StorageType pychip_OpCreds_AllocateController(OpCredsContext * contex
{
paaTrustStorePath = "./credentials/development/paa-root-certs";
}

ChipLogProgress(Support, "Using device attestation PAA trust store path %s.", paaTrustStorePath);

// Initialize device attestation verifier
Expand Down
Loading

0 comments on commit 1894465

Please sign in to comment.