1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13use crate::clusters::helpers::{serialize_opt_bytes_as_hex, serialize_opt_vec_bytes_as_hex};
15
16#[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
34pub 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
48pub 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
59pub 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
70pub 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
81pub 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
93pub 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
106pub 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
117pub 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
128pub 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
139pub 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
150pub 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
164pub 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
173pub 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
196pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
208 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
242pub 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
255pub 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
398pub 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
412pub 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
437pub 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
449pub 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
463pub 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
496pub 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
508pub 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
516pub 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
522pub 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
528pub 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
534pub 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
540pub 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
546pub 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
552pub 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
558pub 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
564pub 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
570pub 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
576pub 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
582pub 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