diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index a90f59f2f33952..4b4b2e98105541 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -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", diff --git a/src/controller/python/OpCredsBinding.cpp b/src/controller/python/OpCredsBinding.cpp index 57fe36d21f9b99..5cdad3cc817e15 100644 --- a/src/controller/python/OpCredsBinding.cpp +++ b/src/controller/python/OpCredsBinding.cpp @@ -44,6 +44,7 @@ #include #include #include +#include using namespace chip; @@ -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 @@ -700,4 +710,15 @@ PyChipError pychip_GetCompletionError() return ToPyChipError(sTestCommissioner.GetCompletionError()); } +PyChipError pychip_DeviceController_SetDACRevocationSetPath(const char * dacRevocationSetPath) +{ + Credentials::DeviceAttestationRevocationDelegate * dacRevocationDelegate = + GetTestAttestationRevocationDelegate(dacRevocationSetPath); + 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" diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index b330a2924121c0..013243c8c4b726 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -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 @@ -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. diff --git a/src/controller/python/chip/FabricAdmin.py b/src/controller/python/chip/FabricAdmin.py index a7c5fb86166339..d575f4690fa801 100644 --- a/src/controller/python/chip/FabricAdmin.py +++ b/src/controller/python/chip/FabricAdmin.py @@ -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 @@ -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( @@ -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 diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h index 7e0fc1c4378848..5cce0bc94e8ad2 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h @@ -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: diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index e6915931a73b68..e51a70632dc73e 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -260,6 +260,9 @@ class ArrayAttestationTrustStore : public AttestationTrustStore const size_t mNumCerts; }; +// forward declaration +class DeviceAttestationRevocationDelegate; + class DeviceAttestationVerifier { public: @@ -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); diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 1054463ea64489..49249cc7dabb0f 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -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: @@ -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 = [] @@ -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, @@ -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)