matter_commissioning/lib.rs
1//! Matter commissioning: setup payloads, device attestation, NOC issuance,
2//! network commissioning, and the state machine that sequences them.
3//!
4//! The commissioning flow here has been driven against real Matter hardware —
5//! over IP and over BLE, onto Wi-Fi and onto Thread.
6//!
7//! If you want a complete controller — commissioning plus reading, writing,
8//! invoking, and subscribing — use [`matter-controller`], which is built on
9//! this crate. Reach for `matter-commissioning` directly when you want the
10//! commissioning pieces on their own, or want to drive the state machine from
11//! your own IO layer.
12//!
13//! [`matter-controller`]: https://crates.io/crates/matter-controller
14//!
15//! ## What's here
16//!
17//! - [`setup`] — QR and manual pairing codes, decode and encode.
18//! - [`attestation`] — typed [`Dac`] / [`Pai`] / [`Paa`] wrappers,
19//! chain validation against a [`PaaTrustStore`] via [`verify_chain`]
20//! (`rustls-webpki` path validation plus a Matter VID/PID overlay),
21//! [`verify_attestation_response`] for the device's signed attestation, and
22//! CSA Certification Declaration (CMS) verification against
23//! [`CdSigningRoots`].
24//! - [`noc`] — Node Operational Certificate issuance: [`FabricRecord`],
25//! CSR verification, RCAC/NOC minting, and the `OperationalCredentials`
26//! command codecs.
27//! - [`state_machine`] — a sans-IO cursor over the whole flow, from
28//! `Stage::SecurePairing` through `Action::Done(CommissionedFabric)`:
29//! attestation, CSR and NOC installation, the network-commissioning
30//! subgraph, and the PASE→CASE handoff. It emits [`Action`]s and consumes
31//! responses; it performs no IO of its own.
32//! - [`clusters`] and [`thread_dataset`] — the `GeneralCommissioning` and
33//! `NetworkCommissioning` command codecs, and Thread Operational Dataset
34//! parsing.
35//! - [`im`] — Interaction Model framing, re-exported from
36//! [`matter_interaction`].
37//! - `driver` (behind the off-by-default `driver` feature) — the async Tokio
38//! IO layer that runs the state machine for real: PASE, mDNS discovery,
39//! CASE, and the Invoke/Read round-trips in between.
40//!
41//! Network commissioning covers Wi-Fi and Thread; a device already on its
42//! operational network (Ethernet, or Wi-Fi it has already joined) skips the
43//! network sub-cursor entirely. A device whose `NetworkCommissioning` feature
44//! map does not match the credentials you supplied fails fast with a typed
45//! `NetworkFeatureUnsupported` error, and [`RemediationHint`] categorises
46//! `NetworkRejected` failures into actionable causes.
47//!
48//! ## Quick-start: parse a setup payload
49//!
50//! ```
51//! use matter_commissioning::setup::{parse_qr, parse_manual_code};
52//! # fn run() -> Result<(), matter_commissioning::setup::Error> {
53//! let from_qr = parse_qr("MT:Y.K90AFN00KA0648G00")?;
54//! let from_manual = parse_manual_code("11693312331")?;
55//! assert_eq!(from_qr.vendor_id, Some(0xFFF1));
56//! assert_eq!(from_manual.passcode.as_u32(), 20_202_021);
57//! # Ok(())
58//! # }
59//! # let _ = run;
60//! ```
61//!
62//! Those are the spec's example codes; substitute the ones printed on your
63//! own device.
64//!
65//! ## Optional `tracing` feature
66//!
67//! Enable the `tracing` crate feature to get per-method spans on
68//! `Commissioner::poll`, `Commissioner::on_response`, and
69//! `Commissioner::on_case_established`. Span fields (`stage`,
70//! `expectation`) align best-effort with matter.js's log-event format
71//! so operators can grep across both implementations. Compatibility
72//! is not guaranteed across matter.js minor versions.
73
74#![forbid(unsafe_code)]
75
76pub mod attestation;
77pub mod clusters;
78#[cfg(feature = "driver")]
79pub mod driver;
80pub mod error;
81/// Lowercase-hex rendering for `tracing` debug dumps of wire bytes.
82#[cfg(feature = "tracing")]
83pub(crate) mod hexdump {
84 use std::fmt::Write;
85
86 /// Render `bytes` as a contiguous lowercase-hex string.
87 pub(crate) fn hex(bytes: &[u8]) -> String {
88 bytes
89 .iter()
90 .fold(String::with_capacity(bytes.len() * 2), |mut out, b| {
91 // Vec-backed String writes are infallible.
92 let _ = write!(out, "{b:02x}");
93 out
94 })
95 }
96}
97/// Interaction Model message framing — re-exported from [`matter_interaction`],
98/// which this crate used to host. All `im::` paths still resolve.
99pub use matter_interaction as im;
100pub mod noc;
101pub mod setup;
102pub mod state_machine;
103#[cfg(feature = "test-support")]
104pub mod test_support;
105pub mod thread_dataset;
106#[cfg(feature = "wiretrace")]
107pub mod wiretrace;
108
109pub use setup::{
110 encode_manual_code, encode_qr, parse_manual_code, parse_qr, CommissioningFlow,
111 DiscoveryCapabilities, Discriminator, Error as SetupError, Passcode, SetupPayload,
112};
113
114pub use attestation::{
115 extract_attestation_elements_fields, verify_attestation_response,
116 verify_certification_declaration, verify_certification_declaration_with_paa, verify_chain,
117 verify_dac_signed_elements, AttestationElementsFields, AttestationError, AttestationResponse,
118 CdSigningRoots, ChainVerification, Dac, Paa, PaaTrustStore, Pai, ProductId, VendorId,
119};
120
121pub use noc::{
122 decode_attestation_response, decode_certificate_chain_response, decode_csr_response,
123 decode_noc_response, encode_add_noc, encode_add_trusted_root, encode_attestation_request,
124 encode_certificate_chain_request, encode_csr_request, encode_update_noc, issue_icac, issue_noc,
125 parse_and_verify_csr, parse_nocsr, verify_csr_response, CertChainType,
126 CertificateChainResponse, CsrResponse, FabricRecord, NocError, NocResponse, NocRng,
127 NocsrElements, ParsedCsr, SystemNocRng, VerifiedCsr,
128};
129
130pub use clusters::network_commissioning::{
131 decode_connect_network_response, decode_feature_map, decode_network_config_response,
132 encode_add_or_update_wifi_network, encode_connect_network, remediation_for,
133 ConnectNetworkResponse, NetworkCommissioningFeature, NetworkConfigResponse,
134};
135
136pub use im::{
137 build_invoke_request, build_read_request, parse_invoke_response, parse_report_data,
138 AttributePath, CommandPath, ImError, ImStatus, InvokeResponse, ReportData, IM_REVISION,
139};
140
141#[cfg(feature = "__test_shortcuts")]
142pub use state_machine::TestStateSeeds;
143pub use state_machine::{
144 Action, CommissionedFabric, Commissioner, CommissionerConfig, CommissioningError, Expectation,
145 NetworkCredentials, NetworkKind, RemediationHint, SessionContext, Stage, WiFiCredentials,
146};
147
148pub use thread_dataset::{ThreadDataset, ThreadDatasetError};
149
150/// Compile-checks the Rust examples in this crate's `README.md`.
151///
152/// `#[cfg(doctest)]` means the item exists only while rustdoc is collecting
153/// doctests, so the README is compiled by `cargo test --doc` without being
154/// duplicated into the rendered crate docs.
155#[cfg(doctest)]
156#[doc = include_str!("../README.md")]
157struct ReadmeDoctests;