1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17#[repr(u8)]
18pub enum CertificateChainType {
19 Daccertificate = 1,
21 Paicertificate = 2,
23}
24
25impl CertificateChainType {
26 pub fn from_u8(value: u8) -> Option<Self> {
28 match value {
29 1 => Some(CertificateChainType::Daccertificate),
30 2 => Some(CertificateChainType::Paicertificate),
31 _ => None,
32 }
33 }
34
35 pub fn to_u8(self) -> u8 {
37 self as u8
38 }
39}
40
41impl From<CertificateChainType> for u8 {
42 fn from(val: CertificateChainType) -> Self {
43 val as u8
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
48#[repr(u8)]
49pub enum NodeOperationalCertStatus {
50 Ok = 0,
52 Invalidpublickey = 1,
54 Invalidnodeopid = 2,
56 Invalidnoc = 3,
58 Missingcsr = 4,
60 Tablefull = 5,
62 Invalidadminsubject = 6,
64 Reservedforfutureuse = 7,
66 Reservedforfutureuse8 = 8,
68 Fabricconflict = 9,
70 Labelconflict = 10,
72 Invalidfabricindex = 11,
74}
75
76impl NodeOperationalCertStatus {
77 pub fn from_u8(value: u8) -> Option<Self> {
79 match value {
80 0 => Some(NodeOperationalCertStatus::Ok),
81 1 => Some(NodeOperationalCertStatus::Invalidpublickey),
82 2 => Some(NodeOperationalCertStatus::Invalidnodeopid),
83 3 => Some(NodeOperationalCertStatus::Invalidnoc),
84 4 => Some(NodeOperationalCertStatus::Missingcsr),
85 5 => Some(NodeOperationalCertStatus::Tablefull),
86 6 => Some(NodeOperationalCertStatus::Invalidadminsubject),
87 7 => Some(NodeOperationalCertStatus::Reservedforfutureuse),
88 8 => Some(NodeOperationalCertStatus::Reservedforfutureuse8),
89 9 => Some(NodeOperationalCertStatus::Fabricconflict),
90 10 => Some(NodeOperationalCertStatus::Labelconflict),
91 11 => Some(NodeOperationalCertStatus::Invalidfabricindex),
92 _ => None,
93 }
94 }
95
96 pub fn to_u8(self) -> u8 {
98 self as u8
99 }
100}
101
102impl From<NodeOperationalCertStatus> for u8 {
103 fn from(val: NodeOperationalCertStatus) -> Self {
104 val as u8
105 }
106}
107
108#[derive(Debug, serde::Serialize)]
111pub struct FabricDescriptor {
112 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
113 pub root_public_key: Option<Vec<u8>>,
114 pub vendor_id: Option<u16>,
115 pub fabric_id: Option<u8>,
116 pub node_id: Option<u64>,
117 pub label: Option<String>,
118 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
119 pub vid_verification_statement: Option<Vec<u8>>,
120}
121
122#[derive(Debug, serde::Serialize)]
123pub struct NOC {
124 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
125 pub noc: Option<Vec<u8>>,
126 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
127 pub icac: Option<Vec<u8>>,
128 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
129 pub vvsc: Option<Vec<u8>>,
130}
131
132pub fn encode_attestation_request(attestation_nonce: Vec<u8>) -> anyhow::Result<Vec<u8>> {
136 let tlv = tlv::TlvItemEnc {
137 tag: 0,
138 value: tlv::TlvItemValueEnc::StructInvisible(vec![
139 (0, tlv::TlvItemValueEnc::OctetString(attestation_nonce)).into(),
140 ]),
141 };
142 Ok(tlv.encode()?)
143}
144
145pub fn encode_certificate_chain_request(certificate_type: CertificateChainType) -> anyhow::Result<Vec<u8>> {
147 let tlv = tlv::TlvItemEnc {
148 tag: 0,
149 value: tlv::TlvItemValueEnc::StructInvisible(vec![
150 (0, tlv::TlvItemValueEnc::UInt8(certificate_type.to_u8())).into(),
151 ]),
152 };
153 Ok(tlv.encode()?)
154}
155
156pub fn encode_csr_request(csr_nonce: Vec<u8>, is_for_update_noc: bool) -> anyhow::Result<Vec<u8>> {
158 let tlv = tlv::TlvItemEnc {
159 tag: 0,
160 value: tlv::TlvItemValueEnc::StructInvisible(vec![
161 (0, tlv::TlvItemValueEnc::OctetString(csr_nonce)).into(),
162 (1, tlv::TlvItemValueEnc::Bool(is_for_update_noc)).into(),
163 ]),
164 };
165 Ok(tlv.encode()?)
166}
167
168pub 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>> {
170 let tlv = tlv::TlvItemEnc {
171 tag: 0,
172 value: tlv::TlvItemValueEnc::StructInvisible(vec![
173 (0, tlv::TlvItemValueEnc::OctetString(noc_value)).into(),
174 (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
175 (2, tlv::TlvItemValueEnc::OctetString(ipk_value)).into(),
176 (3, tlv::TlvItemValueEnc::UInt64(case_admin_subject)).into(),
177 (4, tlv::TlvItemValueEnc::UInt16(admin_vendor_id)).into(),
178 ]),
179 };
180 Ok(tlv.encode()?)
181}
182
183pub fn encode_update_noc(noc_value: Vec<u8>, icac_value: Vec<u8>) -> anyhow::Result<Vec<u8>> {
185 let tlv = tlv::TlvItemEnc {
186 tag: 0,
187 value: tlv::TlvItemValueEnc::StructInvisible(vec![
188 (0, tlv::TlvItemValueEnc::OctetString(noc_value)).into(),
189 (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
190 ]),
191 };
192 Ok(tlv.encode()?)
193}
194
195pub fn encode_update_fabric_label(label: String) -> anyhow::Result<Vec<u8>> {
197 let tlv = tlv::TlvItemEnc {
198 tag: 0,
199 value: tlv::TlvItemValueEnc::StructInvisible(vec![
200 (0, tlv::TlvItemValueEnc::String(label)).into(),
201 ]),
202 };
203 Ok(tlv.encode()?)
204}
205
206pub fn encode_remove_fabric(fabric_index: u8) -> anyhow::Result<Vec<u8>> {
208 let tlv = tlv::TlvItemEnc {
209 tag: 0,
210 value: tlv::TlvItemValueEnc::StructInvisible(vec![
211 (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
212 ]),
213 };
214 Ok(tlv.encode()?)
215}
216
217pub fn encode_add_trusted_root_certificate(root_ca_certificate: Vec<u8>) -> anyhow::Result<Vec<u8>> {
219 let tlv = tlv::TlvItemEnc {
220 tag: 0,
221 value: tlv::TlvItemValueEnc::StructInvisible(vec![
222 (0, tlv::TlvItemValueEnc::OctetString(root_ca_certificate)).into(),
223 ]),
224 };
225 Ok(tlv.encode()?)
226}
227
228pub fn encode_set_vid_verification_statement(vendor_id: u16, vid_verification_statement: Vec<u8>, vvsc: Vec<u8>) -> anyhow::Result<Vec<u8>> {
230 let tlv = tlv::TlvItemEnc {
231 tag: 0,
232 value: tlv::TlvItemValueEnc::StructInvisible(vec![
233 (0, tlv::TlvItemValueEnc::UInt16(vendor_id)).into(),
234 (1, tlv::TlvItemValueEnc::OctetString(vid_verification_statement)).into(),
235 (2, tlv::TlvItemValueEnc::OctetString(vvsc)).into(),
236 ]),
237 };
238 Ok(tlv.encode()?)
239}
240
241pub fn encode_sign_vid_verification_request(fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<Vec<u8>> {
243 let tlv = tlv::TlvItemEnc {
244 tag: 0,
245 value: tlv::TlvItemValueEnc::StructInvisible(vec![
246 (0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
247 (1, tlv::TlvItemValueEnc::OctetString(client_challenge)).into(),
248 ]),
249 };
250 Ok(tlv.encode()?)
251}
252
253pub fn decode_no_cs(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NOC>> {
257 let mut res = Vec::new();
258 if let tlv::TlvItemValue::List(v) = inp {
259 for item in v {
260 res.push(NOC {
261 noc: item.get_octet_string_owned(&[1]),
262 icac: item.get_octet_string_owned(&[2]),
263 vvsc: item.get_octet_string_owned(&[3]),
264 });
265 }
266 }
267 Ok(res)
268}
269
270pub fn decode_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<FabricDescriptor>> {
272 let mut res = Vec::new();
273 if let tlv::TlvItemValue::List(v) = inp {
274 for item in v {
275 res.push(FabricDescriptor {
276 root_public_key: item.get_octet_string_owned(&[1]),
277 vendor_id: item.get_int(&[2]).map(|v| v as u16),
278 fabric_id: item.get_int(&[3]).map(|v| v as u8),
279 node_id: item.get_int(&[4]),
280 label: item.get_string_owned(&[5]),
281 vid_verification_statement: item.get_octet_string_owned(&[6]),
282 });
283 }
284 }
285 Ok(res)
286}
287
288pub fn decode_supported_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
290 if let tlv::TlvItemValue::Int(v) = inp {
291 Ok(*v as u8)
292 } else {
293 Err(anyhow::anyhow!("Expected UInt8"))
294 }
295}
296
297pub fn decode_commissioned_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
299 if let tlv::TlvItemValue::Int(v) = inp {
300 Ok(*v as u8)
301 } else {
302 Err(anyhow::anyhow!("Expected UInt8"))
303 }
304}
305
306pub fn decode_trusted_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
308 let mut res = Vec::new();
309 if let tlv::TlvItemValue::List(v) = inp {
310 for item in v {
311 if let tlv::TlvItemValue::OctetString(o) = &item.value {
312 res.push(o.clone());
313 }
314 }
315 }
316 Ok(res)
317}
318
319pub fn decode_current_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
321 if let tlv::TlvItemValue::Int(v) = inp {
322 Ok(*v as u8)
323 } else {
324 Err(anyhow::anyhow!("Expected UInt8"))
325 }
326}
327
328
329pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
341 if cluster_id != 0x003E {
343 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003E, got {}\"}}", cluster_id);
344 }
345
346 match attribute_id {
347 0x0000 => {
348 match decode_no_cs(tlv_value) {
349 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
350 Err(e) => format!("{{\"error\": \"{}\"}}", e),
351 }
352 }
353 0x0001 => {
354 match decode_fabrics(tlv_value) {
355 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
356 Err(e) => format!("{{\"error\": \"{}\"}}", e),
357 }
358 }
359 0x0002 => {
360 match decode_supported_fabrics(tlv_value) {
361 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
362 Err(e) => format!("{{\"error\": \"{}\"}}", e),
363 }
364 }
365 0x0003 => {
366 match decode_commissioned_fabrics(tlv_value) {
367 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
368 Err(e) => format!("{{\"error\": \"{}\"}}", e),
369 }
370 }
371 0x0004 => {
372 match decode_trusted_root_certificates(tlv_value) {
373 Ok(value) => {
374 let hex_array: Vec<String> = value.iter()
376 .map(|bytes| bytes.iter()
377 .map(|byte| format!("{:02x}", byte))
378 .collect::<String>())
379 .collect();
380 serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
381 },
382 Err(e) => format!("{{\"error\": \"{}\"}}", e),
383 }
384 }
385 0x0005 => {
386 match decode_current_fabric_index(tlv_value) {
387 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
388 Err(e) => format!("{{\"error\": \"{}\"}}", e),
389 }
390 }
391 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
392 }
393}
394
395pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
400 vec![
401 (0x0000, "NOCs"),
402 (0x0001, "Fabrics"),
403 (0x0002, "SupportedFabrics"),
404 (0x0003, "CommissionedFabrics"),
405 (0x0004, "TrustedRootCertificates"),
406 (0x0005, "CurrentFabricIndex"),
407 ]
408}
409
410#[derive(Debug, serde::Serialize)]
411pub struct AttestationResponse {
412 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
413 pub attestation_elements: Option<Vec<u8>>,
414 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
415 pub attestation_signature: Option<Vec<u8>>,
416}
417
418#[derive(Debug, serde::Serialize)]
419pub struct CertificateChainResponse {
420 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
421 pub certificate: Option<Vec<u8>>,
422}
423
424#[derive(Debug, serde::Serialize)]
425pub struct CSRResponse {
426 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
427 pub nocsr_elements: Option<Vec<u8>>,
428 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
429 pub attestation_signature: Option<Vec<u8>>,
430}
431
432#[derive(Debug, serde::Serialize)]
433pub struct NOCResponse {
434 pub status_code: Option<NodeOperationalCertStatus>,
435 pub fabric_index: Option<u8>,
436 pub debug_text: Option<String>,
437}
438
439#[derive(Debug, serde::Serialize)]
440pub struct SignVIDVerificationResponse {
441 pub fabric_index: Option<u8>,
442 pub fabric_binding_version: Option<u8>,
443 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
444 pub signature: Option<Vec<u8>>,
445}
446
447pub fn decode_attestation_response(inp: &tlv::TlvItemValue) -> anyhow::Result<AttestationResponse> {
451 if let tlv::TlvItemValue::List(_fields) = inp {
452 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
453 Ok(AttestationResponse {
454 attestation_elements: item.get_octet_string_owned(&[0]),
455 attestation_signature: item.get_octet_string_owned(&[1]),
456 })
457 } else {
458 Err(anyhow::anyhow!("Expected struct fields"))
459 }
460}
461
462pub fn decode_certificate_chain_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CertificateChainResponse> {
464 if let tlv::TlvItemValue::List(_fields) = inp {
465 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
466 Ok(CertificateChainResponse {
467 certificate: item.get_octet_string_owned(&[0]),
468 })
469 } else {
470 Err(anyhow::anyhow!("Expected struct fields"))
471 }
472}
473
474pub fn decode_csr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CSRResponse> {
476 if let tlv::TlvItemValue::List(_fields) = inp {
477 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
478 Ok(CSRResponse {
479 nocsr_elements: item.get_octet_string_owned(&[0]),
480 attestation_signature: item.get_octet_string_owned(&[1]),
481 })
482 } else {
483 Err(anyhow::anyhow!("Expected struct fields"))
484 }
485}
486
487pub fn decode_noc_response(inp: &tlv::TlvItemValue) -> anyhow::Result<NOCResponse> {
489 if let tlv::TlvItemValue::List(_fields) = inp {
490 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
491 Ok(NOCResponse {
492 status_code: item.get_int(&[0]).and_then(|v| NodeOperationalCertStatus::from_u8(v as u8)),
493 fabric_index: item.get_int(&[1]).map(|v| v as u8),
494 debug_text: item.get_string_owned(&[2]),
495 })
496 } else {
497 Err(anyhow::anyhow!("Expected struct fields"))
498 }
499}
500
501pub fn decode_sign_vid_verification_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SignVIDVerificationResponse> {
503 if let tlv::TlvItemValue::List(_fields) = inp {
504 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
505 Ok(SignVIDVerificationResponse {
506 fabric_index: item.get_int(&[0]).map(|v| v as u8),
507 fabric_binding_version: item.get_int(&[1]).map(|v| v as u8),
508 signature: item.get_octet_string_owned(&[2]),
509 })
510 } else {
511 Err(anyhow::anyhow!("Expected struct fields"))
512 }
513}
514