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

controller/python: add device attestation revocation support #37134

Merged
merged 3 commits into from
Jan 30, 2025
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 src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ shared_library("ChipDeviceCtrl") {
"${chip_root}/src/app/icd/client:handler",
"${chip_root}/src/app/server",
"${chip_root}/src/credentials:default_attestation_verifier",
"${chip_root}/src/credentials:test_dac_revocation_delegate",
"${chip_root}/src/lib",
"${chip_root}/src/lib/core",
"${chip_root}/src/lib/dnssd",
Expand Down
21 changes: 21 additions & 0 deletions src/controller/python/OpCredsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/FileAttestationTrustStore.h>
#include <credentials/attestation_verifier/TestDACRevocationDelegateImpl.h>

using namespace chip;

Expand All @@ -61,6 +62,15 @@ const chip::Credentials::AttestationTrustStore * GetTestFileAttestationTrustStor
return &attestationTrustStore;
}

Credentials::DeviceAttestationRevocationDelegate * GetTestAttestationRevocationDelegate(const char * dacRevocationSetPath)
{
VerifyOrReturnValue(dacRevocationSetPath != nullptr, nullptr);

static Credentials::TestDACRevocationDelegateImpl testDacRevocationDelegate;
testDacRevocationDelegate.SetDeviceAttestationRevocationSetPath(dacRevocationSetPath);
return &testDacRevocationDelegate;
}

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

Expand Down Expand Up @@ -700,4 +710,15 @@ PyChipError pychip_GetCompletionError()
return ToPyChipError(sTestCommissioner.GetCompletionError());
}

PyChipError pychip_DeviceController_SetDACRevocationSetPath(const char * dacRevocationSetPath)
{
Credentials::DeviceAttestationRevocationDelegate * dacRevocationDelegate =
GetTestAttestationRevocationDelegate(dacRevocationSetPath);
tehampson marked this conversation as resolved.
Show resolved Hide resolved
VerifyOrReturnError(dacRevocationDelegate != nullptr, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT));

Credentials::DeviceAttestationVerifier * dacVerifier = Credentials::GetDeviceAttestationVerifier();
VerifyOrReturnError(dacVerifier != nullptr, ToPyChipError(CHIP_ERROR_INCORRECT_STATE));

return ToPyChipError(dacVerifier->SetRevocationDelegate(dacRevocationDelegate));
}
} // extern "C"
15 changes: 15 additions & 0 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,9 @@ def _InitLib(self):
self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.restype = PyChipError
self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.argtypes = [c_uint16, c_uint16]

self._dmLib.pychip_DeviceController_SetDACRevocationSetPath.restype = PyChipError
self._dmLib.pychip_DeviceController_SetDACRevocationSetPath.argtypes = [c_char_p]


class ChipDeviceController(ChipDeviceControllerBase):
''' The ChipDeviceCommissioner binding, named as ChipDeviceController
Expand Down Expand Up @@ -2308,6 +2311,18 @@ async def IssueNOCChain(self, csr: Clusters.OperationalCredentials.Commands.CSRR

return await asyncio.futures.wrap_future(ctx.future)

def SetDACRevocationSetPath(self, dacRevocationSetPath: typing.Optional[str]):
''' Set the path to the device attestation revocation set JSON file.

Args:
dacRevocationSetPath: Path to the JSON file containing the device attestation revocation set
'''
self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetDACRevocationSetPath(
c_char_p(str.encode(dacRevocationSetPath) if dacRevocationSetPath else None))
).raise_on_error()


class BareChipDeviceController(ChipDeviceControllerBase):
''' A bare device controller without AutoCommissioner support.
Expand Down
8 changes: 7 additions & 1 deletion src/controller/python/chip/FabricAdmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ def __init__(self, certificateAuthority: CertificateAuthority.CertificateAuthori
self._activeControllers: List[ChipDeviceCtrl.ChipDeviceController] = []

def NewController(self, nodeId: Optional[int] = None, paaTrustStorePath: str = "",
useTestCommissioner: bool = False, catTags: List[int] = [], keypair: p256keypair.P256Keypair = None):
useTestCommissioner: bool = False, catTags: List[int] = [], keypair: p256keypair.P256Keypair = None,
dacRevocationSetPath: str = ""):
''' Create a new chip.ChipDeviceCtrl.ChipDeviceController instance on this fabric.

When vending ChipDeviceController instances on a given fabric, each controller instance
Expand All @@ -77,6 +78,8 @@ def NewController(self, nodeId: Optional[int] = None, paaTrustStorePath: str = "
paaTrustStorePath: Path to the PAA trust store. If one isn't provided, a suitable default is selected.
useTestCommissioner: If a test commmisioner is to be created.
catTags: A list of 32-bit CAT tags that will added to the NOC generated for this controller.
keypair: A keypair to be used for the controller. If one isn't provided, a new one is generated.
dacRevocationSetPath: Path to the device attestation revocation set JSON file.
'''
if (not (self._isActive)):
raise RuntimeError(
Expand Down Expand Up @@ -107,6 +110,9 @@ def NewController(self, nodeId: Optional[int] = None, paaTrustStorePath: str = "
catTags=catTags,
keypair=keypair)

if dacRevocationSetPath and len(dacRevocationSetPath) > 0:
controller.SetDACRevocationSetPath(dacRevocationSetPath)

self._activeControllers.append(controller)
return controller

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ class DefaultDACVerifier : public DeviceAttestationVerifier

CsaCdKeysTrustStore * GetCertificationDeclarationTrustStore() override { return &mCdKeysTrustStore; }

void SetRevocationDelegate(DeviceAttestationRevocationDelegate * revocationDelegate)
CHIP_ERROR SetRevocationDelegate(DeviceAttestationRevocationDelegate * revocationDelegate) override
{
mRevocationDelegate = revocationDelegate;
return CHIP_NO_ERROR;
}

protected:
Expand Down
15 changes: 15 additions & 0 deletions src/credentials/attestation_verifier/DeviceAttestationVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ class ArrayAttestationTrustStore : public AttestationTrustStore
const size_t mNumCerts;
};

// forward declaration
class DeviceAttestationRevocationDelegate;

class DeviceAttestationVerifier
{
public:
Expand Down Expand Up @@ -410,6 +413,18 @@ class DeviceAttestationVerifier
void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; }
bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; }

/**
* @brief Try to set the revocation delegate.
*
* @param[in] revocationDelegate The revocation delegate to set.
*
* @return CHIP_NO_ERROR on success, CHIP_ERROR_NOT_IMPLEMENTED if the revocation delegate is not supported.
*/
virtual CHIP_ERROR SetRevocationDelegate(DeviceAttestationRevocationDelegate * revocationDelegate)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

protected:
CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements,
const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,8 @@ class MatterTestConfig:
# Accepted Terms and Conditions if used
tc_version_to_simulate: int = None
tc_user_response_to_simulate: int = None
# path to device attestation revocation set json file
dac_revocation_set_path: Optional[pathlib.Path] = None


class ClusterMapper:
Expand Down Expand Up @@ -1949,6 +1951,7 @@ def convert_args_to_matter_config(args: argparse.Namespace) -> MatterTestConfig:

config.tc_version_to_simulate = args.tc_version_to_simulate
config.tc_user_response_to_simulate = args.tc_user_response_to_simulate
config.dac_revocation_set_path = args.dac_revocation_set_path

# Accumulate all command-line-passed named args
all_global_args = []
Expand Down Expand Up @@ -1984,6 +1987,8 @@ def parse_matter_test_args(argv: Optional[List[str]] = None) -> MatterTestConfig
paa_path_default = get_default_paa_trust_store(pathlib.Path.cwd())
basic_group.add_argument('--paa-trust-store-path', action="store", type=pathlib.Path, metavar="PATH", default=paa_path_default,
help="PAA trust store path (default: %s)" % str(paa_path_default))
basic_group.add_argument('--dac-revocation-set-path', action="store", type=pathlib.Path, metavar="PATH",
help="Path to JSON file containing the device attestation revocation set.")
basic_group.add_argument('--ble-interface-id', action="store", type=int,
metavar="INTERFACE_ID", help="ID of BLE adapter (from hciconfig)")
basic_group.add_argument('-N', '--controller-node-id', type=int_decimal_or_hex,
Expand Down Expand Up @@ -2506,7 +2511,8 @@ def run_tests_no_exit(test_class: MatterBaseTest, matter_test_config: MatterTest
default_controller = stack.certificate_authorities[0].adminList[0].NewController(
nodeId=matter_test_config.controller_node_id,
paaTrustStorePath=str(matter_test_config.paa_trust_store_path),
catTags=matter_test_config.controller_cat_tags
catTags=matter_test_config.controller_cat_tags,
dacRevocationSetPath=str(matter_test_config.dac_revocation_set_path),
)
test_config.user_params["default_controller"] = stash_globally(default_controller)

Expand Down
Loading