Skip to main content

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;