diff --git a/rs-matter/Cargo.toml b/rs-matter/Cargo.toml index 98ee8976..bfc35d11 100644 --- a/rs-matter/Cargo.toml +++ b/rs-matter/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.78" [features] default = ["os", "rustcrypto"] -#default = ["os", "mbedtls"] +#default = ["os", "mbedtls"] mbedtls is broken since several months - check the root cause os = ["std", "backtrace", "critical-section/std", "embassy-sync/std", "embassy-time/std", "embassy-time/generic-queue"] std = ["alloc", "rand"] backtrace = [] diff --git a/rs-matter/src/acl.rs b/rs-matter/src/acl.rs index 35e5ce57..158bf094 100644 --- a/rs-matter/src/acl.rs +++ b/rs-matter/src/acl.rs @@ -325,9 +325,9 @@ pub struct AclEntry { } impl AclEntry { - pub fn new(privilege: Privilege, auth_mode: AuthMode) -> Self { + pub fn new(fab_idx: Option, privilege: Privilege, auth_mode: AuthMode) -> Self { Self { - fab_idx: None, + fab_idx, privilege, auth_mode, subjects: Vec::new(), @@ -335,9 +335,13 @@ impl AclEntry { } } - pub fn init(privilege: Privilege, auth_mode: AuthMode) -> impl Init { + pub fn init( + fab_idx: Option, + privilege: Privilege, + auth_mode: AuthMode, + ) -> impl Init { init!(Self { - fab_idx: None, + fab_idx, privilege, auth_mode, subjects <- Vec::init(), @@ -446,7 +450,7 @@ pub(crate) mod tests { use crate::fabric::FabricMgr; use crate::interaction_model::messages::GenericPath; use crate::utils::cell::RefCell; - use crate::utils::rand::sys_rand; + use crate::utils::rand::dummy_rand; use super::{AccessReq, Accessor, AclEntry, AuthMode, Target}; @@ -482,15 +486,15 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); // Deny adding invalid auth mode (PASE is reserved for future) - let new = AclEntry::new(Privilege::VIEW, AuthMode::Pase); + let new = AclEntry::new(None, Privilege::VIEW, AuthMode::Pase); assert!(fm.borrow_mut().acl_add(FAB_1, new).is_err()); // Deny for fab idx mismatch - let new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); assert_eq!(fm.borrow_mut().acl_add(FAB_1, new).unwrap(), 0); assert_eq!(req.allow(), false); @@ -499,11 +503,11 @@ pub(crate) mod tests { // Add fabric with ID 2 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); // Allow - let new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); assert_eq!(fm.borrow_mut().acl_add(FAB_2, new).unwrap(), 0); assert_eq!(req.allow(), true); } @@ -514,7 +518,7 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let accessor = Accessor::new(1, AccessorSubjects::new(112233), AuthMode::Case, &fm); @@ -523,13 +527,13 @@ pub(crate) mod tests { req.set_target_perms(Access::RWVA); // Deny for subject mismatch - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject(112232).unwrap(); assert_eq!(fm.borrow_mut().acl_add(FAB_1, new).unwrap(), 0); assert_eq!(req.allow(), false); // Allow for subject match - target is wildcard - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject(112233).unwrap(); assert_eq!(fm.borrow_mut().acl_add(FAB_1, new).unwrap(), 1); assert_eq!(req.allow(), true); @@ -541,7 +545,7 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let allow_cat = 0xABCD; @@ -558,20 +562,20 @@ pub(crate) mod tests { req.set_target_perms(Access::RWVA); // Deny for CAT id mismatch - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject_catid(gen_noc_cat(disallow_cat, v2)) .unwrap(); fm.borrow_mut().acl_add(FAB_1, new).unwrap(); assert_eq!(req.allow(), false); // Deny of CAT version mismatch - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject_catid(gen_noc_cat(allow_cat, v3)).unwrap(); fm.borrow_mut().acl_add(FAB_1, new).unwrap(); assert_eq!(req.allow(), false); // Allow for CAT match - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject_catid(gen_noc_cat(allow_cat, v2)).unwrap(); fm.borrow_mut().acl_add(FAB_1, new).unwrap(); assert_eq!(req.allow(), true); @@ -583,7 +587,7 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let allow_cat = 0xABCD; @@ -600,14 +604,14 @@ pub(crate) mod tests { req.set_target_perms(Access::RWVA); // Deny for CAT id mismatch - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject_catid(gen_noc_cat(disallow_cat, v2)) .unwrap(); fm.borrow_mut().acl_add(FAB_1, new).unwrap(); assert_eq!(req.allow(), false); // Allow for CAT match and version more than ACL version - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject_catid(gen_noc_cat(allow_cat, v2)).unwrap(); fm.borrow_mut().acl_add(FAB_1, new).unwrap(); assert_eq!(req.allow(), true); @@ -619,7 +623,7 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let accessor = Accessor::new(1, AccessorSubjects::new(112233), AuthMode::Case, &fm); @@ -628,7 +632,7 @@ pub(crate) mod tests { req.set_target_perms(Access::RWVA); // Deny for target mismatch - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_target(Target { cluster: Some(2), endpoint: Some(4567), @@ -639,7 +643,7 @@ pub(crate) mod tests { assert_eq!(req.allow(), false); // Allow for cluster match - subject wildcard - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_target(Target { cluster: Some(1234), endpoint: None, @@ -653,7 +657,7 @@ pub(crate) mod tests { fm.borrow_mut().get_mut(FAB_1).unwrap().acl_remove_all(); // Allow for endpoint match - subject wildcard - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_target(Target { cluster: None, endpoint: Some(1), @@ -667,7 +671,7 @@ pub(crate) mod tests { fm.borrow_mut().get_mut(FAB_1).unwrap().acl_remove_all(); // Allow for exact match - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_target(Target { cluster: Some(1234), endpoint: Some(1), @@ -685,14 +689,14 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let accessor = Accessor::new(1, AccessorSubjects::new(112233), AuthMode::Case, &fm); let path = GenericPath::new(Some(1), Some(1234), None); // Create an Exact Match ACL with View privilege - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_target(Target { cluster: Some(1234), endpoint: Some(1), @@ -708,7 +712,7 @@ pub(crate) mod tests { assert_eq!(req.allow(), false); // Create an Exact Match ACL with Admin privilege - let mut new = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); new.add_target(Target { cluster: Some(1234), endpoint: Some(1), @@ -730,12 +734,12 @@ pub(crate) mod tests { // Add fabric with ID 1 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); // Add fabric with ID 2 fm.borrow_mut() - .add_with_post_init(KeyPair::new(sys_rand).unwrap(), |_| Ok(())) + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) .unwrap(); let path = GenericPath::new(Some(1), Some(1234), None); @@ -747,12 +751,12 @@ pub(crate) mod tests { req2.set_target_perms(Access::RWVA); // Allow for subject match - target is wildcard - Fabric idx 2 - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject(112233).unwrap(); assert_eq!(fm.borrow_mut().acl_add(FAB_1, new).unwrap(), 0); // Allow for subject match - target is wildcard - Fabric idx 3 - let mut new = AclEntry::new(Privilege::VIEW, AuthMode::Case); + let mut new = AclEntry::new(None, Privilege::VIEW, AuthMode::Case); new.add_subject(112233).unwrap(); assert_eq!(fm.borrow_mut().acl_add(FAB_2, new).unwrap(), 0); diff --git a/rs-matter/src/data_model/system_model/access_control.rs b/rs-matter/src/data_model/system_model/access_control.rs index 587dc733..2b1f9434 100644 --- a/rs-matter/src/data_model/system_model/access_control.rs +++ b/rs-matter/src/data_model/system_model/access_control.rs @@ -222,249 +222,287 @@ impl ChangeNotifier<()> for AccessControlCluster { } } -// #[cfg(test)] -// mod tests { -// use crate::acl::{AclEntry, AclMgr, AuthMode}; -// use crate::data_model::objects::{AttrDataEncoder, AttrDetails, Node, Privilege}; -// use crate::data_model::system_model::access_control::Dataver; -// use crate::interaction_model::messages::ib::ListOperation; -// use crate::tlv::{ -// get_root_node_struct, TLVControl, TLVElement, TLVTag, TLVTagType, TLVValueType, TLVWriter, -// ToTLV, -// }; -// use crate::utils::storage::WriteBuf; - -// use super::AccessControlCluster; - -// use crate::acl::tests::{FAB_1, FAB_2}; - -// #[test] -// /// Add an ACL entry -// fn acl_cluster_add() { -// let mut buf: [u8; 100] = [0; 100]; -// let mut writebuf = WriteBuf::new(&mut buf); -// let mut tw = TLVWriter::new(&mut writebuf); - -// let mut acl_mgr = AclMgr::new(); -// let acl = AccessControlCluster::new(Dataver::new(0)); - -// let new = AclEntry::new(FAB_2, Privilege::VIEW, AuthMode::Case); -// new.to_tlv(&TLVTag::Anonymous, &mut tw).unwrap(); -// let data = get_root_node_struct(writebuf.as_slice()).unwrap(); - -// // Test, ACL has fabric index 2, but the accessing fabric is 1 -// // the fabric index in the TLV should be ignored and the ACL should be created with entry 1 -// let result = acl.write_acl_attr(&mut acl_mgr, &ListOperation::AddItem, &data, FAB_1); -// assert!(result.is_ok()); - -// let verifier = AclEntry::new(FAB_1, Privilege::VIEW, AuthMode::Case); -// acl_mgr -// .for_each_acl(|a| { -// assert_eq!(*a, verifier); -// Ok(()) -// }) -// .unwrap(); -// } - -// #[test] -// /// - The listindex used for edit should be relative to the current fabric -// fn acl_cluster_edit() { -// let mut buf: [u8; 100] = [0; 100]; -// let mut writebuf = WriteBuf::new(&mut buf); -// let mut tw = TLVWriter::new(&mut writebuf); - -// // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order -// let mut acl_mgr = AclMgr::new(); -// let mut verifier = [ -// AclEntry::new(FAB_2, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_1, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_2, Privilege::ADMIN, AuthMode::Case), -// ]; -// for i in &verifier { -// acl_mgr.add(i.clone()).unwrap(); -// } -// let acl = AccessControlCluster::new(Dataver::new(0)); - -// let new = AclEntry::new(FAB_2, Privilege::VIEW, AuthMode::Case); -// new.to_tlv(&TLVTag::Anonymous, &mut tw).unwrap(); -// let data = get_root_node_struct(writebuf.as_slice()).unwrap(); - -// // Test, Edit Fabric 2's index 1 - with accessing fabring as 2 - allow -// let result = acl.write_acl_attr(&mut acl_mgr, &ListOperation::EditItem(1), &data, FAB_2); -// // Fabric 2's index 1, is actually our index 2, update the verifier -// verifier[2] = new; -// assert!(result.is_ok()); - -// // Also validate in the acl_mgr that the entries are in the right order -// let mut index = 0; -// acl_mgr -// .for_each_acl(|a| { -// assert_eq!(*a, verifier[index]); -// index += 1; -// Ok(()) -// }) -// .unwrap(); -// } - -// #[test] -// /// - The listindex used for delete should be relative to the current fabric -// fn acl_cluster_delete() { -// // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order -// let mut acl_mgr = AclMgr::new(); -// let input = [ -// AclEntry::new(FAB_2, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_1, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_2, Privilege::ADMIN, AuthMode::Case), -// ]; -// for i in &input { -// acl_mgr.add(i.clone()).unwrap(); -// } -// let acl = AccessControlCluster::new(Dataver::new(0)); -// // data is don't-care actually -// let data = &[TLVControl::new(TLVTagType::Anonymous, TLVValueType::Null).as_raw()]; -// let data = TLVElement::new(data.as_slice()); - -// // Test , Delete Fabric 1's index 0 -// let result = acl.write_acl_attr(&mut acl_mgr, &ListOperation::DeleteItem(0), &data, FAB_1); -// assert!(result.is_ok()); - -// let verifier = [input[0].clone(), input[2].clone()]; -// // Also validate in the acl_mgr that the entries are in the right order -// let mut index = 0; -// acl_mgr -// .for_each_acl(|a| { -// assert_eq!(*a, verifier[index]); -// index += 1; -// Ok(()) -// }) -// .unwrap(); -// } - -// #[test] -// /// - acl read with and without fabric filtering -// fn acl_cluster_read() { -// let mut buf: [u8; 100] = [0; 100]; -// let mut writebuf = WriteBuf::new(&mut buf); - -// // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order -// let mut acl_mgr = AclMgr::new(); -// let input = [ -// AclEntry::new(FAB_2, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_1, Privilege::VIEW, AuthMode::Case), -// AclEntry::new(FAB_2, Privilege::ADMIN, AuthMode::Case), -// ]; -// for i in input { -// acl_mgr.add(i).unwrap(); -// } -// let acl = AccessControlCluster::new(Dataver::new(0)); -// // Test 1, all 3 entries are read in the response without fabric filtering -// { -// let attr = AttrDetails { -// node: &Node { -// id: 0, -// endpoints: &[], -// }, -// endpoint_id: 0, -// cluster_id: 0, -// attr_id: 0, -// list_index: None, -// fab_idx: 1, -// fab_filter: false, -// dataver: None, -// wildcard: false, -// }; - -// let mut tw = TLVWriter::new(&mut writebuf); -// let encoder = AttrDataEncoder::new(&attr, &mut tw); - -// acl.read_acl_attr(&acl_mgr, &attr, encoder).unwrap(); -// assert_eq!( -// // &[ -// // 21, 53, 1, 36, 0, 0, 55, 1, 24, 54, 2, 21, 36, 1, 1, 36, 2, 2, 54, 3, 24, 54, -// // 4, 24, 36, 254, 2, 24, 21, 36, 1, 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, -// // 1, 24, 21, 36, 1, 5, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 2, 24, 24, 24, -// // 24 -// // ], -// &[ -// 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, -// 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 2, 24, 21, 36, 1, 1, 36, 2, 2, 54, -// 3, 24, 54, 4, 24, 36, 254, 1, 24, 21, 36, 1, 5, 36, 2, 2, 54, 3, 24, 54, 4, 24, -// 36, 254, 2, 24, 24, 24, 24 -// ], -// writebuf.as_slice() -// ); -// } -// writebuf.reset(); - -// // Test 2, only single entry is read in the response with fabric filtering and fabric idx 1 -// { -// let attr = AttrDetails { -// node: &Node { -// id: 0, -// endpoints: &[], -// }, -// endpoint_id: 0, -// cluster_id: 0, -// attr_id: 0, -// list_index: None, -// fab_idx: 1, -// fab_filter: true, -// dataver: None, -// wildcard: false, -// }; - -// let mut tw = TLVWriter::new(&mut writebuf); -// let encoder = AttrDataEncoder::new(&attr, &mut tw); - -// acl.read_acl_attr(&acl_mgr, &attr, encoder).unwrap(); -// assert_eq!( -// // &[ -// // 21, 53, 1, 36, 0, 0, 55, 1, 24, 54, 2, 21, 36, 1, 1, 36, 2, 2, 54, 3, 24, 54, -// // 4, 24, 36, 254, 1, 24, 24, 24, 24 -// // ], -// &[ -// 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, -// 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 1, 24, 24, 24, 24 -// ], -// writebuf.as_slice() -// ); -// } -// writebuf.reset(); - -// // Test 3, only single entry is read in the response with fabric filtering and fabric idx 2 -// { -// let attr = AttrDetails { -// node: &Node { -// id: 0, -// endpoints: &[], -// }, -// endpoint_id: 0, -// cluster_id: 0, -// attr_id: 0, -// list_index: None, -// fab_idx: 2, -// fab_filter: true, -// dataver: None, -// wildcard: false, -// }; - -// let mut tw = TLVWriter::new(&mut writebuf); -// let encoder = AttrDataEncoder::new(&attr, &mut tw); - -// acl.read_acl_attr(&acl_mgr, &attr, encoder).unwrap(); -// assert_eq!( -// // &[ -// // 21, 53, 1, 36, 0, 0, 55, 1, 24, 54, 2, 21, 36, 1, 1, 36, 2, 2, 54, 3, 24, 54, -// // 4, 24, 36, 254, 2, 24, 21, 36, 1, 5, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, -// // 2, 24, 24, 24, 24 -// // ], -// &[ -// 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, -// 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 2, 24, 21, 36, 1, 5, 36, 2, 2, 54, -// 3, 24, 54, 4, 24, 36, 254, 2, 24, 24, 24, 24 -// ], -// writebuf.as_slice() -// ); -// } -// } -// } +#[cfg(test)] +mod tests { + use crate::acl::{AclEntry, AuthMode}; + use crate::crypto::KeyPair; + use crate::data_model::objects::{AttrDataEncoder, AttrDetails, Node, Privilege}; + use crate::data_model::system_model::access_control::Dataver; + use crate::fabric::FabricMgr; + use crate::interaction_model::messages::ib::ListOperation; + use crate::tlv::{ + get_root_node_struct, TLVControl, TLVElement, TLVTag, TLVTagType, TLVValueType, TLVWriter, + ToTLV, + }; + use crate::utils::rand::dummy_rand; + use crate::utils::storage::WriteBuf; + + use super::AccessControlCluster; + + use crate::acl::tests::{FAB_1, FAB_2}; + + #[test] + /// Add an ACL entry + fn acl_cluster_add() { + let mut buf: [u8; 100] = [0; 100]; + let mut writebuf = WriteBuf::new(&mut buf); + let mut tw = TLVWriter::new(&mut writebuf); + + let mut fab_mgr = FabricMgr::new(); + + // Add fabric with ID 1 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + let acl = AccessControlCluster::new(Dataver::new(0)); + + let new = AclEntry::new(Some(FAB_2), Privilege::VIEW, AuthMode::Case); + + new.to_tlv(&TLVTag::Anonymous, &mut tw).unwrap(); + let data = get_root_node_struct(writebuf.as_slice()).unwrap(); + + // Test, ACL has fabric index 2, but the accessing fabric is 1 + // the fabric index in the TLV should be ignored and the ACL should be created with entry 1 + let result = acl.write_acl_attr(&mut fab_mgr, &ListOperation::AddItem, &data, FAB_1); + assert!(result.is_ok()); + + let verifier = AclEntry::new(Some(FAB_1), Privilege::VIEW, AuthMode::Case); + for fabric in fab_mgr.iter() { + for a in fabric.acl_iter() { + assert_eq!(*a, verifier); + } + } + } + + #[test] + /// - The listindex used for edit should be relative to the current fabric + fn acl_cluster_edit() { + let mut buf: [u8; 100] = [0; 100]; + let mut writebuf = WriteBuf::new(&mut buf); + let mut tw = TLVWriter::new(&mut writebuf); + + let mut fab_mgr = FabricMgr::new(); + + // Add fabric with ID 1 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add fabric with ID 2 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order + let mut verifier = [ + AclEntry::new(Some(FAB_2), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_1), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_2), Privilege::ADMIN, AuthMode::Case), + ]; + for i in &verifier { + fab_mgr.acl_add(i.fab_idx.unwrap(), i.clone()).unwrap(); + } + let acl = AccessControlCluster::new(Dataver::new(0)); + + let new = AclEntry::new(Some(FAB_2), Privilege::VIEW, AuthMode::Case); + new.to_tlv(&TLVTag::Anonymous, &mut tw).unwrap(); + let data = get_root_node_struct(writebuf.as_slice()).unwrap(); + + // Test, Edit Fabric 2's index 1 - with accessing fabric as 2 - allow + let result = acl.write_acl_attr(&mut fab_mgr, &ListOperation::EditItem(1), &data, FAB_2); + // Fabric 2's index 1, is actually our index 2, update the verifier + verifier[2] = new; + assert!(result.is_ok()); + + // Also validate in the fab_mgr that the entries are in the right order + assert_eq!(fab_mgr.get(FAB_1).unwrap().acl_iter().count(), 1); + assert_eq!( + fab_mgr.get(FAB_1).unwrap().acl_iter().next().unwrap(), + &verifier[1] + ); + assert_eq!(fab_mgr.get(FAB_2).unwrap().acl_iter().count(), 2); + assert_eq!( + fab_mgr.get(FAB_2).unwrap().acl_iter().next().unwrap(), + &verifier[0] + ); + assert_eq!( + fab_mgr + .get(FAB_2) + .unwrap() + .acl_iter() + .skip(1) + .next() + .unwrap(), + &verifier[2] + ); + } + + #[test] + /// - The listindex used for delete should be relative to the current fabric + fn acl_cluster_delete() { + let mut fab_mgr = FabricMgr::new(); + + // Add fabric with ID 1 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add fabric with ID 2 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order + let input = [ + AclEntry::new(Some(FAB_2), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_1), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_2), Privilege::ADMIN, AuthMode::Case), + ]; + for i in &input { + fab_mgr.acl_add(i.fab_idx.unwrap(), i.clone()).unwrap(); + } + let acl = AccessControlCluster::new(Dataver::new(0)); + // data is don't-care actually + let data = &[TLVControl::new(TLVTagType::Anonymous, TLVValueType::Null).as_raw()]; + let data = TLVElement::new(data.as_slice()); + + // Test: delete Fabric 1's index 0 + let result = acl.write_acl_attr(&mut fab_mgr, &ListOperation::DeleteItem(0), &data, FAB_1); + assert!(result.is_ok()); + + let verifier = [input[0].clone(), input[2].clone()]; + // Also validate in the fab_mgr that the entries are in the right order + let mut index = 0; + for fabric in fab_mgr.iter() { + for a in fabric.acl_iter() { + assert_eq!(*a, verifier[index]); + index += 1; + } + } + } + + #[test] + /// - acl read with and without fabric filtering + fn acl_cluster_read() { + let mut buf: [u8; 100] = [0; 100]; + let mut writebuf = WriteBuf::new(&mut buf); + + let mut fab_mgr = FabricMgr::new(); + + // Add fabric with ID 1 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add fabric with ID 2 + fab_mgr + .add_with_post_init(KeyPair::new(dummy_rand).unwrap(), |_| Ok(())) + .unwrap(); + + // Add 3 ACLs, belonging to fabric index 2, 1 and 2, in that order + let input = [ + AclEntry::new(Some(FAB_2), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_1), Privilege::VIEW, AuthMode::Case), + AclEntry::new(Some(FAB_2), Privilege::ADMIN, AuthMode::Case), + ]; + for i in input { + fab_mgr.acl_add(i.fab_idx.unwrap(), i).unwrap(); + } + let acl = AccessControlCluster::new(Dataver::new(0)); + // Test 1, all 3 entries are read in the response without fabric filtering + { + let attr = AttrDetails { + node: &Node { + id: 0, + endpoints: &[], + }, + endpoint_id: 0, + cluster_id: 0, + attr_id: 0, + list_index: None, + fab_idx: 1, + fab_filter: false, + dataver: None, + wildcard: false, + }; + + let mut tw = TLVWriter::new(&mut writebuf); + let encoder = AttrDataEncoder::new(&attr, &mut tw); + + acl.read_acl_attr(&fab_mgr, &attr, encoder).unwrap(); + assert_eq!( + &[ + 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, + 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 1, 24, 21, 36, 1, 1, 36, 2, 2, 54, + 3, 24, 54, 4, 24, 36, 254, 2, 24, 21, 36, 1, 5, 36, 2, 2, 54, 3, 24, 54, 4, 24, + 36, 254, 2, 24, 24, 24, 24 + ], + writebuf.as_slice() + ); + } + writebuf.reset(); + + // Test 2, only single entry is read in the response with fabric filtering and fabric idx 1 + { + let attr = AttrDetails { + node: &Node { + id: 0, + endpoints: &[], + }, + endpoint_id: 0, + cluster_id: 0, + attr_id: 0, + list_index: None, + fab_idx: 1, + fab_filter: true, + dataver: None, + wildcard: false, + }; + + let mut tw = TLVWriter::new(&mut writebuf); + let encoder = AttrDataEncoder::new(&attr, &mut tw); + + acl.read_acl_attr(&fab_mgr, &attr, encoder).unwrap(); + assert_eq!( + &[ + 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, + 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 1, 24, 24, 24, 24 + ], + writebuf.as_slice() + ); + } + writebuf.reset(); + + // Test 3, only single entry is read in the response with fabric filtering and fabric idx 2 + { + let attr = AttrDetails { + node: &Node { + id: 0, + endpoints: &[], + }, + endpoint_id: 0, + cluster_id: 0, + attr_id: 0, + list_index: None, + fab_idx: 2, + fab_filter: true, + dataver: None, + wildcard: false, + }; + + let mut tw = TLVWriter::new(&mut writebuf); + let encoder = AttrDataEncoder::new(&attr, &mut tw); + + acl.read_acl_attr(&fab_mgr, &attr, encoder).unwrap(); + assert_eq!( + &[ + 21, 53, 1, 36, 0, 0, 55, 1, 36, 2, 0, 36, 3, 0, 36, 4, 0, 24, 54, 2, 21, 36, 1, + 1, 36, 2, 2, 54, 3, 24, 54, 4, 24, 36, 254, 2, 24, 21, 36, 1, 5, 36, 2, 2, 54, + 3, 24, 54, 4, 24, 36, 254, 2, 24, 24, 24, 24 + ], + writebuf.as_slice() + ); + } + } +} diff --git a/rs-matter/src/fabric.rs b/rs-matter/src/fabric.rs index edbb02dc..7b11bfe7 100644 --- a/rs-matter/src/fabric.rs +++ b/rs-matter/src/fabric.rs @@ -173,7 +173,7 @@ impl Fabric { if let Some(case_admin_subject) = case_admin_subject { self.acl.clear(); self.acl.push_init( - AclEntry::init(Privilege::ADMIN, AuthMode::Case) + AclEntry::init(None, Privilege::ADMIN, AuthMode::Case) .into_fallible() .chain(|e| { e.fab_idx = Some(self.fab_idx); diff --git a/rs-matter/src/utils/rand.rs b/rs-matter/src/utils/rand.rs index 59a89727..392b9abc 100644 --- a/rs-matter/src/utils/rand.rs +++ b/rs-matter/src/utils/rand.rs @@ -1,6 +1,12 @@ pub type Rand = fn(&mut [u8]); -pub fn dummy_rand(_buf: &mut [u8]) {} +pub fn dummy_rand(buf: &mut [u8]) { + // rust-crypto's KeyPair::new(rand) blocks on a zeroed buffer + // Trick it a bit, as we use `dummy_rand` in our no_std tests + for i in 0..buf.len() { + buf[i] = (i % 256) as u8; + } +} #[cfg(feature = "std")] pub fn sys_rand(buf: &mut [u8]) { diff --git a/rs-matter/tests/common/e2e.rs b/rs-matter/tests/common/e2e.rs index f7854e89..ee9c14f1 100644 --- a/rs-matter/tests/common/e2e.rs +++ b/rs-matter/tests/common/e2e.rs @@ -133,7 +133,7 @@ impl E2eRunner { /// Add a default ACL entry to the remote (tested) Matter instance. pub fn add_default_acl(&self) { // Only allow the standard peer node id of the IM Engine - let mut default_acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut default_acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); default_acl.add_subject(Self::PEER_ID).unwrap(); self.matter .fabric_mgr diff --git a/rs-matter/tests/data_model/acl_and_dataver.rs b/rs-matter/tests/data_model/acl_and_dataver.rs index 6e0773ec..cb34a7cb 100644 --- a/rs-matter/tests/data_model/acl_and_dataver.rs +++ b/rs-matter/tests/data_model/acl_and_dataver.rs @@ -67,7 +67,7 @@ fn wc_read_attribute() { im.handle_read_reqs(&handler, &[AttrPath::new(&wc_att1)], &[]); // Add ACL to allow our peer to only access endpoint 0 - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); acl.add_target(Target::new(Some(0), None, None)).unwrap(); im.matter @@ -84,7 +84,7 @@ fn wc_read_attribute() { ); // Add ACL to allow our peer to also access endpoint 1 - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); acl.add_target(Target::new(Some(1), None, None)).unwrap(); im.matter @@ -125,7 +125,7 @@ fn exact_read_attribute() { im.handle_read_reqs(&handler, input, expected); // Add ACL to allow our peer to access any endpoint - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); im.matter .fabric_mgr @@ -178,7 +178,7 @@ fn wc_write_attribute() { ); // Add ACL to allow our peer to access one endpoint - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); acl.add_target(Target::new(Some(0), None, None)).unwrap(); im.matter @@ -201,7 +201,7 @@ fn wc_write_attribute() { ); // Add ACL to allow our peer to access another endpoint - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); acl.add_target(Target::new(Some(1), None, None)).unwrap(); im.matter @@ -257,7 +257,7 @@ fn exact_write_attribute() { ); // Add ACL to allow our peer to access any endpoint - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); im.matter .fabric_mgr @@ -309,7 +309,7 @@ fn exact_write_attribute_noc_cat() { ); // Add ACL to allow our peer to access any endpoint - let mut acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); acl.add_subject_catid(cat_in_acl).unwrap(); im.matter .fabric_mgr @@ -339,7 +339,7 @@ fn insufficient_perms_write() { let handler = im.handler(); // Add ACL to allow our peer with only OPERATE permission - let mut acl = AclEntry::new(Privilege::OPERATE, AuthMode::Case); + let mut acl = AclEntry::new(None, Privilege::OPERATE, AuthMode::Case); acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); acl.add_target(Target::new(Some(0), None, None)).unwrap(); im.matter @@ -398,7 +398,7 @@ fn write_with_runtime_acl_add() { let input0 = TestAttrData::new(None, AttrPath::new(&ep0_att), &val0 as _); // Create ACL to allow our peer ADMIN on everything - let mut allow_acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut allow_acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); allow_acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); let acl_att = GenericPath::new( @@ -409,7 +409,7 @@ fn write_with_runtime_acl_add() { let acl_input = TestAttrData::new(None, AttrPath::new(&acl_att), &allow_acl); // Create ACL that only allows write to the ACL Cluster - let mut basic_acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let mut basic_acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); basic_acl.add_subject(IM_ENGINE_PEER_ID).unwrap(); basic_acl .add_target(Target::new(Some(0), Some(access_control::ID), None)) @@ -448,7 +448,7 @@ fn test_read_data_ver() { let handler = im.handler(); // Add ACL to allow our peer with only OPERATE permission - let acl = AclEntry::new(Privilege::OPERATE, AuthMode::Case); + let acl = AclEntry::new(None, Privilege::OPERATE, AuthMode::Case); im.matter .fabric_mgr .borrow_mut() @@ -545,7 +545,7 @@ fn test_write_data_ver() { let handler = im.handler(); // Add ACL to allow our peer with only OPERATE permission - let acl = AclEntry::new(Privilege::ADMIN, AuthMode::Case); + let acl = AclEntry::new(None, Privilege::ADMIN, AuthMode::Case); im.matter .fabric_mgr .borrow_mut()