1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use anyhow::{Context, Result};
4
5use crate::{fabric, sigma, spake2p, tlv};
6
7#[derive(Clone)]
8pub struct DeviceConfig {
9 pub pin: u32,
10 pub discriminator: u16,
11 pub listen_address: String,
12 pub vendor_id: u16,
13 pub product_id: u16,
14 pub dac_cert_path: String,
15 pub pai_cert_path: String,
16 pub dac_key_path: String,
17 pub hostname: String,
18 pub state_dir: Option<String>,
20 pub vendor_name: String,
21 pub product_name: String,
22 pub hardware_version: u16,
23 pub software_version: u32,
24 pub serial_number: String,
25 pub unique_id: String,
26 pub advertise_addresses: Option<Vec<std::net::IpAddr>>,
30}
31
32impl DeviceConfig {
33 pub fn split_advertise_ips(&self) -> (Option<Vec<Ipv4Addr>>, Option<Vec<Ipv6Addr>>) {
36 match &self.advertise_addresses {
37 None => (None, None),
38 Some(addrs) => {
39 let v4: Vec<Ipv4Addr> = addrs.iter().filter_map(|a| match a {
40 std::net::IpAddr::V4(ip) => Some(*ip),
41 _ => None,
42 }).collect();
43 let v6: Vec<Ipv6Addr> = addrs.iter().filter_map(|a| match a {
44 std::net::IpAddr::V6(ip) => Some(*ip),
45 _ => None,
46 }).collect();
47 (Some(v4), Some(v6))
48 }
49 }
50 }
51}
52
53mod hex_bytes {
55 use serde::{Deserialize, Deserializer, Serializer};
56
57 pub fn serialize<S: Serializer>(bytes: &[u8], s: S) -> Result<S::Ok, S::Error> {
58 s.serialize_str(&hex::encode(bytes))
59 }
60
61 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<u8>, D::Error> {
62 let s = String::deserialize(d)?;
63 hex::decode(&s).map_err(serde::de::Error::custom)
64 }
65}
66
67mod hex_bytes_opt {
69 use serde::{Deserialize, Deserializer, Serializer};
70
71 pub fn serialize<S: Serializer>(bytes: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error> {
72 match bytes {
73 Some(b) => s.serialize_some(&hex::encode(b)),
74 None => s.serialize_none(),
75 }
76 }
77
78 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Vec<u8>>, D::Error> {
79 let opt: Option<String> = Option::deserialize(d)?;
80 opt.map(|s| hex::decode(&s).map_err(serde::de::Error::custom))
81 .transpose()
82 }
83}
84
85#[derive(serde::Serialize, serde::Deserialize)]
87pub struct PersistedFabricState {
88 pub fabric_index: u8,
89 #[serde(with = "hex_bytes")]
90 pub trusted_root_cert: Vec<u8>,
91 #[serde(with = "hex_bytes")]
92 pub noc: Vec<u8>,
93 #[serde(with = "hex_bytes_opt")]
94 pub icac: Option<Vec<u8>>,
95 #[serde(with = "hex_bytes")]
96 pub ipk: Vec<u8>,
97 pub controller_id: u64,
98 pub vendor_id: u16,
99 #[serde(with = "hex_bytes")]
100 pub device_matter_cert: Vec<u8>,
101 pub label: String,
102}
103
104#[derive(serde::Serialize, serde::Deserialize)]
106pub struct PersistedDeviceState {
107 pub operational_key_hex: String,
108 pub next_fabric_index: u8,
109 pub fabrics: Vec<PersistedFabricState>,
110 pub attribute_overrides: Vec<AttributeOverride>,
111}
112
113#[derive(serde::Serialize, serde::Deserialize)]
115pub struct AttributeOverride {
116 pub endpoint: u16,
117 pub cluster: u32,
118 pub attribute: u32,
119 pub tlv_hex: String,
120}
121
122pub(crate) struct PaseState {
123 pub(crate) engine: spake2p::Engine,
124 pub(crate) verifier: spake2p::Verifier,
125 #[allow(dead_code)]
126 pub(crate) exchange_id: u16,
127 pub(crate) pbkdf_req_payload: Vec<u8>,
128 pub(crate) pbkdf_resp_payload: Vec<u8>,
129 pub(crate) responder_session_id: u16,
130 pub(crate) initiator_session_id: u16,
131}
132
133pub(crate) struct CaseState {
134 pub(crate) sigma2_ctx: sigma::Sigma2ResponseCtx,
135 #[allow(dead_code)]
136 pub(crate) exchange_id: u16,
137 pub(crate) fabric_index: u8,
139}
140
141#[derive(Clone)]
143pub(crate) enum SubscribedPaths {
144 All,
146 Specific(Vec<(u16, u32, u32)>),
148}
149
150pub(crate) struct SubscribeState {
151 pub(crate) exchange_id: u16,
152 pub(crate) subscription_id: u32,
153 pub(crate) paths: SubscribedPaths,
154 pub(crate) max_interval_secs: u16,
155}
156
157pub(crate) struct ActiveSubscription {
158 pub(crate) subscription_id: u32,
159 pub(crate) session_id: u16,
160 pub(crate) peer_addr: std::net::SocketAddr,
161 pub(crate) max_interval_secs: u16,
162 pub(crate) paths: SubscribedPaths,
163}
164
165pub(crate) struct PendingChunkState {
166 pub(crate) exchange_id: u16,
167 pub(crate) remaining: Vec<crate::device_messages::AttrReport>,
169 pub(crate) subscription_id: Option<u32>,
170}
171
172pub(crate) struct FabricInfo {
173 pub(crate) fabric_index: u8,
175 pub(crate) ipk: Vec<u8>,
176 pub(crate) fabric: Option<fabric::Fabric>,
177 pub(crate) device_matter_cert: Vec<u8>,
178 pub(crate) controller_id: u64,
179 pub(crate) vendor_id: u16,
180 pub(crate) trusted_root_cert: Vec<u8>,
182 pub(crate) noc: Vec<u8>,
184 pub(crate) icac: Option<Vec<u8>>,
186 pub(crate) label: String,
187}
188
189impl FabricInfo {
190 pub(crate) fn ca_public_key(&self) -> Result<Vec<u8>> {
192 let decoded = tlv::decode_tlv(&self.trusted_root_cert)?;
193 let pubkey = decoded
194 .get_octet_string(&[9])
195 .context("CA cert: public key (tag 9) missing")?;
196 Ok(pubkey.to_vec())
197 }
198
199 fn noc_field(&self, tag_path: &[u8], field_name: &str) -> Result<u64> {
200 let decoded = tlv::decode_tlv(&self.noc)?;
201 decoded
202 .get_int(tag_path)
203 .with_context(|| format!("NOC: {} missing from subject", field_name))
204 }
205
206 pub(crate) fn fabric_id(&self) -> Result<u64> {
207 self.noc_field(&[6u8, 21], "fabric_id")
208 }
209
210 pub(crate) fn device_node_id(&self) -> Result<u64> {
211 self.noc_field(&[6u8, 17], "node_id")
212 }
213
214 pub(crate) fn ca_id(&self) -> Result<u64> {
215 let decoded = tlv::decode_tlv(&self.trusted_root_cert)?;
216 decoded
217 .get_int(&[6, 20])
218 .context("CA cert: ca_id missing from subject")
219 }
220}