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};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum CertificateChainType {
21 Daccertificate = 1,
23 Paicertificate = 2,
25}
26
27impl CertificateChainType {
28 pub fn from_u8(value: u8) -> Option<Self> {
30 match value {
31 1 => Some(CertificateChainType::Daccertificate),
32 2 => Some(CertificateChainType::Paicertificate),
33 _ => None,
34 }
35 }
36
37 pub fn to_u8(self) -> u8 {
39 self as u8
40 }
41}
42
43impl From<CertificateChainType> for u8 {
44 fn from(val: CertificateChainType) -> Self {
45 val as u8
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum NodeOperationalCertStatus {
52 Ok = 0,
54 Invalidpublickey = 1,
56 Invalidnodeopid = 2,
58 Invalidnoc = 3,
60 Missingcsr = 4,
62 Tablefull = 5,
64 Invalidadminsubject = 6,
66 Fabricconflict = 9,
68 Labelconflict = 10,
70 Invalidfabricindex = 11,
72}
73
74impl NodeOperationalCertStatus {
75 pub fn from_u8(value: u8) -> Option<Self> {
77 match value {
78 0 => Some(NodeOperationalCertStatus::Ok),
79 1 => Some(NodeOperationalCertStatus::Invalidpublickey),
80 2 => Some(NodeOperationalCertStatus::Invalidnodeopid),
81 3 => Some(NodeOperationalCertStatus::Invalidnoc),
82 4 => Some(NodeOperationalCertStatus::Missingcsr),
83 5 => Some(NodeOperationalCertStatus::Tablefull),
84 6 => Some(NodeOperationalCertStatus::Invalidadminsubject),
85 9 => Some(NodeOperationalCertStatus::Fabricconflict),
86 10 => Some(NodeOperationalCertStatus::Labelconflict),
87 11 => Some(NodeOperationalCertStatus::Invalidfabricindex),
88 _ => None,
89 }
90 }
91
92 pub fn to_u8(self) -> u8 {
94 self as u8
95 }
96}
97
98impl From<NodeOperationalCertStatus> for u8 {
99 fn from(val: NodeOperationalCertStatus) -> Self {
100 val as u8
101 }
102}
103
104#[derive(Debug, serde::Serialize)]
107pub struct FabricDescriptor {
108 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
109 pub root_public_key: Option<Vec<u8>>,
110 pub vendor_id: Option<u16>,
111 pub fabric_id: Option<u8>,
112 pub node_id: Option<u64>,
113 pub label: Option<String>,
114 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
115 pub vid_verification_statement: Option<Vec<u8>>,
116}
117
118#[derive(Debug, serde::Serialize)]
119pub struct NOC {
120 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
121 pub noc: Option<Vec<u8>>,
122 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
123 pub icac: Option<Vec<u8>>,
124 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
125 pub vvsc: Option<Vec<u8>>,
126}
127
128pub fn encode_attestation_request(attestation_nonce: Vec<u8>) -> anyhow::Result<Vec<u8>> {
132 let tlv = tlv::TlvItemEnc {
133 tag: 0,
134 value: tlv::TlvItemValueEnc::StructInvisible(vec![
135 (0, tlv::TlvItemValueEnc::OctetString(attestation_nonce)).into(),
136 ]),
137 };
138 Ok(tlv.encode()?)
139}
140
141pub fn encode_certificate_chain_request(certificate_type: CertificateChainType) -> anyhow::Result<Vec<u8>> {
143 let tlv = tlv::TlvItemEnc {
144 tag: 0,
145 value: tlv::TlvItemValueEnc::StructInvisible(vec![
146 (0, tlv::TlvItemValueEnc::UInt8(certificate_type.to_u8())).into(),
147 ]),
148 };
149 Ok(tlv.encode()?)
150}
151
152pub fn encode_csr_request(csr_nonce: Vec<u8>, is_for_update_noc: Option<bool>) -> anyhow::Result<Vec<u8>> {
154 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
155 tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(csr_nonce)).into());
156 if let Some(x) = is_for_update_noc { tlv_fields.push((1, tlv::TlvItemValueEnc::Bool(x)).into()); }
157 let tlv = tlv::TlvItemEnc {
158 tag: 0,
159 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
160 };
161 Ok(tlv.encode()?)
162}
163
164pub fn encode_add_noc(noc_value: Vec<u8>, icac_value: Option<Vec<u8>>, ipk_value: Vec<u8>, case_admin_subject: u64, admin_vendor_id: u16) -> anyhow::Result<Vec<u8>> {
166 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
167 tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(noc_value)).into());
168 if let Some(x) = icac_value { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
169 tlv_fields.push((2, tlv::TlvItemValueEnc::OctetString(ipk_value)).into());
170 tlv_fields.push((3, tlv::TlvItemValueEnc::UInt64(case_admin_subject)).into());
171 tlv_fields.push((4, tlv::TlvItemValueEnc::UInt16(admin_vendor_id)).into());
172 let tlv = tlv::TlvItemEnc {
173 tag: 0,
174 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
175 };
176 Ok(tlv.encode()?)
177}
178
179pub fn encode_update_noc(noc_value: Vec<u8>, icac_value: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
181 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
182 tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(noc_value)).into());
183 if let Some(x) = icac_value { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
184 let tlv = tlv::TlvItemEnc {
185 tag: 0,
186 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
187 };
188 Ok(tlv.encode()?)
189}
190
191pub fn encode_update_fabric_label(label: String) -> anyhow::Result<Vec<u8>> {
193 let tlv = tlv::TlvItemEnc {
194 tag: 0,
195 value: tlv::TlvItemValueEnc::StructInvisible(vec![
196 (0, tlv::TlvItemValueEnc::String(label)).into(),
197 ]),
198 };
199 Ok(tlv.encode()?)
200}
201
202pub fn encode_remove_fabric(fabric_index: u8) -> anyhow::Result<Vec<u8>> {
204 let tlv = tlv::TlvItemEnc {
205 tag: 0,
206 value: tlv::TlvItemValueEnc::StructInvisible(vec![
207 (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
208 ]),
209 };
210 Ok(tlv.encode()?)
211}
212
213pub fn encode_add_trusted_root_certificate(root_ca_certificate: Vec<u8>) -> anyhow::Result<Vec<u8>> {
215 let tlv = tlv::TlvItemEnc {
216 tag: 0,
217 value: tlv::TlvItemValueEnc::StructInvisible(vec![
218 (0, tlv::TlvItemValueEnc::OctetString(root_ca_certificate)).into(),
219 ]),
220 };
221 Ok(tlv.encode()?)
222}
223
224pub fn encode_set_vid_verification_statement(vendor_id: Option<u16>, vid_verification_statement: Option<Vec<u8>>, vvsc: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
226 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
227 if let Some(x) = vendor_id { tlv_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
228 if let Some(x) = vid_verification_statement { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
229 if let Some(x) = vvsc { tlv_fields.push((2, tlv::TlvItemValueEnc::OctetString(x)).into()); }
230 let tlv = tlv::TlvItemEnc {
231 tag: 0,
232 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
233 };
234 Ok(tlv.encode()?)
235}
236
237pub fn encode_sign_vid_verification_request(fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<Vec<u8>> {
239 let tlv = tlv::TlvItemEnc {
240 tag: 0,
241 value: tlv::TlvItemValueEnc::StructInvisible(vec![
242 (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
243 (1, tlv::TlvItemValueEnc::OctetString(client_challenge)).into(),
244 ]),
245 };
246 Ok(tlv.encode()?)
247}
248
249pub fn decode_no_cs(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NOC>> {
253 let mut res = Vec::new();
254 if let tlv::TlvItemValue::List(v) = inp {
255 for item in v {
256 res.push(NOC {
257 noc: item.get_octet_string_owned(&[1]),
258 icac: item.get_octet_string_owned(&[2]),
259 vvsc: item.get_octet_string_owned(&[3]),
260 });
261 }
262 }
263 Ok(res)
264}
265
266pub fn decode_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<FabricDescriptor>> {
268 let mut res = Vec::new();
269 if let tlv::TlvItemValue::List(v) = inp {
270 for item in v {
271 res.push(FabricDescriptor {
272 root_public_key: item.get_octet_string_owned(&[1]),
273 vendor_id: item.get_int(&[2]).map(|v| v as u16),
274 fabric_id: item.get_int(&[3]).map(|v| v as u8),
275 node_id: item.get_int(&[4]),
276 label: item.get_string_owned(&[5]),
277 vid_verification_statement: item.get_octet_string_owned(&[6]),
278 });
279 }
280 }
281 Ok(res)
282}
283
284pub fn decode_supported_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
286 if let tlv::TlvItemValue::Int(v) = inp {
287 Ok(*v as u8)
288 } else {
289 Err(anyhow::anyhow!("Expected UInt8"))
290 }
291}
292
293pub fn decode_commissioned_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
295 if let tlv::TlvItemValue::Int(v) = inp {
296 Ok(*v as u8)
297 } else {
298 Err(anyhow::anyhow!("Expected UInt8"))
299 }
300}
301
302pub fn decode_trusted_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
304 let mut res = Vec::new();
305 if let tlv::TlvItemValue::List(v) = inp {
306 for item in v {
307 if let tlv::TlvItemValue::OctetString(o) = &item.value {
308 res.push(o.clone());
309 }
310 }
311 }
312 Ok(res)
313}
314
315pub fn decode_current_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
317 if let tlv::TlvItemValue::Int(v) = inp {
318 Ok(*v as u8)
319 } else {
320 Err(anyhow::anyhow!("Expected UInt8"))
321 }
322}
323
324
325pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
337 if ![0x003E].contains(&cluster_id) {
339 return format!("{{\"error\": \"Invalid cluster ID. Expected [0x003E], got {}\"}}", cluster_id);
340 }
341
342 match attribute_id {
343 0x0000 => {
344 match decode_no_cs(tlv_value) {
345 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
346 Err(e) => format!("{{\"error\": \"{}\"}}", e),
347 }
348 }
349 0x0001 => {
350 match decode_fabrics(tlv_value) {
351 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
352 Err(e) => format!("{{\"error\": \"{}\"}}", e),
353 }
354 }
355 0x0002 => {
356 match decode_supported_fabrics(tlv_value) {
357 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
358 Err(e) => format!("{{\"error\": \"{}\"}}", e),
359 }
360 }
361 0x0003 => {
362 match decode_commissioned_fabrics(tlv_value) {
363 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
364 Err(e) => format!("{{\"error\": \"{}\"}}", e),
365 }
366 }
367 0x0004 => {
368 match decode_trusted_root_certificates(tlv_value) {
369 Ok(value) => {
370 let hex_array: Vec<String> = value.iter()
372 .map(|bytes| bytes.iter()
373 .map(|byte| format!("{:02x}", byte))
374 .collect::<String>())
375 .collect();
376 serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
377 },
378 Err(e) => format!("{{\"error\": \"{}\"}}", e),
379 }
380 }
381 0x0005 => {
382 match decode_current_fabric_index(tlv_value) {
383 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
384 Err(e) => format!("{{\"error\": \"{}\"}}", e),
385 }
386 }
387 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
388 }
389}
390
391pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
396 vec![
397 (0x0000, "NOCs"),
398 (0x0001, "Fabrics"),
399 (0x0002, "SupportedFabrics"),
400 (0x0003, "CommissionedFabrics"),
401 (0x0004, "TrustedRootCertificates"),
402 (0x0005, "CurrentFabricIndex"),
403 ]
404}
405
406pub fn get_command_list() -> Vec<(u32, &'static str)> {
409 vec![
410 (0x00, "AttestationRequest"),
411 (0x02, "CertificateChainRequest"),
412 (0x04, "CSRRequest"),
413 (0x06, "AddNOC"),
414 (0x07, "UpdateNOC"),
415 (0x09, "UpdateFabricLabel"),
416 (0x0A, "RemoveFabric"),
417 (0x0B, "AddTrustedRootCertificate"),
418 (0x0C, "SetVIDVerificationStatement"),
419 (0x0D, "SignVIDVerificationRequest"),
420 ]
421}
422
423pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
424 match cmd_id {
425 0x00 => Some("AttestationRequest"),
426 0x02 => Some("CertificateChainRequest"),
427 0x04 => Some("CSRRequest"),
428 0x06 => Some("AddNOC"),
429 0x07 => Some("UpdateNOC"),
430 0x09 => Some("UpdateFabricLabel"),
431 0x0A => Some("RemoveFabric"),
432 0x0B => Some("AddTrustedRootCertificate"),
433 0x0C => Some("SetVIDVerificationStatement"),
434 0x0D => Some("SignVIDVerificationRequest"),
435 _ => None,
436 }
437}
438
439pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
440 match cmd_id {
441 0x00 => Some(vec![
442 crate::clusters::codec::CommandField { tag: 0, name: "attestation_nonce", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
443 ]),
444 0x02 => Some(vec![
445 crate::clusters::codec::CommandField { tag: 0, name: "certificate_type", kind: crate::clusters::codec::FieldKind::Enum { name: "CertificateChainType", variants: &[(1, "Daccertificate"), (2, "Paicertificate")] }, optional: false, nullable: false },
446 ]),
447 0x04 => Some(vec![
448 crate::clusters::codec::CommandField { tag: 0, name: "csr_nonce", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
449 crate::clusters::codec::CommandField { tag: 1, name: "is_for_update_noc", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
450 ]),
451 0x06 => Some(vec![
452 crate::clusters::codec::CommandField { tag: 0, name: "noc_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
453 crate::clusters::codec::CommandField { tag: 1, name: "icac_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
454 crate::clusters::codec::CommandField { tag: 2, name: "ipk_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
455 crate::clusters::codec::CommandField { tag: 3, name: "case_admin_subject", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
456 crate::clusters::codec::CommandField { tag: 4, name: "admin_vendor_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
457 ]),
458 0x07 => Some(vec![
459 crate::clusters::codec::CommandField { tag: 0, name: "noc_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
460 crate::clusters::codec::CommandField { tag: 1, name: "icac_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
461 ]),
462 0x09 => Some(vec![
463 crate::clusters::codec::CommandField { tag: 0, name: "label", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
464 ]),
465 0x0A => Some(vec![
466 crate::clusters::codec::CommandField { tag: 0, name: "fabric_index", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
467 ]),
468 0x0B => Some(vec![
469 crate::clusters::codec::CommandField { tag: 0, name: "root_ca_certificate", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
470 ]),
471 0x0C => Some(vec![
472 crate::clusters::codec::CommandField { tag: 0, name: "vendor_id", kind: crate::clusters::codec::FieldKind::U16, optional: true, nullable: false },
473 crate::clusters::codec::CommandField { tag: 1, name: "vid_verification_statement", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
474 crate::clusters::codec::CommandField { tag: 2, name: "vvsc", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
475 ]),
476 0x0D => Some(vec![
477 crate::clusters::codec::CommandField { tag: 0, name: "fabric_index", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
478 crate::clusters::codec::CommandField { tag: 1, name: "client_challenge", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
479 ]),
480 _ => None,
481 }
482}
483
484pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
485 match cmd_id {
486 0x00 => {
487 let attestation_nonce = crate::clusters::codec::json_util::get_octstr(args, "attestation_nonce")?;
488 encode_attestation_request(attestation_nonce)
489 }
490 0x02 => {
491 let certificate_type = {
492 let n = crate::clusters::codec::json_util::get_u64(args, "certificate_type")?;
493 CertificateChainType::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid CertificateChainType: {}", n))?
494 };
495 encode_certificate_chain_request(certificate_type)
496 }
497 0x04 => {
498 let csr_nonce = crate::clusters::codec::json_util::get_octstr(args, "csr_nonce")?;
499 let is_for_update_noc = crate::clusters::codec::json_util::get_opt_bool(args, "is_for_update_noc")?;
500 encode_csr_request(csr_nonce, is_for_update_noc)
501 }
502 0x06 => {
503 let noc_value = crate::clusters::codec::json_util::get_octstr(args, "noc_value")?;
504 let icac_value = crate::clusters::codec::json_util::get_opt_octstr(args, "icac_value")?;
505 let ipk_value = crate::clusters::codec::json_util::get_octstr(args, "ipk_value")?;
506 let case_admin_subject = crate::clusters::codec::json_util::get_u64(args, "case_admin_subject")?;
507 let admin_vendor_id = crate::clusters::codec::json_util::get_u16(args, "admin_vendor_id")?;
508 encode_add_noc(noc_value, icac_value, ipk_value, case_admin_subject, admin_vendor_id)
509 }
510 0x07 => {
511 let noc_value = crate::clusters::codec::json_util::get_octstr(args, "noc_value")?;
512 let icac_value = crate::clusters::codec::json_util::get_opt_octstr(args, "icac_value")?;
513 encode_update_noc(noc_value, icac_value)
514 }
515 0x09 => {
516 let label = crate::clusters::codec::json_util::get_string(args, "label")?;
517 encode_update_fabric_label(label)
518 }
519 0x0A => {
520 let fabric_index = crate::clusters::codec::json_util::get_u8(args, "fabric_index")?;
521 encode_remove_fabric(fabric_index)
522 }
523 0x0B => {
524 let root_ca_certificate = crate::clusters::codec::json_util::get_octstr(args, "root_ca_certificate")?;
525 encode_add_trusted_root_certificate(root_ca_certificate)
526 }
527 0x0C => {
528 let vendor_id = crate::clusters::codec::json_util::get_opt_u16(args, "vendor_id")?;
529 let vid_verification_statement = crate::clusters::codec::json_util::get_opt_octstr(args, "vid_verification_statement")?;
530 let vvsc = crate::clusters::codec::json_util::get_opt_octstr(args, "vvsc")?;
531 encode_set_vid_verification_statement(vendor_id, vid_verification_statement, vvsc)
532 }
533 0x0D => {
534 let fabric_index = crate::clusters::codec::json_util::get_u8(args, "fabric_index")?;
535 let client_challenge = crate::clusters::codec::json_util::get_octstr(args, "client_challenge")?;
536 encode_sign_vid_verification_request(fabric_index, client_challenge)
537 }
538 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
539 }
540}
541
542#[derive(Debug, serde::Serialize)]
543pub struct AttestationResponse {
544 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
545 pub attestation_elements: Option<Vec<u8>>,
546 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
547 pub attestation_signature: Option<Vec<u8>>,
548}
549
550#[derive(Debug, serde::Serialize)]
551pub struct CertificateChainResponse {
552 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
553 pub certificate: Option<Vec<u8>>,
554}
555
556#[derive(Debug, serde::Serialize)]
557pub struct CSRResponse {
558 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
559 pub nocsr_elements: Option<Vec<u8>>,
560 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
561 pub attestation_signature: Option<Vec<u8>>,
562}
563
564#[derive(Debug, serde::Serialize)]
565pub struct NOCResponse {
566 pub status_code: Option<NodeOperationalCertStatus>,
567 pub fabric_index: Option<u8>,
568 pub debug_text: Option<String>,
569}
570
571#[derive(Debug, serde::Serialize)]
572pub struct SignVIDVerificationResponse {
573 pub fabric_index: Option<u8>,
574 pub fabric_binding_version: Option<u8>,
575 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
576 pub signature: Option<Vec<u8>>,
577}
578
579pub fn decode_attestation_response(inp: &tlv::TlvItemValue) -> anyhow::Result<AttestationResponse> {
583 if let tlv::TlvItemValue::List(_fields) = inp {
584 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
585 Ok(AttestationResponse {
586 attestation_elements: item.get_octet_string_owned(&[0]),
587 attestation_signature: item.get_octet_string_owned(&[1]),
588 })
589 } else {
590 Err(anyhow::anyhow!("Expected struct fields"))
591 }
592}
593
594pub fn decode_certificate_chain_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CertificateChainResponse> {
596 if let tlv::TlvItemValue::List(_fields) = inp {
597 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
598 Ok(CertificateChainResponse {
599 certificate: item.get_octet_string_owned(&[0]),
600 })
601 } else {
602 Err(anyhow::anyhow!("Expected struct fields"))
603 }
604}
605
606pub fn decode_csr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CSRResponse> {
608 if let tlv::TlvItemValue::List(_fields) = inp {
609 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
610 Ok(CSRResponse {
611 nocsr_elements: item.get_octet_string_owned(&[0]),
612 attestation_signature: item.get_octet_string_owned(&[1]),
613 })
614 } else {
615 Err(anyhow::anyhow!("Expected struct fields"))
616 }
617}
618
619pub fn decode_noc_response(inp: &tlv::TlvItemValue) -> anyhow::Result<NOCResponse> {
621 if let tlv::TlvItemValue::List(_fields) = inp {
622 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
623 Ok(NOCResponse {
624 status_code: item.get_int(&[0]).and_then(|v| NodeOperationalCertStatus::from_u8(v as u8)),
625 fabric_index: item.get_int(&[1]).map(|v| v as u8),
626 debug_text: item.get_string_owned(&[2]),
627 })
628 } else {
629 Err(anyhow::anyhow!("Expected struct fields"))
630 }
631}
632
633pub fn decode_sign_vid_verification_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SignVIDVerificationResponse> {
635 if let tlv::TlvItemValue::List(_fields) = inp {
636 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
637 Ok(SignVIDVerificationResponse {
638 fabric_index: item.get_int(&[0]).map(|v| v as u8),
639 fabric_binding_version: item.get_int(&[1]).map(|v| v as u8),
640 signature: item.get_octet_string_owned(&[2]),
641 })
642 } else {
643 Err(anyhow::anyhow!("Expected struct fields"))
644 }
645}
646
647pub async fn attestation_request(conn: &crate::controller::Connection, endpoint: u16, attestation_nonce: Vec<u8>) -> anyhow::Result<AttestationResponse> {
651 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ATTESTATIONREQUEST, &encode_attestation_request(attestation_nonce)?).await?;
652 decode_attestation_response(&tlv)
653}
654
655pub async fn certificate_chain_request(conn: &crate::controller::Connection, endpoint: u16, certificate_type: CertificateChainType) -> anyhow::Result<CertificateChainResponse> {
657 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CERTIFICATECHAINREQUEST, &encode_certificate_chain_request(certificate_type)?).await?;
658 decode_certificate_chain_response(&tlv)
659}
660
661pub async fn csr_request(conn: &crate::controller::Connection, endpoint: u16, csr_nonce: Vec<u8>, is_for_update_noc: Option<bool>) -> anyhow::Result<CSRResponse> {
663 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_CSRREQUEST, &encode_csr_request(csr_nonce, is_for_update_noc)?).await?;
664 decode_csr_response(&tlv)
665}
666
667pub async fn add_noc(conn: &crate::controller::Connection, endpoint: u16, noc_value: Vec<u8>, icac_value: Option<Vec<u8>>, ipk_value: Vec<u8>, case_admin_subject: u64, admin_vendor_id: u16) -> anyhow::Result<NOCResponse> {
669 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ADDNOC, &encode_add_noc(noc_value, icac_value, ipk_value, case_admin_subject, admin_vendor_id)?).await?;
670 decode_noc_response(&tlv)
671}
672
673pub async fn update_noc(conn: &crate::controller::Connection, endpoint: u16, noc_value: Vec<u8>, icac_value: Option<Vec<u8>>) -> anyhow::Result<NOCResponse> {
675 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_UPDATENOC, &encode_update_noc(noc_value, icac_value)?).await?;
676 decode_noc_response(&tlv)
677}
678
679pub async fn update_fabric_label(conn: &crate::controller::Connection, endpoint: u16, label: String) -> anyhow::Result<NOCResponse> {
681 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_UPDATEFABRICLABEL, &encode_update_fabric_label(label)?).await?;
682 decode_noc_response(&tlv)
683}
684
685pub async fn remove_fabric(conn: &crate::controller::Connection, endpoint: u16, fabric_index: u8) -> anyhow::Result<NOCResponse> {
687 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_REMOVEFABRIC, &encode_remove_fabric(fabric_index)?).await?;
688 decode_noc_response(&tlv)
689}
690
691pub async fn add_trusted_root_certificate(conn: &crate::controller::Connection, endpoint: u16, root_ca_certificate: Vec<u8>) -> anyhow::Result<()> {
693 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_ADDTRUSTEDROOTCERTIFICATE, &encode_add_trusted_root_certificate(root_ca_certificate)?).await?;
694 Ok(())
695}
696
697pub async fn set_vid_verification_statement(conn: &crate::controller::Connection, endpoint: u16, vendor_id: Option<u16>, vid_verification_statement: Option<Vec<u8>>, vvsc: Option<Vec<u8>>) -> anyhow::Result<()> {
699 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_SETVIDVERIFICATIONSTATEMENT, &encode_set_vid_verification_statement(vendor_id, vid_verification_statement, vvsc)?).await?;
700 Ok(())
701}
702
703pub async fn sign_vid_verification_request(conn: &crate::controller::Connection, endpoint: u16, fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<SignVIDVerificationResponse> {
705 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_CMD_ID_SIGNVIDVERIFICATIONREQUEST, &encode_sign_vid_verification_request(fabric_index, client_challenge)?).await?;
706 decode_sign_vid_verification_response(&tlv)
707}
708
709pub async fn read_no_cs(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NOC>> {
711 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_NOCS).await?;
712 decode_no_cs(&tlv)
713}
714
715pub async fn read_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<FabricDescriptor>> {
717 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_FABRICS).await?;
718 decode_fabrics(&tlv)
719}
720
721pub async fn read_supported_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
723 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_SUPPORTEDFABRICS).await?;
724 decode_supported_fabrics(&tlv)
725}
726
727pub async fn read_commissioned_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
729 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_COMMISSIONEDFABRICS).await?;
730 decode_commissioned_fabrics(&tlv)
731}
732
733pub async fn read_trusted_root_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
735 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_TRUSTEDROOTCERTIFICATES).await?;
736 decode_trusted_root_certificates(&tlv)
737}
738
739pub async fn read_current_fabric_index(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
741 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_CURRENTFABRICINDEX).await?;
742 decode_current_fabric_index(&tlv)
743}
744