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