matc/clusters/codec/
tls_certificate_management.rs

1//! Matter TLV encoders and decoders for TLS Certificate Management Cluster
2//! Cluster ID: 0x0801
3//!
4//! This file is automatically generated from TLSCertificateManagement.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex, serialize_opt_vec_bytes_as_hex};
15
16// Struct definitions
17
18#[derive(Debug, serde::Serialize)]
19pub struct TLSCert {
20    pub caid: Option<u8>,
21    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
22    pub certificate: Option<Vec<u8>>,
23}
24
25#[derive(Debug, serde::Serialize)]
26pub struct TLSClientCertificateDetail {
27    pub ccdid: Option<u8>,
28    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
29    pub client_certificate: Option<Vec<u8>>,
30    #[serde(serialize_with = "serialize_opt_vec_bytes_as_hex")]
31    pub intermediate_certificates: Option<Vec<Vec<u8>>>,
32}
33
34// Command encoders
35
36/// Encode ProvisionRootCertificate command (0x00)
37pub fn encode_provision_root_certificate(certificate: Vec<u8>, caid: Option<u8>) -> anyhow::Result<Vec<u8>> {
38    let tlv = tlv::TlvItemEnc {
39        tag: 0,
40        value: tlv::TlvItemValueEnc::StructInvisible(vec![
41        (0, tlv::TlvItemValueEnc::OctetString(certificate)).into(),
42        (1, tlv::TlvItemValueEnc::UInt8(caid.unwrap_or(0))).into(),
43        ]),
44    };
45    Ok(tlv.encode()?)
46}
47
48/// Encode FindRootCertificate command (0x02)
49pub fn encode_find_root_certificate(caid: Option<u8>) -> anyhow::Result<Vec<u8>> {
50    let tlv = tlv::TlvItemEnc {
51        tag: 0,
52        value: tlv::TlvItemValueEnc::StructInvisible(vec![
53        (0, tlv::TlvItemValueEnc::UInt8(caid.unwrap_or(0))).into(),
54        ]),
55    };
56    Ok(tlv.encode()?)
57}
58
59/// Encode LookupRootCertificate command (0x04)
60pub fn encode_lookup_root_certificate(fingerprint: Vec<u8>) -> anyhow::Result<Vec<u8>> {
61    let tlv = tlv::TlvItemEnc {
62        tag: 0,
63        value: tlv::TlvItemValueEnc::StructInvisible(vec![
64        (0, tlv::TlvItemValueEnc::OctetString(fingerprint)).into(),
65        ]),
66    };
67    Ok(tlv.encode()?)
68}
69
70/// Encode RemoveRootCertificate command (0x06)
71pub fn encode_remove_root_certificate(caid: u8) -> anyhow::Result<Vec<u8>> {
72    let tlv = tlv::TlvItemEnc {
73        tag: 0,
74        value: tlv::TlvItemValueEnc::StructInvisible(vec![
75        (0, tlv::TlvItemValueEnc::UInt8(caid)).into(),
76        ]),
77    };
78    Ok(tlv.encode()?)
79}
80
81/// Encode ClientCSR command (0x07)
82pub fn encode_client_csr(nonce: Vec<u8>, ccdid: Option<u8>) -> anyhow::Result<Vec<u8>> {
83    let tlv = tlv::TlvItemEnc {
84        tag: 0,
85        value: tlv::TlvItemValueEnc::StructInvisible(vec![
86        (0, tlv::TlvItemValueEnc::OctetString(nonce)).into(),
87        (1, tlv::TlvItemValueEnc::UInt8(ccdid.unwrap_or(0))).into(),
88        ]),
89    };
90    Ok(tlv.encode()?)
91}
92
93/// Encode ProvisionClientCertificate command (0x09)
94pub fn encode_provision_client_certificate(ccdid: u8, client_certificate: Vec<u8>, intermediate_certificates: Vec<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
95    let tlv = tlv::TlvItemEnc {
96        tag: 0,
97        value: tlv::TlvItemValueEnc::StructInvisible(vec![
98        (0, tlv::TlvItemValueEnc::UInt8(ccdid)).into(),
99        (1, tlv::TlvItemValueEnc::OctetString(client_certificate)).into(),
100        (2, tlv::TlvItemValueEnc::StructAnon(intermediate_certificates.into_iter().map(|v| (0, tlv::TlvItemValueEnc::OctetString(v)).into()).collect())).into(),
101        ]),
102    };
103    Ok(tlv.encode()?)
104}
105
106/// Encode FindClientCertificate command (0x0A)
107pub fn encode_find_client_certificate(ccdid: Option<u8>) -> anyhow::Result<Vec<u8>> {
108    let tlv = tlv::TlvItemEnc {
109        tag: 0,
110        value: tlv::TlvItemValueEnc::StructInvisible(vec![
111        (0, tlv::TlvItemValueEnc::UInt8(ccdid.unwrap_or(0))).into(),
112        ]),
113    };
114    Ok(tlv.encode()?)
115}
116
117/// Encode LookupClientCertificate command (0x0C)
118pub fn encode_lookup_client_certificate(fingerprint: Vec<u8>) -> anyhow::Result<Vec<u8>> {
119    let tlv = tlv::TlvItemEnc {
120        tag: 0,
121        value: tlv::TlvItemValueEnc::StructInvisible(vec![
122        (0, tlv::TlvItemValueEnc::OctetString(fingerprint)).into(),
123        ]),
124    };
125    Ok(tlv.encode()?)
126}
127
128/// Encode RemoveClientCertificate command (0x0E)
129pub fn encode_remove_client_certificate(ccdid: u8) -> anyhow::Result<Vec<u8>> {
130    let tlv = tlv::TlvItemEnc {
131        tag: 0,
132        value: tlv::TlvItemValueEnc::StructInvisible(vec![
133        (0, tlv::TlvItemValueEnc::UInt8(ccdid)).into(),
134        ]),
135    };
136    Ok(tlv.encode()?)
137}
138
139// Attribute decoders
140
141/// Decode MaxRootCertificates attribute (0x0000)
142pub fn decode_max_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
143    if let tlv::TlvItemValue::Int(v) = inp {
144        Ok(*v as u8)
145    } else {
146        Err(anyhow::anyhow!("Expected UInt8"))
147    }
148}
149
150/// Decode ProvisionedRootCertificates attribute (0x0001)
151pub fn decode_provisioned_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TLSCert>> {
152    let mut res = Vec::new();
153    if let tlv::TlvItemValue::List(v) = inp {
154        for item in v {
155            res.push(TLSCert {
156                caid: item.get_int(&[0]).map(|v| v as u8),
157                certificate: item.get_octet_string_owned(&[1]),
158            });
159        }
160    }
161    Ok(res)
162}
163
164/// Decode MaxClientCertificates attribute (0x0002)
165pub fn decode_max_client_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
166    if let tlv::TlvItemValue::Int(v) = inp {
167        Ok(*v as u8)
168    } else {
169        Err(anyhow::anyhow!("Expected UInt8"))
170    }
171}
172
173/// Decode ProvisionedClientCertificates attribute (0x0003)
174pub fn decode_provisioned_client_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TLSClientCertificateDetail>> {
175    let mut res = Vec::new();
176    if let tlv::TlvItemValue::List(v) = inp {
177        for item in v {
178            res.push(TLSClientCertificateDetail {
179                ccdid: item.get_int(&[0]).map(|v| v as u8),
180                client_certificate: item.get_octet_string_owned(&[1]),
181                intermediate_certificates: {
182                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
183                        let items: Vec<Vec<u8>> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::OctetString(v) = &e.value { Some(v.clone()) } else { None } }).collect();
184                        Some(items)
185                    } else {
186                        None
187                    }
188                },
189            });
190        }
191    }
192    Ok(res)
193}
194
195
196// JSON dispatcher function
197
198/// Decode attribute value and return as JSON string
199///
200/// # Parameters
201/// * `cluster_id` - The cluster identifier
202/// * `attribute_id` - The attribute identifier
203/// * `tlv_value` - The TLV value to decode
204///
205/// # Returns
206/// JSON string representation of the decoded value or error
207pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
208    // Verify this is the correct cluster
209    if cluster_id != 0x0801 {
210        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0801, got {}\"}}", cluster_id);
211    }
212
213    match attribute_id {
214        0x0000 => {
215            match decode_max_root_certificates(tlv_value) {
216                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
217                Err(e) => format!("{{\"error\": \"{}\"}}", e),
218            }
219        }
220        0x0001 => {
221            match decode_provisioned_root_certificates(tlv_value) {
222                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
223                Err(e) => format!("{{\"error\": \"{}\"}}", e),
224            }
225        }
226        0x0002 => {
227            match decode_max_client_certificates(tlv_value) {
228                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
229                Err(e) => format!("{{\"error\": \"{}\"}}", e),
230            }
231        }
232        0x0003 => {
233            match decode_provisioned_client_certificates(tlv_value) {
234                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
235                Err(e) => format!("{{\"error\": \"{}\"}}", e),
236            }
237        }
238        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
239    }
240}
241
242/// Get list of all attributes supported by this cluster
243///
244/// # Returns
245/// Vector of tuples containing (attribute_id, attribute_name)
246pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
247    vec![
248        (0x0000, "MaxRootCertificates"),
249        (0x0001, "ProvisionedRootCertificates"),
250        (0x0002, "MaxClientCertificates"),
251        (0x0003, "ProvisionedClientCertificates"),
252    ]
253}
254
255// Command listing
256
257pub fn get_command_list() -> Vec<(u32, &'static str)> {
258    vec![
259        (0x00, "ProvisionRootCertificate"),
260        (0x02, "FindRootCertificate"),
261        (0x04, "LookupRootCertificate"),
262        (0x06, "RemoveRootCertificate"),
263        (0x07, "ClientCSR"),
264        (0x09, "ProvisionClientCertificate"),
265        (0x0A, "FindClientCertificate"),
266        (0x0C, "LookupClientCertificate"),
267        (0x0E, "RemoveClientCertificate"),
268    ]
269}
270
271pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
272    match cmd_id {
273        0x00 => Some("ProvisionRootCertificate"),
274        0x02 => Some("FindRootCertificate"),
275        0x04 => Some("LookupRootCertificate"),
276        0x06 => Some("RemoveRootCertificate"),
277        0x07 => Some("ClientCSR"),
278        0x09 => Some("ProvisionClientCertificate"),
279        0x0A => Some("FindClientCertificate"),
280        0x0C => Some("LookupClientCertificate"),
281        0x0E => Some("RemoveClientCertificate"),
282        _ => None,
283    }
284}
285
286pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
287    match cmd_id {
288        0x00 => Some(vec![
289            crate::clusters::codec::CommandField { tag: 0, name: "certificate", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
290            crate::clusters::codec::CommandField { tag: 1, name: "caid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
291        ]),
292        0x02 => Some(vec![
293            crate::clusters::codec::CommandField { tag: 0, name: "caid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
294        ]),
295        0x04 => Some(vec![
296            crate::clusters::codec::CommandField { tag: 0, name: "fingerprint", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
297        ]),
298        0x06 => Some(vec![
299            crate::clusters::codec::CommandField { tag: 0, name: "caid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
300        ]),
301        0x07 => Some(vec![
302            crate::clusters::codec::CommandField { tag: 0, name: "nonce", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
303            crate::clusters::codec::CommandField { tag: 1, name: "ccdid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
304        ]),
305        0x09 => Some(vec![
306            crate::clusters::codec::CommandField { tag: 0, name: "ccdid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
307            crate::clusters::codec::CommandField { tag: 1, name: "client_certificate", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
308            crate::clusters::codec::CommandField { tag: 2, name: "intermediate_certificates", kind: crate::clusters::codec::FieldKind::List { entry_type: "octstr" }, optional: false, nullable: false },
309        ]),
310        0x0A => Some(vec![
311            crate::clusters::codec::CommandField { tag: 0, name: "ccdid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: true },
312        ]),
313        0x0C => Some(vec![
314            crate::clusters::codec::CommandField { tag: 0, name: "fingerprint", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
315        ]),
316        0x0E => Some(vec![
317            crate::clusters::codec::CommandField { tag: 0, name: "ccdid", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
318        ]),
319        _ => None,
320    }
321}
322
323pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
324    match cmd_id {
325        0x00 => {
326        let certificate = crate::clusters::codec::json_util::get_octstr(args, "certificate")?;
327        let caid = crate::clusters::codec::json_util::get_opt_u8(args, "caid")?;
328        encode_provision_root_certificate(certificate, caid)
329        }
330        0x02 => {
331        let caid = crate::clusters::codec::json_util::get_opt_u8(args, "caid")?;
332        encode_find_root_certificate(caid)
333        }
334        0x04 => {
335        let fingerprint = crate::clusters::codec::json_util::get_octstr(args, "fingerprint")?;
336        encode_lookup_root_certificate(fingerprint)
337        }
338        0x06 => {
339        let caid = crate::clusters::codec::json_util::get_u8(args, "caid")?;
340        encode_remove_root_certificate(caid)
341        }
342        0x07 => {
343        let nonce = crate::clusters::codec::json_util::get_octstr(args, "nonce")?;
344        let ccdid = crate::clusters::codec::json_util::get_opt_u8(args, "ccdid")?;
345        encode_client_csr(nonce, ccdid)
346        }
347        0x09 => Err(anyhow::anyhow!("command \"ProvisionClientCertificate\" has complex args: use raw mode")),
348        0x0A => {
349        let ccdid = crate::clusters::codec::json_util::get_opt_u8(args, "ccdid")?;
350        encode_find_client_certificate(ccdid)
351        }
352        0x0C => {
353        let fingerprint = crate::clusters::codec::json_util::get_octstr(args, "fingerprint")?;
354        encode_lookup_client_certificate(fingerprint)
355        }
356        0x0E => {
357        let ccdid = crate::clusters::codec::json_util::get_u8(args, "ccdid")?;
358        encode_remove_client_certificate(ccdid)
359        }
360        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
361    }
362}
363
364#[derive(Debug, serde::Serialize)]
365pub struct ProvisionRootCertificateResponse {
366    pub caid: Option<u8>,
367}
368
369#[derive(Debug, serde::Serialize)]
370pub struct FindRootCertificateResponse {
371    pub certificate_details: Option<Vec<TLSCert>>,
372}
373
374#[derive(Debug, serde::Serialize)]
375pub struct LookupRootCertificateResponse {
376    pub caid: Option<u8>,
377}
378
379#[derive(Debug, serde::Serialize)]
380pub struct ClientCSRResponse {
381    pub ccdid: Option<u8>,
382    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
383    pub csr: Option<Vec<u8>>,
384    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
385    pub nonce_signature: Option<Vec<u8>>,
386}
387
388#[derive(Debug, serde::Serialize)]
389pub struct FindClientCertificateResponse {
390    pub certificate_details: Option<Vec<TLSClientCertificateDetail>>,
391}
392
393#[derive(Debug, serde::Serialize)]
394pub struct LookupClientCertificateResponse {
395    pub ccdid: Option<u8>,
396}
397
398// Command response decoders
399
400/// Decode ProvisionRootCertificateResponse command response (01)
401pub fn decode_provision_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ProvisionRootCertificateResponse> {
402    if let tlv::TlvItemValue::List(_fields) = inp {
403        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
404        Ok(ProvisionRootCertificateResponse {
405                caid: item.get_int(&[0]).map(|v| v as u8),
406        })
407    } else {
408        Err(anyhow::anyhow!("Expected struct fields"))
409    }
410}
411
412/// Decode FindRootCertificateResponse command response (03)
413pub fn decode_find_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<FindRootCertificateResponse> {
414    if let tlv::TlvItemValue::List(_fields) = inp {
415        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
416        Ok(FindRootCertificateResponse {
417                certificate_details: {
418                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
419                        let mut items = Vec::new();
420                        for list_item in l {
421                            items.push(TLSCert {
422                caid: list_item.get_int(&[0]).map(|v| v as u8),
423                certificate: list_item.get_octet_string_owned(&[1]),
424                            });
425                        }
426                        Some(items)
427                    } else {
428                        None
429                    }
430                },
431        })
432    } else {
433        Err(anyhow::anyhow!("Expected struct fields"))
434    }
435}
436
437/// Decode LookupRootCertificateResponse command response (05)
438pub fn decode_lookup_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<LookupRootCertificateResponse> {
439    if let tlv::TlvItemValue::List(_fields) = inp {
440        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
441        Ok(LookupRootCertificateResponse {
442                caid: item.get_int(&[0]).map(|v| v as u8),
443        })
444    } else {
445        Err(anyhow::anyhow!("Expected struct fields"))
446    }
447}
448
449/// Decode ClientCSRResponse command response (08)
450pub fn decode_client_csr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ClientCSRResponse> {
451    if let tlv::TlvItemValue::List(_fields) = inp {
452        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
453        Ok(ClientCSRResponse {
454                ccdid: item.get_int(&[0]).map(|v| v as u8),
455                csr: item.get_octet_string_owned(&[1]),
456                nonce_signature: item.get_octet_string_owned(&[2]),
457        })
458    } else {
459        Err(anyhow::anyhow!("Expected struct fields"))
460    }
461}
462
463/// Decode FindClientCertificateResponse command response (0B)
464pub fn decode_find_client_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<FindClientCertificateResponse> {
465    if let tlv::TlvItemValue::List(_fields) = inp {
466        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
467        Ok(FindClientCertificateResponse {
468                certificate_details: {
469                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
470                        let mut items = Vec::new();
471                        for list_item in l {
472                            items.push(TLSClientCertificateDetail {
473                ccdid: list_item.get_int(&[0]).map(|v| v as u8),
474                client_certificate: list_item.get_octet_string_owned(&[1]),
475                intermediate_certificates: {
476                    if let Some(tlv::TlvItemValue::List(l)) = list_item.get(&[2]) {
477                        let items: Vec<Vec<u8>> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::OctetString(v) = &e.value { Some(v.clone()) } else { None } }).collect();
478                        Some(items)
479                    } else {
480                        None
481                    }
482                },
483                            });
484                        }
485                        Some(items)
486                    } else {
487                        None
488                    }
489                },
490        })
491    } else {
492        Err(anyhow::anyhow!("Expected struct fields"))
493    }
494}
495
496/// Decode LookupClientCertificateResponse command response (0D)
497pub fn decode_lookup_client_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<LookupClientCertificateResponse> {
498    if let tlv::TlvItemValue::List(_fields) = inp {
499        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
500        Ok(LookupClientCertificateResponse {
501                ccdid: item.get_int(&[0]).map(|v| v as u8),
502        })
503    } else {
504        Err(anyhow::anyhow!("Expected struct fields"))
505    }
506}
507
508// Typed facade (invokes + reads)
509
510/// Invoke `ProvisionRootCertificate` command on cluster `TLS Certificate Management`.
511pub async fn provision_root_certificate(conn: &crate::controller::Connection, endpoint: u16, certificate: Vec<u8>, caid: Option<u8>) -> anyhow::Result<ProvisionRootCertificateResponse> {
512    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_PROVISIONROOTCERTIFICATE, &encode_provision_root_certificate(certificate, caid)?).await?;
513    decode_provision_root_certificate_response(&tlv)
514}
515
516/// Invoke `FindRootCertificate` command on cluster `TLS Certificate Management`.
517pub async fn find_root_certificate(conn: &crate::controller::Connection, endpoint: u16, caid: Option<u8>) -> anyhow::Result<FindRootCertificateResponse> {
518    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_FINDROOTCERTIFICATE, &encode_find_root_certificate(caid)?).await?;
519    decode_find_root_certificate_response(&tlv)
520}
521
522/// Invoke `LookupRootCertificate` command on cluster `TLS Certificate Management`.
523pub async fn lookup_root_certificate(conn: &crate::controller::Connection, endpoint: u16, fingerprint: Vec<u8>) -> anyhow::Result<LookupRootCertificateResponse> {
524    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_LOOKUPROOTCERTIFICATE, &encode_lookup_root_certificate(fingerprint)?).await?;
525    decode_lookup_root_certificate_response(&tlv)
526}
527
528/// Invoke `RemoveRootCertificate` command on cluster `TLS Certificate Management`.
529pub async fn remove_root_certificate(conn: &crate::controller::Connection, endpoint: u16, caid: u8) -> anyhow::Result<()> {
530    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_REMOVEROOTCERTIFICATE, &encode_remove_root_certificate(caid)?).await?;
531    Ok(())
532}
533
534/// Invoke `ClientCSR` command on cluster `TLS Certificate Management`.
535pub async fn client_csr(conn: &crate::controller::Connection, endpoint: u16, nonce: Vec<u8>, ccdid: Option<u8>) -> anyhow::Result<ClientCSRResponse> {
536    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_CLIENTCSR, &encode_client_csr(nonce, ccdid)?).await?;
537    decode_client_csr_response(&tlv)
538}
539
540/// Invoke `ProvisionClientCertificate` command on cluster `TLS Certificate Management`.
541pub async fn provision_client_certificate(conn: &crate::controller::Connection, endpoint: u16, ccdid: u8, client_certificate: Vec<u8>, intermediate_certificates: Vec<Vec<u8>>) -> anyhow::Result<()> {
542    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_PROVISIONCLIENTCERTIFICATE, &encode_provision_client_certificate(ccdid, client_certificate, intermediate_certificates)?).await?;
543    Ok(())
544}
545
546/// Invoke `FindClientCertificate` command on cluster `TLS Certificate Management`.
547pub async fn find_client_certificate(conn: &crate::controller::Connection, endpoint: u16, ccdid: Option<u8>) -> anyhow::Result<FindClientCertificateResponse> {
548    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_FINDCLIENTCERTIFICATE, &encode_find_client_certificate(ccdid)?).await?;
549    decode_find_client_certificate_response(&tlv)
550}
551
552/// Invoke `LookupClientCertificate` command on cluster `TLS Certificate Management`.
553pub async fn lookup_client_certificate(conn: &crate::controller::Connection, endpoint: u16, fingerprint: Vec<u8>) -> anyhow::Result<LookupClientCertificateResponse> {
554    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_LOOKUPCLIENTCERTIFICATE, &encode_lookup_client_certificate(fingerprint)?).await?;
555    decode_lookup_client_certificate_response(&tlv)
556}
557
558/// Invoke `RemoveClientCertificate` command on cluster `TLS Certificate Management`.
559pub async fn remove_client_certificate(conn: &crate::controller::Connection, endpoint: u16, ccdid: u8) -> anyhow::Result<()> {
560    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_CMD_ID_REMOVECLIENTCERTIFICATE, &encode_remove_client_certificate(ccdid)?).await?;
561    Ok(())
562}
563
564/// Read `MaxRootCertificates` attribute from cluster `TLS Certificate Management`.
565pub async fn read_max_root_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
566    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_ATTR_ID_MAXROOTCERTIFICATES).await?;
567    decode_max_root_certificates(&tlv)
568}
569
570/// Read `ProvisionedRootCertificates` attribute from cluster `TLS Certificate Management`.
571pub async fn read_provisioned_root_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<TLSCert>> {
572    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_ATTR_ID_PROVISIONEDROOTCERTIFICATES).await?;
573    decode_provisioned_root_certificates(&tlv)
574}
575
576/// Read `MaxClientCertificates` attribute from cluster `TLS Certificate Management`.
577pub async fn read_max_client_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
578    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_ATTR_ID_MAXCLIENTCERTIFICATES).await?;
579    decode_max_client_certificates(&tlv)
580}
581
582/// Read `ProvisionedClientCertificates` attribute from cluster `TLS Certificate Management`.
583pub async fn read_provisioned_client_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<TLSClientCertificateDetail>> {
584    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TLS_CERTIFICATE_MANAGEMENT, crate::clusters::defs::CLUSTER_TLS_CERTIFICATE_MANAGEMENT_ATTR_ID_PROVISIONEDCLIENTCERTIFICATES).await?;
585    decode_provisioned_client_certificates(&tlv)
586}
587