Implement commissioner-side support for Per-Device Credentials - #74032
Implement commissioner-side support for Per-Device Credentials#74032ksperling-apple wants to merge 5 commits into
Conversation
Alongside the definition of CertificateKeyId.
Implement support for PDC commissioning steps in the DeviceCommissioner and AutoCommissioner. The new abstraction introduced to handle the interaction with the network infrastructure (i.e. with the NETIM cluster on a NIM device) is the NetworkIdentityRegistrar. The registrar provides the low-level operations for retrieval of the Network Identity and registration and unregistration of the Network Client Identity during commissioning. The DeviceCommissioner gains two new steps (kPDCGetNetworkIdentity and kPDCRegisterClientIdentity) that encapsulate those interactions and handles roll-back of the client identity if commissioning does not succeed. The kWiFiNetworkSetup step is updated to use the PDC variant of AddOrUpdateWiFiNetwork as necessary. The commissioner validates that both the network and client identities are valid, and that the commissionee holds the private key for the client identity. Note the two new steps are inserted in the appropriate places in the enum (kPDCRegisterClientIdentity inside the kWiFiNetworkSetup .. kICDSendStayActive range, and kPDCGetNetworkIdentity before kCleanup), so some existing enum values are being renumbered. The AutoCommissioner (or other commissioning delegate) is responsible for orchestration and propagating the step outputs from CommissioningReports into CommissioningParameters for subsequent steps. Note that PDC commissioning support is not guarded behind an ifdef, since commissioners that support Wi-Fi SHOULD support PDC, and there is currently no supported way to build e.g. a Thread-only commissioner in any case.
This class implements the NetworkIdentityRegistrar interface expected by the DeviceCommissioner by interacting with a Network Identity Management cluster server (generally on a NIM device).
This adds --pdc-netim-node-id and --pdc-netim-endpoint-id endpoint arguments to existing WiFi commissioning commands. If they are specified, a PDC-capable commissionee will be commissioned with PDC credentials obtained from the pointed-to Network Infrastructure Management cluster server (generally on a NIM device). If the commissionee is not PDC-capable, the password parameter will be used as before. (The special password value of "-", which is not a valid WiFi password, can be used to disable that fallback.)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (26)
💤 Files with no reviewable changes (3)
Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review. 📝 WalkthroughWalkthroughThis change adds Per-Device Credentials commissioning for Wi-Fi networks. It defines network identity registrar interfaces and NIM operations, adds PDC commissioning stages and report data, verifies possession signatures, and registers client identities. DeviceCommissioner now rolls back registrations during failures, cancellation, and shutdown. chip-tool pairing accepts registrar node and endpoint arguments and defers exit during revocation. Tests cover registrar lifecycle, commissioning, validation, retries, and rollback. Sequence Diagram(s)sequenceDiagram
participant chip-tool
participant DeviceCommissioner
participant NetworkIdentityManagementRegistrar
participant Commissionee
chip-tool->>DeviceCommissioner: Start pairing with PDC credentials
DeviceCommissioner->>NetworkIdentityManagementRegistrar: GetNetworkIdentity
NetworkIdentityManagementRegistrar-->>DeviceCommissioner: Return network identity
DeviceCommissioner->>Commissionee: Configure Wi-Fi with PDC data
Commissionee-->>DeviceCommissioner: Return client identity and signature
DeviceCommissioner->>NetworkIdentityManagementRegistrar: RegisterClient
DeviceCommissioner-->>chip-tool: Complete pairing or defer for rollback
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to No concrete current-head issue remains that should block merging. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 36.13% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 238 functions across 21 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
🟡 Changes recommended
A missing required include for PRIX32 in src/credentials/CHIPCert.h can cause build failures (and there is also a small doc typo to fix).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Implements commissioner-side commissioning support for Wi‑Fi Per-Device Credentials (PDC) by introducing a NetworkIdentityRegistrar abstraction, integrating new commissioning stages into AutoCommissioner/DeviceCommissioner, and wiring chip-tool CLI support for NETIM-driven PDC flows.
Changes:
- Add two new commissioning stages (
kPDCGetNetworkIdentity,kPDCRegisterClientIdentity) and associated parameter/report plumbing (network identity, client identity, possession nonce/signature, rollback policy). - Implement
NetworkIdentityManagementRegistrarto drive the Network Identity Management cluster and provide lifecycle/idle-wait semantics. - Extend chip-tool pairing commands with
--pdc-netim-node-id/--pdc-netim-endpoint-id, plus substantial new unit test coverage for commissioner and registrar behavior.
File summaries
| File | Description |
|---|---|
| src/python_testing/TC_CGEN_2_2.py | Updates Python test’s hardcoded commissioning stage number to reflect enum renumbering. |
| src/credentials/CHIPCert.h | Adds common logging macros for CertificateKeyId rendering. |
| src/controller/tests/TestPDCCommissioning.cpp | Adds comprehensive unit tests for PDC flows across AutoCommissioner/DeviceCommissioner, including rollback and retry behavior. |
| src/controller/tests/TestNetworkIdentityManagementRegistrar.cpp | Adds lifecycle/idle-wait unit tests for NetworkIdentityManagementRegistrar. |
| src/controller/tests/TestCommissioningDelegate.cpp | Extends commissioning parameter setter/getter tests for new PDC-related fields. |
| src/controller/tests/TestAutoCommissioner.cpp | Adds tests ensuring PDCPossessionNonce buffer constraints and span relocation behavior. |
| src/controller/tests/DeviceCommissionerTestAccess.h | Exposes PDC-specific internal hooks for tests (verification and registration state). |
| src/controller/tests/BUILD.gn | Registers new controller test sources. |
| src/controller/tests/AutoCommissionerTestAccess.h | Exposes additional test accessors used by new PDC tests. |
| src/controller/NetworkIdentityRegistrar.h | Introduces registrar interface used by commissioner for PDC identity query/register/revoke. |
| src/controller/NetworkIdentityManagementRegistrar.h | Adds concrete registrar implementation interface + idle-wait/shutdown semantics. |
| src/controller/NetworkIdentityManagementRegistrar.cpp | Implements NETIM-backed registrar operations, cancellation, and idle-wait notification ordering. |
| src/controller/ControllerOperation.h | Introduces reusable controller operation base for CASE-connect + optional invoke lifecycle. |
| src/controller/ControllerOperation.cpp | Implements controller operation connection/invoke cancellation plumbing. |
| src/controller/CommissioningDelegate.h | Adds new stages, WiFiCredentials/CommissioningParameters extensions, and new report variants. |
| src/controller/CommissioningDelegate.cpp | Adds StageToString/MetricKey support for the new PDC stages. |
| src/controller/CHIPDeviceController.h | Adds PDC callbacks, verification, and rollback tracking fields to DeviceCommissioner. |
| src/controller/CHIPDeviceController.cpp | Implements PDC stage behavior, response validation, registrar interactions, and rollback/wait logic. |
| src/controller/BUILD.gn | Wires new controller sources into the build. |
| src/controller/AutoCommissioner.h | Adds PDC buffers and ClearPDCParameters() API. |
| src/controller/AutoCommissioner.cpp | Implements PDC stage selection, parameter capture/clearing, nonce generation, and retry/cleanup behavior. |
| src/app/clusters/network-identity-management-server/NetworkIdentityManagementCluster.cpp | Removes now-redundant include of the deleted logging header. |
| src/app/clusters/network-identity-management-server/Logging.h | Deletes cluster-local KeyId logging macros (moved to shared credentials header). |
| src/app/clusters/network-identity-management-server/BUILD.gn | Removes Logging.h from the build sources list. |
| examples/chip-tool/commands/pairing/PairingCommand.h | Adds CLI args and state for NETIM-backed PDC registrar lifecycle management. |
| examples/chip-tool/commands/pairing/PairingCommand.cpp | Implements NETIM registrar construction, Wi‑Fi credential selection, and deferred exit until revocation completes. |
Review details
- Files reviewed: 26/26 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| #include <cstdint> | ||
| #include <string.h> | ||
|
|
||
| #include <crypto/CHIPCryptoPAL.h> | ||
| #include <lib/asn1/ASN1.h> | ||
| #include <lib/core/CASEAuthTag.h> | ||
| #include <lib/core/CHIPConfig.h> | ||
| #include <lib/core/CHIPEncoding.h> | ||
| #include <lib/core/DataModelTypes.h> |
| * Asynchronous methods do not return a status to their caller: they must invoke their callback | ||
| * exactly once. Completing the callback synchronously, i.e. before returning from the method, is | ||
| * allowed, and is the expected way signal errors that prevent the operation from starting. | ||
| * |
There was a problem hiding this comment.
🔵 Needs a closer look
src/credentials/CHIPCert.h introduces PRIX32 usage in new logging macros without ensuring the required PRI*/PRIX* format macros header is included, which can cause build failures depending on include order/toolchain.
Review details
Suppressed comments (1)
src/credentials/CHIPCert.h:38
ChipLogFormatKeyIdusesPRIX32, but this header does not include a header that guarantees thePRI*/PRIX*format macros are defined. This can break compilation depending on include order/toolchain. Include<inttypes.h>(or<cinttypes>) in this header.
#include <lib/asn1/ASN1.h>
#include <lib/core/CASEAuthTag.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPEncoding.h>
#include <lib/core/DataModelTypes.h>
- Files reviewed: 26/26 changed files
- Comments generated: 0 new
- Review effort level: Lite
| "ExampleOperationalCredentialsIssuer.cpp", | ||
| "NetworkIdentityManagementRegistrar.cpp", | ||
| "NetworkIdentityManagementRegistrar.h", | ||
| "NetworkIdentityRegistrar.h", |
There was a problem hiding this comment.
NetworkIdentityRegistrar.h is already in the unconditional sources list above (with the other header-only entries), so this second copy inside the conditional block is redundant.
| // Nothing was registered, so we owe the registrar no rollback. | ||
| ChipLogFailure(status, Controller, "Failed to register Network Client Identity"); | ||
| commissioner->mNetworkClientRegistration.Clear(); |
There was a problem hiding this comment.
A cancelled registration keeps the rollback obligation, because the AddClient may still have taken effect. A failure that arrives after the command reached the network is the same situation. A lost response or a dropped session leaves an entry on the network with nothing recording it.
RemoveClient already maps NOT_FOUND to success, so revoking either way costs one round trip on an attempt that is failing anyway. How about, removing the clear():
| // Nothing was registered, so we owe the registrar no rollback. | |
| ChipLogFailure(status, Controller, "Failed to register Network Client Identity"); | |
| commissioner->mNetworkClientRegistration.Clear(); | |
| // Note we keep the rollback obligation. A failure that arrives after the command reached | |
| // the network may still have taken effect, in the same way a cancelled one may have. | |
| ChipLogFailure(status, Controller, "Failed to register Network Client Identity"); |
| // If present, kWiFiNetworkSetup will configure the commissionee for PDC using this identity. | ||
| // The AutoCommissioner populates this from the PDCNetworkIdentityInfo report returned | ||
| // by kPDCGetNetworkIdentity, but a CommissioningDelegate is free to obtain the Network Identity | ||
| // in some other way and bypass that step entirely. |
There was a problem hiding this comment.
The spec says clients should check the PDC feature flag before using PDC. A server on cluster revision 2 or below ignores the NetworkIdentity field and configures an open network instead of rejecting the command.
The AutoCommissioner does check the flag. A delegate that supplies the Network Identity itself, as this comment invites, has nothing in kWiFiNetworkSetup to stop it. Is that meant to be the delegate's responsibility?
There was a problem hiding this comment.
I think this is the delegate's job. The DeviceCommissioner just executes the steps it's told to execute, e.g. executing kWiFiNetworkSetup doesn't check that the Network Commissioning cluster on the commissionee actually supports WiFi. I'll add a sentence to that comment.
| void Fail(CHIP_ERROR error) override { Complete(error); } | ||
|
|
||
| uint8_t mClientIdentity[Credentials::kMaxCHIPCompactNetworkIdentityLength]; | ||
| uint8_t mClientIdentityLength = 0; |
There was a problem hiding this comment.
The guard in Start() bounds the identity by sizeof(mClientIdentity), and the length is then narrowed to uint8_t. Nothing couples the two, so a future identity type larger than 255 bytes would pass the guard and truncate silently. The spec anticipates one, in the note under QueryIdentityResponse.
| uint8_t mClientIdentityLength = 0; | |
| uint8_t mClientIdentityLength = 0; | |
| static_assert(Credentials::kMaxCHIPCompactNetworkIdentityLength <= UINT8_MAX); |
| void DeviceCommissioner::ReportUnrevokedNetworkClientIdentity(Credentials::CertificateKeyId clientIdentifier, const char * reason, | ||
| CHIP_ERROR error) | ||
| { | ||
| bool haveError = (error != CHIP_NO_ERROR); |
There was a problem hiding this comment.
| bool haveError = (error != CHIP_NO_ERROR); | |
| [[maybe_unused]] bool haveError = (error != CHIP_NO_ERROR); |
| std::unique_ptr<NetworkIdentityManagementRegistrar> & owner; | ||
| std::optional<CHIP_ERROR> status; | ||
|
|
||
| Callback::Callback<OnClientUnregisteredFunct> callback{ [](void * context, CHIP_ERROR status) { |
There was a problem hiding this comment.
The status param is causing a variable shadowing error with the status above
Summary
PDC commissioning in DeviceCommissioner / AutoCommissioner
Implement support for PDC commissioning steps in the DeviceCommissioner
and AutoCommissioner. The new abstraction introduced to handle the
interaction with the network infrastructure (i.e. with the NETIM cluster
on a NIM device) is the NetworkIdentityRegistrar. The registrar provides
the low-level operations for retrieval of the Network Identity and
registration and unregistration of the Network Client Identity during
commissioning.
The DeviceCommissioner gains two new steps (kPDCGetNetworkIdentity and
kPDCRegisterClientIdentity) that encapsulate those interactions and
handles roll-back of the client identity if commissioning does not
succeed. The kWiFiNetworkSetup step is updated to use the PDC variant of
AddOrUpdateWiFiNetwork as necessary. The commissioner validates that
both the network and client identities are valid, and that the
commissionee holds the private key for the client identity.
Note the two new steps are inserted in the appropriate places in the
enum (kPDCRegisterClientIdentity inside the kWiFiNetworkSetup ..
kICDSendStayActive range, and kPDCGetNetworkIdentity before kCleanup),
so some existing enum values are being renumbered.
Implement NetworkIdentityManagementRegistrar
This class implements the NetworkIdentityRegistrar interface expected by
the DeviceCommissioner by interacting with a Network Identity Management
cluster server (generally on a NIM device).
Implement PDC commissioning support in chip-tool
This adds --pdc-netim-node-id and --pdc-netim-endpoint-id endpoint
arguments to existing WiFi commissioning commands. If they are
specified, a PDC-capable commissionee will be commissioned with PDC
credentials obtained from the pointed-to Network Infrastructure
Management cluster server (generally on a NIM device). If the
commissionee is not PDC-capable, the password parameter will be used as
before. (The special password value of "-", which is not a valid WiFi
password, can be used to disable that fallback.)
Testing
New unit tests for all low-level aspects, particular the AutoCommissioner / DeviceCommissioner aspects.
Manual end-to-end testing with the NIM example app (still requires some manual intervention on the AP side due to integration code that is still missing.)