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