#![allow(clippy::too_many_arguments)]
use crate::tlv;
use anyhow;
use serde_json;
use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum CertificateChainType {
Daccertificate = 1,
Paicertificate = 2,
}
impl CertificateChainType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(CertificateChainType::Daccertificate),
2 => Some(CertificateChainType::Paicertificate),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<CertificateChainType> for u8 {
fn from(val: CertificateChainType) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum NodeOperationalCertStatus {
Ok = 0,
Invalidpublickey = 1,
Invalidnodeopid = 2,
Invalidnoc = 3,
Missingcsr = 4,
Tablefull = 5,
Invalidadminsubject = 6,
Reservedforfutureuse = 7,
Reservedforfutureuse8 = 8,
Fabricconflict = 9,
Labelconflict = 10,
Invalidfabricindex = 11,
}
impl NodeOperationalCertStatus {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(NodeOperationalCertStatus::Ok),
1 => Some(NodeOperationalCertStatus::Invalidpublickey),
2 => Some(NodeOperationalCertStatus::Invalidnodeopid),
3 => Some(NodeOperationalCertStatus::Invalidnoc),
4 => Some(NodeOperationalCertStatus::Missingcsr),
5 => Some(NodeOperationalCertStatus::Tablefull),
6 => Some(NodeOperationalCertStatus::Invalidadminsubject),
7 => Some(NodeOperationalCertStatus::Reservedforfutureuse),
8 => Some(NodeOperationalCertStatus::Reservedforfutureuse8),
9 => Some(NodeOperationalCertStatus::Fabricconflict),
10 => Some(NodeOperationalCertStatus::Labelconflict),
11 => Some(NodeOperationalCertStatus::Invalidfabricindex),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<NodeOperationalCertStatus> for u8 {
fn from(val: NodeOperationalCertStatus) -> Self {
val as u8
}
}
#[derive(Debug, serde::Serialize)]
pub struct FabricDescriptor {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub root_public_key: Option<Vec<u8>>,
pub vendor_id: Option<u16>,
pub fabric_id: Option<u8>,
pub node_id: Option<u64>,
pub label: Option<String>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub vid_verification_statement: Option<Vec<u8>>,
}
#[derive(Debug, serde::Serialize)]
pub struct NOC {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub noc: Option<Vec<u8>>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub icac: Option<Vec<u8>>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub vvsc: Option<Vec<u8>>,
}
pub fn encode_attestation_request(attestation_nonce: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(attestation_nonce)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_certificate_chain_request(certificate_type: CertificateChainType) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(certificate_type.to_u8())).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_csr_request(csr_nonce: Vec<u8>, is_for_update_noc: Option<bool>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(csr_nonce)).into());
if let Some(x) = is_for_update_noc { tlv_fields.push((1, tlv::TlvItemValueEnc::Bool(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub 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>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(noc_value)).into());
if let Some(x) = icac_value { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
tlv_fields.push((2, tlv::TlvItemValueEnc::OctetString(ipk_value)).into());
tlv_fields.push((3, tlv::TlvItemValueEnc::UInt64(case_admin_subject)).into());
tlv_fields.push((4, tlv::TlvItemValueEnc::UInt16(admin_vendor_id)).into());
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub fn encode_update_noc(noc_value: Vec<u8>, icac_value: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
tlv_fields.push((0, tlv::TlvItemValueEnc::OctetString(noc_value)).into());
if let Some(x) = icac_value { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub fn encode_update_fabric_label(label: String) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::String(label)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_fabric(fabric_index: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_trusted_root_certificate(root_ca_certificate: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::OctetString(root_ca_certificate)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_set_vid_verification_statement(vendor_id: Option<u16>, vid_verification_statement: Option<Vec<u8>>, vvsc: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
if let Some(x) = vendor_id { tlv_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
if let Some(x) = vid_verification_statement { tlv_fields.push((1, tlv::TlvItemValueEnc::OctetString(x)).into()); }
if let Some(x) = vvsc { tlv_fields.push((2, tlv::TlvItemValueEnc::OctetString(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
};
Ok(tlv.encode()?)
}
pub fn encode_sign_vid_verification_request(fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(fabric_index)).into(),
(1, tlv::TlvItemValueEnc::OctetString(client_challenge)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn decode_no_cs(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NOC>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(NOC {
noc: item.get_octet_string_owned(&[1]),
icac: item.get_octet_string_owned(&[2]),
vvsc: item.get_octet_string_owned(&[3]),
});
}
}
Ok(res)
}
pub fn decode_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<FabricDescriptor>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(FabricDescriptor {
root_public_key: item.get_octet_string_owned(&[1]),
vendor_id: item.get_int(&[2]).map(|v| v as u16),
fabric_id: item.get_int(&[3]).map(|v| v as u8),
node_id: item.get_int(&[4]),
label: item.get_string_owned(&[5]),
vid_verification_statement: item.get_octet_string_owned(&[6]),
});
}
}
Ok(res)
}
pub fn decode_supported_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_commissioned_fabrics(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_trusted_root_certificates(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Vec<u8>>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
if let tlv::TlvItemValue::OctetString(o) = &item.value {
res.push(o.clone());
}
}
}
Ok(res)
}
pub fn decode_current_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u8)
} else {
Err(anyhow::anyhow!("Expected UInt8"))
}
}
pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
if cluster_id != 0x003E {
return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003E, got {}\"}}", cluster_id);
}
match attribute_id {
0x0000 => {
match decode_no_cs(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0001 => {
match decode_fabrics(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0002 => {
match decode_supported_fabrics(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0003 => {
match decode_commissioned_fabrics(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0004 => {
match decode_trusted_root_certificates(tlv_value) {
Ok(value) => {
let hex_array: Vec<String> = value.iter()
.map(|bytes| bytes.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<String>())
.collect();
serde_json::to_string(&hex_array).unwrap_or_else(|_| "null".to_string())
},
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0005 => {
match decode_current_fabric_index(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
_ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
}
}
pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
vec![
(0x0000, "NOCs"),
(0x0001, "Fabrics"),
(0x0002, "SupportedFabrics"),
(0x0003, "CommissionedFabrics"),
(0x0004, "TrustedRootCertificates"),
(0x0005, "CurrentFabricIndex"),
]
}
pub fn get_command_list() -> Vec<(u32, &'static str)> {
vec![
(0x00, "AttestationRequest"),
(0x02, "CertificateChainRequest"),
(0x04, "CSRRequest"),
(0x06, "AddNOC"),
(0x07, "UpdateNOC"),
(0x09, "UpdateFabricLabel"),
(0x0A, "RemoveFabric"),
(0x0B, "AddTrustedRootCertificate"),
(0x0C, "SetVIDVerificationStatement"),
(0x0D, "SignVIDVerificationRequest"),
]
}
pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
match cmd_id {
0x00 => Some("AttestationRequest"),
0x02 => Some("CertificateChainRequest"),
0x04 => Some("CSRRequest"),
0x06 => Some("AddNOC"),
0x07 => Some("UpdateNOC"),
0x09 => Some("UpdateFabricLabel"),
0x0A => Some("RemoveFabric"),
0x0B => Some("AddTrustedRootCertificate"),
0x0C => Some("SetVIDVerificationStatement"),
0x0D => Some("SignVIDVerificationRequest"),
_ => None,
}
}
pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
match cmd_id {
0x00 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "attestation_nonce", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
]),
0x02 => Some(vec![
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 },
]),
0x04 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "csr_nonce", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "is_for_update_noc", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
]),
0x06 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "noc_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "icac_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "ipk_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 3, name: "case_admin_subject", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 4, name: "admin_vendor_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
]),
0x07 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "noc_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "icac_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x09 => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "label", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
]),
0x0A => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "fabric_index", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
]),
0x0B => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "root_ca_certificate", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
]),
0x0C => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "vendor_id", kind: crate::clusters::codec::FieldKind::U16, optional: true, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "vid_verification_statement", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
crate::clusters::codec::CommandField { tag: 2, name: "vvsc", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
]),
0x0D => Some(vec![
crate::clusters::codec::CommandField { tag: 0, name: "fabric_index", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
crate::clusters::codec::CommandField { tag: 1, name: "client_challenge", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
]),
_ => None,
}
}
pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
match cmd_id {
0x00 => {
let attestation_nonce = crate::clusters::codec::json_util::get_octstr(args, "attestation_nonce")?;
encode_attestation_request(attestation_nonce)
}
0x02 => {
let certificate_type = {
let n = crate::clusters::codec::json_util::get_u64(args, "certificate_type")?;
CertificateChainType::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid CertificateChainType: {}", n))?
};
encode_certificate_chain_request(certificate_type)
}
0x04 => {
let csr_nonce = crate::clusters::codec::json_util::get_octstr(args, "csr_nonce")?;
let is_for_update_noc = crate::clusters::codec::json_util::get_opt_bool(args, "is_for_update_noc")?;
encode_csr_request(csr_nonce, is_for_update_noc)
}
0x06 => {
let noc_value = crate::clusters::codec::json_util::get_octstr(args, "noc_value")?;
let icac_value = crate::clusters::codec::json_util::get_opt_octstr(args, "icac_value")?;
let ipk_value = crate::clusters::codec::json_util::get_octstr(args, "ipk_value")?;
let case_admin_subject = crate::clusters::codec::json_util::get_u64(args, "case_admin_subject")?;
let admin_vendor_id = crate::clusters::codec::json_util::get_u16(args, "admin_vendor_id")?;
encode_add_noc(noc_value, icac_value, ipk_value, case_admin_subject, admin_vendor_id)
}
0x07 => {
let noc_value = crate::clusters::codec::json_util::get_octstr(args, "noc_value")?;
let icac_value = crate::clusters::codec::json_util::get_opt_octstr(args, "icac_value")?;
encode_update_noc(noc_value, icac_value)
}
0x09 => {
let label = crate::clusters::codec::json_util::get_string(args, "label")?;
encode_update_fabric_label(label)
}
0x0A => {
let fabric_index = crate::clusters::codec::json_util::get_u8(args, "fabric_index")?;
encode_remove_fabric(fabric_index)
}
0x0B => {
let root_ca_certificate = crate::clusters::codec::json_util::get_octstr(args, "root_ca_certificate")?;
encode_add_trusted_root_certificate(root_ca_certificate)
}
0x0C => {
let vendor_id = crate::clusters::codec::json_util::get_opt_u16(args, "vendor_id")?;
let vid_verification_statement = crate::clusters::codec::json_util::get_opt_octstr(args, "vid_verification_statement")?;
let vvsc = crate::clusters::codec::json_util::get_opt_octstr(args, "vvsc")?;
encode_set_vid_verification_statement(vendor_id, vid_verification_statement, vvsc)
}
0x0D => {
let fabric_index = crate::clusters::codec::json_util::get_u8(args, "fabric_index")?;
let client_challenge = crate::clusters::codec::json_util::get_octstr(args, "client_challenge")?;
encode_sign_vid_verification_request(fabric_index, client_challenge)
}
_ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
}
}
#[derive(Debug, serde::Serialize)]
pub struct AttestationResponse {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub attestation_elements: Option<Vec<u8>>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub attestation_signature: Option<Vec<u8>>,
}
#[derive(Debug, serde::Serialize)]
pub struct CertificateChainResponse {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub certificate: Option<Vec<u8>>,
}
#[derive(Debug, serde::Serialize)]
pub struct CSRResponse {
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub nocsr_elements: Option<Vec<u8>>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub attestation_signature: Option<Vec<u8>>,
}
#[derive(Debug, serde::Serialize)]
pub struct NOCResponse {
pub status_code: Option<NodeOperationalCertStatus>,
pub fabric_index: Option<u8>,
pub debug_text: Option<String>,
}
#[derive(Debug, serde::Serialize)]
pub struct SignVIDVerificationResponse {
pub fabric_index: Option<u8>,
pub fabric_binding_version: Option<u8>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub signature: Option<Vec<u8>>,
}
pub fn decode_attestation_response(inp: &tlv::TlvItemValue) -> anyhow::Result<AttestationResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(AttestationResponse {
attestation_elements: item.get_octet_string_owned(&[0]),
attestation_signature: item.get_octet_string_owned(&[1]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_certificate_chain_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CertificateChainResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(CertificateChainResponse {
certificate: item.get_octet_string_owned(&[0]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_csr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CSRResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(CSRResponse {
nocsr_elements: item.get_octet_string_owned(&[0]),
attestation_signature: item.get_octet_string_owned(&[1]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_noc_response(inp: &tlv::TlvItemValue) -> anyhow::Result<NOCResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(NOCResponse {
status_code: item.get_int(&[0]).and_then(|v| NodeOperationalCertStatus::from_u8(v as u8)),
fabric_index: item.get_int(&[1]).map(|v| v as u8),
debug_text: item.get_string_owned(&[2]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_sign_vid_verification_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SignVIDVerificationResponse> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(SignVIDVerificationResponse {
fabric_index: item.get_int(&[0]).map(|v| v as u8),
fabric_binding_version: item.get_int(&[1]).map(|v| v as u8),
signature: item.get_octet_string_owned(&[2]),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub async fn attestation_request(conn: &crate::controller::Connection, endpoint: u16, attestation_nonce: Vec<u8>) -> anyhow::Result<AttestationResponse> {
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?;
decode_attestation_response(&tlv)
}
pub async fn certificate_chain_request(conn: &crate::controller::Connection, endpoint: u16, certificate_type: CertificateChainType) -> anyhow::Result<CertificateChainResponse> {
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?;
decode_certificate_chain_response(&tlv)
}
pub async fn csr_request(conn: &crate::controller::Connection, endpoint: u16, csr_nonce: Vec<u8>, is_for_update_noc: Option<bool>) -> anyhow::Result<CSRResponse> {
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?;
decode_csr_response(&tlv)
}
pub 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> {
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?;
decode_noc_response(&tlv)
}
pub async fn update_noc(conn: &crate::controller::Connection, endpoint: u16, noc_value: Vec<u8>, icac_value: Option<Vec<u8>>) -> anyhow::Result<NOCResponse> {
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?;
decode_noc_response(&tlv)
}
pub async fn update_fabric_label(conn: &crate::controller::Connection, endpoint: u16, label: String) -> anyhow::Result<NOCResponse> {
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?;
decode_noc_response(&tlv)
}
pub async fn remove_fabric(conn: &crate::controller::Connection, endpoint: u16, fabric_index: u8) -> anyhow::Result<NOCResponse> {
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?;
decode_noc_response(&tlv)
}
pub async fn add_trusted_root_certificate(conn: &crate::controller::Connection, endpoint: u16, root_ca_certificate: Vec<u8>) -> anyhow::Result<()> {
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?;
Ok(())
}
pub 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<()> {
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?;
Ok(())
}
pub async fn sign_vid_verification_request(conn: &crate::controller::Connection, endpoint: u16, fabric_index: u8, client_challenge: Vec<u8>) -> anyhow::Result<SignVIDVerificationResponse> {
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?;
decode_sign_vid_verification_response(&tlv)
}
pub async fn read_no_cs(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NOC>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_NOCS).await?;
decode_no_cs(&tlv)
}
pub async fn read_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<FabricDescriptor>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_FABRICS).await?;
decode_fabrics(&tlv)
}
pub async fn read_supported_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_SUPPORTEDFABRICS).await?;
decode_supported_fabrics(&tlv)
}
pub async fn read_commissioned_fabrics(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_COMMISSIONEDFABRICS).await?;
decode_commissioned_fabrics(&tlv)
}
pub async fn read_trusted_root_certificates(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Vec<u8>>> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_TRUSTEDROOTCERTIFICATES).await?;
decode_trusted_root_certificates(&tlv)
}
pub async fn read_current_fabric_index(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OPERATIONAL_CREDENTIALS, crate::clusters::defs::CLUSTER_OPERATIONAL_CREDENTIALS_ATTR_ID_CURRENTFABRICINDEX).await?;
decode_current_fabric_index(&tlv)
}