From 725d19187e882f4df09cd61919e06534cfd97057 Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Thu, 9 Feb 2023 15:45:25 +0530 Subject: [PATCH] Session: Include NoC CAT fields, and populate them from the CASE exchange --- matter/src/cert/mod.rs | 16 +++++++++++++++ matter/src/data_model/core.rs | 2 +- matter/src/data_model/sdm/failsafe.rs | 13 ++++++++---- matter/src/data_model/sdm/noc.rs | 8 ++++---- matter/src/secure_channel/case.rs | 11 ++++++++-- matter/src/transport/session.rs | 29 +++++++++++++++++++++++++-- matter/tests/common/im_engine.rs | 4 ++-- 7 files changed, 68 insertions(+), 15 deletions(-) diff --git a/matter/src/cert/mod.rs b/matter/src/cert/mod.rs index b3f9338..93e5e40 100644 --- a/matter/src/cert/mod.rs +++ b/matter/src/cert/mod.rs @@ -318,6 +318,18 @@ impl DistNames { } }) } + + fn u64_arr(&self, match_id: DnTags, output: &mut [u64]) { + let mut out_index = 0; + for (_, val) in self.dn.iter().filter(|(id, _)| *id == match_id as u8) { + if let DistNameValue::Uint(a) = val { + if out_index < output.len() { + output[out_index] = *a; + out_index += 1; + } + } + } + } } const PRINTABLE_STR_THRESHOLD: u8 = 0x80; @@ -543,6 +555,10 @@ impl Cert { self.subject.u64(DnTags::NodeId).ok_or(Error::NoNodeId) } + pub fn get_cat_ids(&self, output: &mut [u64]) { + self.subject.u64_arr(DnTags::NocCat, output) + } + pub fn get_fabric_id(&self) -> Result { self.subject.u64(DnTags::FabricId).ok_or(Error::NoFabricId) } diff --git a/matter/src/data_model/core.rs b/matter/src/data_model/core.rs index d2f4059..49ca031 100644 --- a/matter/src/data_model/core.rs +++ b/matter/src/data_model/core.rs @@ -221,7 +221,7 @@ impl DataModel { match sess.get_session_mode() { SessionMode::Case(c) => { let subject = AccessorSubjects::new(sess.get_peer_node_id().unwrap_or_default()); - Accessor::new(c, subject, AuthMode::Case, self.acl_mgr.clone()) + Accessor::new(c.fab_idx, subject, AuthMode::Case, self.acl_mgr.clone()) } SessionMode::Pase => Accessor::new( 0, diff --git a/matter/src/data_model/sdm/failsafe.rs b/matter/src/data_model/sdm/failsafe.rs index 12a5d11..cd3c2be 100644 --- a/matter/src/data_model/sdm/failsafe.rs +++ b/matter/src/data_model/sdm/failsafe.rs @@ -89,10 +89,15 @@ impl FailSafe { match c.noc_state { NocState::NocNotRecvd => return Err(Error::Invalid), NocState::AddNocRecvd(idx) | NocState::UpdateNocRecvd(idx) => { - if SessionMode::Case(idx) != session_mode { - error!( - "Received disarm in separate session from previous Add/Update NOC" - ); + if let SessionMode::Case(c) = session_mode { + if c.fab_idx != idx { + error!( + "Received disarm in separate session from previous Add/Update NOC" + ); + return Err(Error::Invalid); + } + } else { + error!("Received disarm in a non-CASE session"); return Err(Error::Invalid); } } diff --git a/matter/src/data_model/sdm/noc.rs b/matter/src/data_model/sdm/noc.rs index 2d3beeb..f6bb99f 100644 --- a/matter/src/data_model/sdm/noc.rs +++ b/matter/src/data_model/sdm/noc.rs @@ -248,11 +248,11 @@ impl NocCluster { .map_err(|_| IMStatusCode::InvalidDataType)?; let (result, fab_idx) = - if let SessionMode::Case(fab_idx) = cmd_req.trans.session.get_session_mode() { - if self.fabric_mgr.set_label(fab_idx, label).is_err() { - (NocStatus::LabelConflict, fab_idx) + if let SessionMode::Case(c) = cmd_req.trans.session.get_session_mode() { + if self.fabric_mgr.set_label(c.fab_idx, label).is_err() { + (NocStatus::LabelConflict, c.fab_idx) } else { - (NocStatus::Ok, fab_idx) + (NocStatus::Ok, c.fab_idx) } } else { // Update Fabric Label not allowed diff --git a/matter/src/secure_channel/case.rs b/matter/src/secure_channel/case.rs index 33c8e47..58a5593 100644 --- a/matter/src/secure_channel/case.rs +++ b/matter/src/secure_channel/case.rs @@ -33,7 +33,7 @@ use crate::{ network::Address, proto_demux::{ProtoCtx, ResponseRequired}, queue::{Msg, WorkQ}, - session::{CloneData, SessionMode}, + session::{CaseDetails, CloneData, NocCatIds, SessionMode}, }, utils::writebuf::WriteBuf, }; @@ -155,6 +155,8 @@ impl Case { } // Only now do we add this message to the TT Hash + let mut peer_catids: NocCatIds = Default::default(); + initiator_noc.get_cat_ids(&mut peer_catids); case_session.tt_hash.update(ctx.rx.as_borrow_slice())?; let clone_data = Case::get_session_clone_data( fabric.ipk.op_key(), @@ -162,6 +164,7 @@ impl Case { initiator_noc.get_node_id()?, ctx.exch_ctx.sess.get_peer_addr(), &case_session, + &peer_catids, )?; // Queue a transport mgr request to add a new session WorkQ::get()?.sync_send(Msg::NewSession(clone_data))?; @@ -281,6 +284,7 @@ impl Case { peer_nodeid: u64, peer_addr: Address, case_session: &CaseSession, + peer_catids: &NocCatIds, ) -> Result { let mut session_keys = [0_u8; 3 * crypto::SYMM_KEY_LEN_BYTES]; Case::get_session_keys( @@ -296,7 +300,10 @@ impl Case { case_session.peer_sessid, case_session.local_sessid, peer_addr, - SessionMode::Case(case_session.local_fabric_idx as u8), + SessionMode::Case(CaseDetails::new( + case_session.local_fabric_idx as u8, + peer_catids, + )), ); clone_data.dec_key.copy_from_slice(&session_keys[0..16]); diff --git a/matter/src/transport/session.rs b/matter/src/transport/session.rs index db0c845..da8d7cd 100644 --- a/matter/src/transport/session.rs +++ b/matter/src/transport/session.rs @@ -37,12 +37,28 @@ use super::{ packet::{Packet, PacketPool}, }; +pub const MAX_CAT_IDS_PER_NOC: usize = 3; const MATTER_AES128_KEY_SIZE: usize = 16; +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct CaseDetails { + pub fab_idx: u8, + pub cat_ids: [u64; MAX_CAT_IDS_PER_NOC], +} + +impl CaseDetails { + pub fn new(fab_idx: u8, cat_ids: &[u64; MAX_CAT_IDS_PER_NOC]) -> Self { + Self { + fab_idx, + cat_ids: *cat_ids, + } + } +} + #[derive(Debug, PartialEq, Copy, Clone)] pub enum SessionMode { // The Case session will capture the local fabric index - Case(u8), + Case(CaseDetails), Pase, PlainText, } @@ -53,6 +69,8 @@ impl Default for SessionMode { } } +pub type NocCatIds = [u64; MAX_CAT_IDS_PER_NOC]; + #[derive(Debug)] pub struct Session { peer_addr: Address, @@ -188,9 +206,16 @@ impl Session { self.peer_nodeid } + pub fn get_peer_cat_ids(&self) -> Option<&NocCatIds> { + match &self.mode { + SessionMode::Case(a) => Some(&a.cat_ids), + _ => None, + } + } + pub fn get_local_fabric_idx(&self) -> Option { match self.mode { - SessionMode::Case(a) => Some(a), + SessionMode::Case(a) => Some(a.fab_idx), _ => None, } } diff --git a/matter/tests/common/im_engine.rs b/matter/tests/common/im_engine.rs index 561c014..29e1c76 100644 --- a/matter/tests/common/im_engine.rs +++ b/matter/tests/common/im_engine.rs @@ -32,7 +32,6 @@ use matter::{ secure_channel::pake::PaseMgr, tlv::{TLVWriter, TagType, ToTLV}, transport::packet::Packet, - transport::proto_demux::HandleProto, transport::{ exchange::{self, Exchange, ExchangeCtx}, network::Address, @@ -40,6 +39,7 @@ use matter::{ proto_demux::ProtoCtx, session::{CloneData, SessionMgr, SessionMode}, }, + transport::{proto_demux::HandleProto, session::CaseDetails}, utils::writebuf::WriteBuf, }; use std::{ @@ -146,7 +146,7 @@ impl ImEngine { std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5542, )), - SessionMode::Case(1), + SessionMode::Case(CaseDetails::new(1, &Default::default())), ); let sess_idx = sess_mgr.clone_session(&clone_data).unwrap(); let sess = sess_mgr.get_session_handle(sess_idx);