matc/clusters/codec/
operational_credential_cluster.rs

1//! Generated Matter TLV encoders and decoders for Operational Credentials Cluster
2//! Cluster ID: 0x003E
3//! 
4//! This file is automatically generated from OperationalCredentialCluster.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct FabricDescriptor {
15    pub root_public_key: Option<Vec<u8>>,
16    pub vendor_id: Option<u16>,
17    pub fabric_id: Option<u8>,
18    pub node_id: Option<u64>,
19    pub label: Option<String>,
20    pub vid_verification_statement: Option<Vec<u8>>,
21}
22
23#[derive(Debug, serde::Serialize)]
24pub struct NOC {
25    pub noc: Option<Vec<u8>>,
26    pub icac: Option<Vec<u8>>,
27    pub vvsc: Option<Vec<u8>>,
28}
29
30// Command encoders
31
32/// Encode AttestationRequest command (0x00)
33pub fn encode_attestation_request(attestation_nonce: Vec<u8>) -> anyhow::Result<Vec<u8>> {
34    let tlv = tlv::TlvItemEnc {
35        tag: 0,
36        value: tlv::TlvItemValueEnc::StructInvisible(vec![
37        (0, tlv::TlvItemValueEnc::OctetString(attestation_nonce)).into(),
38        ]),
39    };
40    Ok(tlv.encode()?)
41}
42
43/// Encode CertificateChainRequest command (0x02)
44pub fn encode_certificate_chain_request(certificate_type: u8) -> anyhow::Result<Vec<u8>> {
45    let tlv = tlv::TlvItemEnc {
46        tag: 0,
47        value: tlv::TlvItemValueEnc::StructInvisible(vec![
48        (0, tlv::TlvItemValueEnc::UInt8(certificate_type)).into(),
49        ]),
50    };
51    Ok(tlv.encode()?)
52}
53
54/// Encode CSRRequest command (0x04)
55pub fn encode_csr_request(csr_nonce: Vec<u8>, is_for_update_noc: bool) -> anyhow::Result<Vec<u8>> {
56    let tlv = tlv::TlvItemEnc {
57        tag: 0,
58        value: tlv::TlvItemValueEnc::StructInvisible(vec![
59        (0, tlv::TlvItemValueEnc::OctetString(csr_nonce)).into(),
60        (1, tlv::TlvItemValueEnc::Bool(is_for_update_noc)).into(),
61        ]),
62    };
63    Ok(tlv.encode()?)
64}
65
66/// Encode AddNOC command (0x06)
67pub fn encode_add_noc(noc_value: Vec<u8>, icac_value: Vec<u8>, ipk_value: Vec<u8>, case_admin_subject: u64, admin_vendor_id: u16) -> anyhow::Result<Vec<u8>> {
68    let tlv = tlv::TlvItemEnc {
69        tag: 0,
70        value: tlv::TlvItemValueEnc::StructInvisible(vec![
71        (0, tlv::TlvItemValueEnc::OctetString(noc_value)).into(),
72        (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
73        (2, tlv::TlvItemValueEnc::OctetString(ipk_value)).into(),
74        (3, tlv::TlvItemValueEnc::UInt64(case_admin_subject)).into(),
75        (4, tlv::TlvItemValueEnc::UInt16(admin_vendor_id)).into(),
76        ]),
77    };
78    Ok(tlv.encode()?)
79}
80
81/// Encode UpdateNOC command (0x07)
82pub fn encode_update_noc(noc_value: Vec<u8>, icac_value: Vec<u8>) -> anyhow::Result<Vec<u8>> {
83    let tlv = tlv::TlvItemEnc {
84        tag: 0,
85        value: tlv::TlvItemValueEnc::StructInvisible(vec![
86        (0, tlv::TlvItemValueEnc::OctetString(noc_value)).into(),
87        (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
88        ]),
89    };
90    Ok(tlv.encode()?)
91}
92
93/// Encode UpdateFabricLabel command (0x09)
94pub fn encode_update_fabric_label(label: String) -> anyhow::Result<Vec<u8>> {
95    let tlv = tlv::TlvItemEnc {
96        tag: 0,
97        value: tlv::TlvItemValueEnc::StructInvisible(vec![
98        (0, tlv::TlvItemValueEnc::String(label)).into(),
99        ]),
100    };
101    Ok(tlv.encode()?)
102}
103
104/// Encode RemoveFabric command (0x0A)
105pub fn encode_remove_fabric(fabric_index: u8) -> anyhow::Result<Vec<u8>> {
106    let tlv = tlv::TlvItemEnc {
107        tag: 0,
108        value: tlv::TlvItemValueEnc::StructInvisible(vec![
109        (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
110        ]),
111    };
112    Ok(tlv.encode()?)
113}
114
115/// Encode AddTrustedRootCertificate command (0x0B)
116pub fn encode_add_trusted_root_certificate(root_ca_certificate: Vec<u8>) -> anyhow::Result<Vec<u8>> {
117    let tlv = tlv::TlvItemEnc {
118        tag: 0,
119        value: tlv::TlvItemValueEnc::StructInvisible(vec![
120        (0, tlv::TlvItemValueEnc::OctetString(root_ca_certificate)).into(),
121        ]),
122    };
123    Ok(tlv.encode()?)
124}
125
126/// Encode SetVIDVerificationStatement command (0x0C)
127pub fn encode_set_vid_verification_statement(vendor_id: u16, vid_verification_statement: Vec<u8>, vvsc: Vec<u8>) -> anyhow::Result<Vec<u8>> {
128    let tlv = tlv::TlvItemEnc {
129        tag: 0,
130        value: tlv::TlvItemValueEnc::StructInvisible(vec![
131        (0, tlv::TlvItemValueEnc::UInt16(vendor_id)).into(),
132        (1, tlv::TlvItemValueEnc::OctetString(vid_verification_statement)).into(),
133        (2, tlv::TlvItemValueEnc::OctetString(vvsc)).into(),
134        ]),
135    };
136    Ok(tlv.encode()?)
137}
138
139/// Encode SignVIDVerificationRequest command (0x0D)
140pub fn encode_sign_vid_verification_request(fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<Vec<u8>> {
141    let tlv = tlv::TlvItemEnc {
142        tag: 0,
143        value: tlv::TlvItemValueEnc::StructInvisible(vec![
144        (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
145        (1, tlv::TlvItemValueEnc::OctetString(client_challenge)).into(),
146        ]),
147    };
148    Ok(tlv.encode()?)
149}
150
151// Attribute decoders
152
153/// Decode NOCs attribute (0x0000)
154pub fn decode_no_cs(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NOC>> {
155    let mut res = Vec::new();
156    if let tlv::TlvItemValue::List(v) = inp {
157        for item in v {
158            res.push(NOC {
159                noc: item.get_octet_string_owned(&[1]),
160                icac: item.get_octet_string_owned(&[2]),
161                vvsc: item.get_octet_string_owned(&[3]),
162            });
163        }
164    }
165    Ok(res)
166}
167
168/// Decode Fabrics attribute (0x0001)
169pub fn decode_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<FabricDescriptor>> {
170    let mut res = Vec::new();
171    if let tlv::TlvItemValue::List(v) = inp {
172        for item in v {
173            res.push(FabricDescriptor {
174                root_public_key: item.get_octet_string_owned(&[1]),
175                vendor_id: item.get_int(&[2]).map(|v| v as u16),
176                fabric_id: item.get_int(&[3]).map(|v| v as u8),
177                node_id: item.get_int(&[4]),
178                label: item.get_string_owned(&[5]),
179                vid_verification_statement: item.get_octet_string_owned(&[6]),
180            });
181        }
182    }
183    Ok(res)
184}
185
186/// Decode SupportedFabrics attribute (0x0002)
187pub fn decode_supported_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
188    if let tlv::TlvItemValue::Int(v) = inp {
189        Ok(*v as u8)
190    } else {
191        Err(anyhow::anyhow!("Expected Integer"))
192    }
193}
194
195/// Decode CommissionedFabrics attribute (0x0003)
196pub fn decode_commissioned_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
197    if let tlv::TlvItemValue::Int(v) = inp {
198        Ok(*v as u8)
199    } else {
200        Err(anyhow::anyhow!("Expected Integer"))
201    }
202}
203
204/// Decode TrustedRootCertificates attribute (0x0004)
205pub fn decode_trusted_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
206    let mut res = Vec::new();
207    if let tlv::TlvItemValue::List(v) = inp {
208        for item in v {
209            if let tlv::TlvItemValue::OctetString(o) = &item.value {
210                res.push(o.clone());
211            }
212        }
213    }
214    Ok(res)
215}
216
217/// Decode CurrentFabricIndex attribute (0x0005)
218pub fn decode_current_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
219    if let tlv::TlvItemValue::Int(v) = inp {
220        Ok(*v as u8)
221    } else {
222        Err(anyhow::anyhow!("Expected Integer"))
223    }
224}
225
226
227// JSON dispatcher function
228
229/// Decode attribute value and return as JSON string
230/// 
231/// # Parameters
232/// * `cluster_id` - The cluster identifier
233/// * `attribute_id` - The attribute identifier
234/// * `tlv_value` - The TLV value to decode
235/// 
236/// # Returns
237/// JSON string representation of the decoded value or error
238pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
239    // Verify this is the correct cluster
240    if cluster_id != 0x003E {
241        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003E, got {}\"}}", cluster_id);
242    }
243    
244    match attribute_id {
245        0x0000 => {
246            match decode_no_cs(tlv_value) {
247                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
248                Err(e) => format!("{{\"error\": \"{}\"}}", e),
249            }
250        }
251        0x0001 => {
252            match decode_fabrics(tlv_value) {
253                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
254                Err(e) => format!("{{\"error\": \"{}\"}}", e),
255            }
256        }
257        0x0002 => {
258            match decode_supported_fabrics(tlv_value) {
259                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
260                Err(e) => format!("{{\"error\": \"{}\"}}", e),
261            }
262        }
263        0x0003 => {
264            match decode_commissioned_fabrics(tlv_value) {
265                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
266                Err(e) => format!("{{\"error\": \"{}\"}}", e),
267            }
268        }
269        0x0004 => {
270            match decode_trusted_root_certificates(tlv_value) {
271                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
272                Err(e) => format!("{{\"error\": \"{}\"}}", e),
273            }
274        }
275        0x0005 => {
276            match decode_current_fabric_index(tlv_value) {
277                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
278                Err(e) => format!("{{\"error\": \"{}\"}}", e),
279            }
280        }
281        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
282    }
283}
284
285/// Get list of all attributes supported by this cluster
286/// 
287/// # Returns
288/// Vector of tuples containing (attribute_id, attribute_name)
289pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
290    vec![
291        (0x0000, "NOCs"),
292        (0x0001, "Fabrics"),
293        (0x0002, "SupportedFabrics"),
294        (0x0003, "CommissionedFabrics"),
295        (0x0004, "TrustedRootCertificates"),
296        (0x0005, "CurrentFabricIndex"),
297    ]
298}
299