1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11use crate::clusters::helpers::{serialize_opt_bytes_as_hex, serialize_opt_vec_bytes_as_hex};
13
14#[derive(Debug, serde::Serialize)]
17pub struct TLSCert {
18 pub caid: Option<u8>,
19 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
20 pub certificate: Option<Vec<u8>>,
21}
22
23#[derive(Debug, serde::Serialize)]
24pub struct TLSClientCertificateDetail {
25 pub ccdid: Option<u8>,
26 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
27 pub client_certificate: Option<Vec<u8>>,
28 #[serde(serialize_with = "serialize_opt_vec_bytes_as_hex")]
29 pub intermediate_certificates: Option<Vec<Vec<u8>>>,
30}
31
32pub fn encode_provision_root_certificate(certificate: Vec<u8>, caid: Option<u8>) -> anyhow::Result<Vec<u8>> {
36 let tlv = tlv::TlvItemEnc {
37 tag: 0,
38 value: tlv::TlvItemValueEnc::StructInvisible(vec![
39 (0, tlv::TlvItemValueEnc::OctetString(certificate)).into(),
40 (1, tlv::TlvItemValueEnc::UInt8(caid.unwrap_or(0))).into(),
41 ]),
42 };
43 Ok(tlv.encode()?)
44}
45
46pub fn encode_find_root_certificate(caid: Option<u8>) -> anyhow::Result<Vec<u8>> {
48 let tlv = tlv::TlvItemEnc {
49 tag: 0,
50 value: tlv::TlvItemValueEnc::StructInvisible(vec![
51 (0, tlv::TlvItemValueEnc::UInt8(caid.unwrap_or(0))).into(),
52 ]),
53 };
54 Ok(tlv.encode()?)
55}
56
57pub fn encode_lookup_root_certificate(fingerprint: Vec<u8>) -> anyhow::Result<Vec<u8>> {
59 let tlv = tlv::TlvItemEnc {
60 tag: 0,
61 value: tlv::TlvItemValueEnc::StructInvisible(vec![
62 (0, tlv::TlvItemValueEnc::OctetString(fingerprint)).into(),
63 ]),
64 };
65 Ok(tlv.encode()?)
66}
67
68pub fn encode_remove_root_certificate(caid: u8) -> anyhow::Result<Vec<u8>> {
70 let tlv = tlv::TlvItemEnc {
71 tag: 0,
72 value: tlv::TlvItemValueEnc::StructInvisible(vec![
73 (0, tlv::TlvItemValueEnc::UInt8(caid)).into(),
74 ]),
75 };
76 Ok(tlv.encode()?)
77}
78
79pub fn encode_client_csr(nonce: Vec<u8>, ccdid: Option<u8>) -> anyhow::Result<Vec<u8>> {
81 let tlv = tlv::TlvItemEnc {
82 tag: 0,
83 value: tlv::TlvItemValueEnc::StructInvisible(vec![
84 (0, tlv::TlvItemValueEnc::OctetString(nonce)).into(),
85 (1, tlv::TlvItemValueEnc::UInt8(ccdid.unwrap_or(0))).into(),
86 ]),
87 };
88 Ok(tlv.encode()?)
89}
90
91pub fn encode_provision_client_certificate(ccdid: u8, client_certificate: Vec<u8>, intermediate_certificates: Vec<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
93 let tlv = tlv::TlvItemEnc {
94 tag: 0,
95 value: tlv::TlvItemValueEnc::StructInvisible(vec![
96 (0, tlv::TlvItemValueEnc::UInt8(ccdid)).into(),
97 (1, tlv::TlvItemValueEnc::OctetString(client_certificate)).into(),
98 (2, tlv::TlvItemValueEnc::StructAnon(intermediate_certificates.into_iter().map(|v| (0, tlv::TlvItemValueEnc::OctetString(v)).into()).collect())).into(),
99 ]),
100 };
101 Ok(tlv.encode()?)
102}
103
104pub fn encode_find_client_certificate(ccdid: Option<u8>) -> anyhow::Result<Vec<u8>> {
106 let tlv = tlv::TlvItemEnc {
107 tag: 0,
108 value: tlv::TlvItemValueEnc::StructInvisible(vec![
109 (0, tlv::TlvItemValueEnc::UInt8(ccdid.unwrap_or(0))).into(),
110 ]),
111 };
112 Ok(tlv.encode()?)
113}
114
115pub fn encode_lookup_client_certificate(fingerprint: Vec<u8>) -> anyhow::Result<Vec<u8>> {
117 let tlv = tlv::TlvItemEnc {
118 tag: 0,
119 value: tlv::TlvItemValueEnc::StructInvisible(vec![
120 (0, tlv::TlvItemValueEnc::OctetString(fingerprint)).into(),
121 ]),
122 };
123 Ok(tlv.encode()?)
124}
125
126pub fn encode_remove_client_certificate(ccdid: u8) -> anyhow::Result<Vec<u8>> {
128 let tlv = tlv::TlvItemEnc {
129 tag: 0,
130 value: tlv::TlvItemValueEnc::StructInvisible(vec![
131 (0, tlv::TlvItemValueEnc::UInt8(ccdid)).into(),
132 ]),
133 };
134 Ok(tlv.encode()?)
135}
136
137pub fn decode_max_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
141 if let tlv::TlvItemValue::Int(v) = inp {
142 Ok(*v as u8)
143 } else {
144 Err(anyhow::anyhow!("Expected UInt8"))
145 }
146}
147
148pub fn decode_provisioned_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TLSCert>> {
150 let mut res = Vec::new();
151 if let tlv::TlvItemValue::List(v) = inp {
152 for item in v {
153 res.push(TLSCert {
154 caid: item.get_int(&[0]).map(|v| v as u8),
155 certificate: item.get_octet_string_owned(&[1]),
156 });
157 }
158 }
159 Ok(res)
160}
161
162pub fn decode_max_client_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
164 if let tlv::TlvItemValue::Int(v) = inp {
165 Ok(*v as u8)
166 } else {
167 Err(anyhow::anyhow!("Expected UInt8"))
168 }
169}
170
171pub fn decode_provisioned_client_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<TLSClientCertificateDetail>> {
173 let mut res = Vec::new();
174 if let tlv::TlvItemValue::List(v) = inp {
175 for item in v {
176 res.push(TLSClientCertificateDetail {
177 ccdid: item.get_int(&[0]).map(|v| v as u8),
178 client_certificate: item.get_octet_string_owned(&[1]),
179 intermediate_certificates: {
180 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
181 let items: Vec<Vec<u8>> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::OctetString(v) = &e.value { Some(v.clone()) } else { None } }).collect();
182 Some(items)
183 } else {
184 None
185 }
186 },
187 });
188 }
189 }
190 Ok(res)
191}
192
193
194pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
206 if cluster_id != 0x0801 {
208 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0801, got {}\"}}", cluster_id);
209 }
210
211 match attribute_id {
212 0x0000 => {
213 match decode_max_root_certificates(tlv_value) {
214 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
215 Err(e) => format!("{{\"error\": \"{}\"}}", e),
216 }
217 }
218 0x0001 => {
219 match decode_provisioned_root_certificates(tlv_value) {
220 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
221 Err(e) => format!("{{\"error\": \"{}\"}}", e),
222 }
223 }
224 0x0002 => {
225 match decode_max_client_certificates(tlv_value) {
226 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
227 Err(e) => format!("{{\"error\": \"{}\"}}", e),
228 }
229 }
230 0x0003 => {
231 match decode_provisioned_client_certificates(tlv_value) {
232 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
233 Err(e) => format!("{{\"error\": \"{}\"}}", e),
234 }
235 }
236 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
237 }
238}
239
240pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
245 vec![
246 (0x0000, "MaxRootCertificates"),
247 (0x0001, "ProvisionedRootCertificates"),
248 (0x0002, "MaxClientCertificates"),
249 (0x0003, "ProvisionedClientCertificates"),
250 ]
251}
252
253#[derive(Debug, serde::Serialize)]
254pub struct ProvisionRootCertificateResponse {
255 pub caid: Option<u8>,
256}
257
258#[derive(Debug, serde::Serialize)]
259pub struct FindRootCertificateResponse {
260 pub certificate_details: Option<Vec<TLSCert>>,
261}
262
263#[derive(Debug, serde::Serialize)]
264pub struct LookupRootCertificateResponse {
265 pub caid: Option<u8>,
266}
267
268#[derive(Debug, serde::Serialize)]
269pub struct ClientCSRResponse {
270 pub ccdid: Option<u8>,
271 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
272 pub csr: Option<Vec<u8>>,
273 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
274 pub nonce_signature: Option<Vec<u8>>,
275}
276
277#[derive(Debug, serde::Serialize)]
278pub struct FindClientCertificateResponse {
279 pub certificate_details: Option<Vec<TLSClientCertificateDetail>>,
280}
281
282#[derive(Debug, serde::Serialize)]
283pub struct LookupClientCertificateResponse {
284 pub ccdid: Option<u8>,
285}
286
287pub fn decode_provision_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ProvisionRootCertificateResponse> {
291 if let tlv::TlvItemValue::List(_fields) = inp {
292 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
293 Ok(ProvisionRootCertificateResponse {
294 caid: item.get_int(&[0]).map(|v| v as u8),
295 })
296 } else {
297 Err(anyhow::anyhow!("Expected struct fields"))
298 }
299}
300
301pub fn decode_find_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<FindRootCertificateResponse> {
303 if let tlv::TlvItemValue::List(_fields) = inp {
304 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
305 Ok(FindRootCertificateResponse {
306 certificate_details: {
307 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
308 let mut items = Vec::new();
309 for list_item in l {
310 items.push(TLSCert {
311 caid: list_item.get_int(&[0]).map(|v| v as u8),
312 certificate: list_item.get_octet_string_owned(&[1]),
313 });
314 }
315 Some(items)
316 } else {
317 None
318 }
319 },
320 })
321 } else {
322 Err(anyhow::anyhow!("Expected struct fields"))
323 }
324}
325
326pub fn decode_lookup_root_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<LookupRootCertificateResponse> {
328 if let tlv::TlvItemValue::List(_fields) = inp {
329 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
330 Ok(LookupRootCertificateResponse {
331 caid: item.get_int(&[0]).map(|v| v as u8),
332 })
333 } else {
334 Err(anyhow::anyhow!("Expected struct fields"))
335 }
336}
337
338pub fn decode_client_csr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ClientCSRResponse> {
340 if let tlv::TlvItemValue::List(_fields) = inp {
341 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
342 Ok(ClientCSRResponse {
343 ccdid: item.get_int(&[0]).map(|v| v as u8),
344 csr: item.get_octet_string_owned(&[1]),
345 nonce_signature: item.get_octet_string_owned(&[2]),
346 })
347 } else {
348 Err(anyhow::anyhow!("Expected struct fields"))
349 }
350}
351
352pub fn decode_find_client_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<FindClientCertificateResponse> {
354 if let tlv::TlvItemValue::List(_fields) = inp {
355 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
356 Ok(FindClientCertificateResponse {
357 certificate_details: {
358 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
359 let mut items = Vec::new();
360 for list_item in l {
361 items.push(TLSClientCertificateDetail {
362 ccdid: list_item.get_int(&[0]).map(|v| v as u8),
363 client_certificate: list_item.get_octet_string_owned(&[1]),
364 intermediate_certificates: {
365 if let Some(tlv::TlvItemValue::List(l)) = list_item.get(&[2]) {
366 let items: Vec<Vec<u8>> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::OctetString(v) = &e.value { Some(v.clone()) } else { None } }).collect();
367 Some(items)
368 } else {
369 None
370 }
371 },
372 });
373 }
374 Some(items)
375 } else {
376 None
377 }
378 },
379 })
380 } else {
381 Err(anyhow::anyhow!("Expected struct fields"))
382 }
383}
384
385pub fn decode_lookup_client_certificate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<LookupClientCertificateResponse> {
387 if let tlv::TlvItemValue::List(_fields) = inp {
388 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
389 Ok(LookupClientCertificateResponse {
390 ccdid: item.get_int(&[0]).map(|v| v as u8),
391 })
392 } else {
393 Err(anyhow::anyhow!("Expected struct fields"))
394 }
395}
396