From 95c74ec2983a44e191e17aca90471728f53c0d88 Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Tue, 10 Jan 2023 10:48:20 +0530 Subject: [PATCH] pase: Split out a separate Pase Mgr - This is required so that the AdminCommissioning Cluster has a reference to the Pase Mgr - The Cluster can then open commissioning window accordingly - Right now, for the error paths in the PASE/CASE sessions, I have set ResponseRequired to No, but I am not quite sure if this is the expected behaviour. Need to check --- matter/src/core.rs | 8 ++- matter/src/secure_channel/case.rs | 24 +++---- matter/src/secure_channel/core.rs | 100 ++++-------------------------- matter/src/secure_channel/pake.rs | 83 ++++++++++++++++++++++++- 4 files changed, 112 insertions(+), 103 deletions(-) diff --git a/matter/src/core.rs b/matter/src/core.rs index 9dedb6b..71eb6c3 100644 --- a/matter/src/core.rs +++ b/matter/src/core.rs @@ -25,7 +25,7 @@ use crate::{ fabric::FabricMgr, interaction_model::InteractionModel, mdns::Mdns, - secure_channel::{core::SecureChannel, spake2p::VerifierData}, + secure_channel::{core::SecureChannel, pake::PaseMgr, spake2p::VerifierData}, transport, }; use std::sync::Arc; @@ -72,11 +72,13 @@ impl Matter { let interaction_model = Box::new(InteractionModel::new(Box::new(matter.data_model.clone()))); matter.transport_mgr.register_protocol(interaction_model)?; - let mut secure_channel = Box::new(SecureChannel::new(matter.fabric_mgr.clone())); + + let mut pase = PaseMgr::new(); if open_comm_window { - secure_channel.open_comm_window(dev_comm.verifier, dev_comm.discriminator)?; + pase.enable_pase_session(dev_comm.verifier, dev_comm.discriminator)?; } + let secure_channel = Box::new(SecureChannel::new(pase.clone(), matter.fabric_mgr.clone())); matter.transport_mgr.register_protocol(secure_channel)?; Ok(matter) } diff --git a/matter/src/secure_channel/case.rs b/matter/src/secure_channel/case.rs index 75d1fc9..33c8e47 100644 --- a/matter/src/secure_channel/case.rs +++ b/matter/src/secure_channel/case.rs @@ -26,12 +26,12 @@ use crate::{ crypto::{self, CryptoKeyPair, KeyPair, Sha256}, error::Error, fabric::{Fabric, FabricMgr, FabricMgrInner}, - secure_channel::common, secure_channel::common::SCStatusCodes, + secure_channel::common::{self, OpCode}, tlv::{get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType}, transport::{ network::Address, - proto_demux::ProtoCtx, + proto_demux::{ProtoCtx, ResponseRequired}, queue::{Msg, WorkQ}, session::{CloneData, SessionMode}, }, @@ -78,7 +78,7 @@ impl Case { Self { fabric_mgr } } - pub fn handle_casesigma3(&mut self, ctx: &mut ProtoCtx) -> Result<(), Error> { + pub fn casesigma3_handler(&mut self, ctx: &mut ProtoCtx) -> Result { let mut case_session = ctx .exch_ctx .exch @@ -97,7 +97,7 @@ impl Case { None, )?; ctx.exch_ctx.exch.close(); - return Ok(()); + return Ok(ResponseRequired::Yes); } // Safe to unwrap here let fabric = fabric.as_ref().as_ref().unwrap(); @@ -132,7 +132,7 @@ impl Case { None, )?; ctx.exch_ctx.exch.close(); - return Ok(()); + return Ok(ResponseRequired::Yes); } if Case::validate_sigma3_sign( @@ -151,7 +151,7 @@ impl Case { None, )?; ctx.exch_ctx.exch.close(); - return Ok(()); + return Ok(ResponseRequired::Yes); } // Only now do we add this message to the TT Hash @@ -174,10 +174,12 @@ impl Case { ctx.exch_ctx.exch.clear_data_boxed(); ctx.exch_ctx.exch.close(); - Ok(()) + Ok(ResponseRequired::Yes) } - pub fn handle_casesigma1(&mut self, ctx: &mut ProtoCtx) -> Result<(), Error> { + pub fn casesigma1_handler(&mut self, ctx: &mut ProtoCtx) -> Result { + ctx.tx.set_proto_opcode(OpCode::CASESigma2 as u8); + let rx_buf = ctx.rx.as_borrow_slice(); let root = get_root_node_struct(rx_buf)?; let r = Sigma1Req::from_tlv(&root)?; @@ -193,7 +195,7 @@ impl Case { None, )?; ctx.exch_ctx.exch.close(); - return Ok(()); + return Ok(ResponseRequired::Yes); } let local_sessid = ctx.exch_ctx.sess.reserve_new_sess_id(); @@ -239,7 +241,7 @@ impl Case { None, )?; ctx.exch_ctx.exch.close(); - return Ok(()); + return Ok(ResponseRequired::Yes); } let sign_len = Case::get_sigma2_sign( @@ -270,7 +272,7 @@ impl Case { tw.end_container()?; case_session.tt_hash.update(ctx.tx.as_borrow_slice())?; ctx.exch_ctx.exch.set_data_boxed(case_session); - Ok(()) + Ok(ResponseRequired::Yes) } fn get_session_clone_data( diff --git a/matter/src/secure_channel/core.rs b/matter/src/secure_channel/core.rs index c5f04a8..8d11134 100644 --- a/matter/src/secure_channel/core.rs +++ b/matter/src/secure_channel/core.rs @@ -20,105 +20,30 @@ use std::sync::Arc; use crate::{ error::*, fabric::FabricMgr, - mdns::{self, Mdns}, - secure_channel::{common::*, pake::PAKE}, - sys::SysMdnsService, + secure_channel::common::*, tlv, transport::proto_demux::{self, ProtoCtx, ResponseRequired}, }; use log::{error, info}; use num; -use rand::prelude::*; -use super::{case::Case, spake2p::VerifierData}; +use super::{case::Case, pake::PaseMgr}; /* Handle messages related to the Secure Channel */ pub struct SecureChannel { case: Case, - pake: Option<(PAKE, SysMdnsService)>, + pase: PaseMgr, } impl SecureChannel { - pub fn new(fabric_mgr: Arc) -> SecureChannel { + pub fn new(pase: PaseMgr, fabric_mgr: Arc) -> SecureChannel { SecureChannel { - pake: None, + pase, case: Case::new(fabric_mgr), } } - - pub fn open_comm_window( - &mut self, - verifier: VerifierData, - discriminator: u16, - ) -> Result<(), Error> { - let name: u64 = rand::thread_rng().gen_range(0..0xFFFFFFFFFFFFFFFF); - let name = format!("{:016X}", name); - let mdns = Mdns::get()? - .publish_service(&name, mdns::ServiceMode::Commissionable(discriminator))?; - self.pake = Some((PAKE::new(verifier), mdns)); - Ok(()) - } - - pub fn close_comm_window(&mut self) { - self.pake = None; - } - - fn mrpstandaloneack_handler(&mut self, _ctx: &mut ProtoCtx) -> Result { - info!("In MRP StandAlone ACK Handler"); - Ok(ResponseRequired::No) - } - - fn pbkdfparamreq_handler(&mut self, ctx: &mut ProtoCtx) -> Result { - info!("In PBKDF Param Request Handler"); - ctx.tx.set_proto_opcode(OpCode::PBKDFParamResponse as u8); - if let Some((pake, _)) = &mut self.pake { - pake.handle_pbkdfparamrequest(ctx)?; - } else { - error!("PASE Not enabled"); - create_sc_status_report(&mut ctx.tx, SCStatusCodes::InvalidParameter, None)?; - } - Ok(ResponseRequired::Yes) - } - - fn pasepake1_handler(&mut self, ctx: &mut ProtoCtx) -> Result { - info!("In PASE Pake1 Handler"); - ctx.tx.set_proto_opcode(OpCode::PASEPake2 as u8); - if let Some((pake, _)) = &mut self.pake { - pake.handle_pasepake1(ctx)?; - } else { - error!("PASE Not enabled"); - create_sc_status_report(&mut ctx.tx, SCStatusCodes::InvalidParameter, None)?; - } - Ok(ResponseRequired::Yes) - } - - fn pasepake3_handler(&mut self, ctx: &mut ProtoCtx) -> Result { - info!("In PASE Pake3 Handler"); - if let Some((pake, _)) = &mut self.pake { - pake.handle_pasepake3(ctx)?; - // TODO: Currently we assume that PAKE is not successful and reset the PAKE object - self.pake = None; - } else { - error!("PASE Not enabled"); - create_sc_status_report(&mut ctx.tx, SCStatusCodes::InvalidParameter, None)?; - } - Ok(ResponseRequired::Yes) - } - - fn casesigma1_handler(&mut self, ctx: &mut ProtoCtx) -> Result { - info!("In CASE Sigma1 Handler"); - ctx.tx.set_proto_opcode(OpCode::CASESigma2 as u8); - self.case.handle_casesigma1(ctx)?; - Ok(ResponseRequired::Yes) - } - - fn casesigma3_handler(&mut self, ctx: &mut ProtoCtx) -> Result { - info!("In CASE Sigma3 Handler"); - self.case.handle_casesigma3(ctx)?; - Ok(ResponseRequired::Yes) - } } impl proto_demux::HandleProto for SecureChannel { @@ -126,15 +51,16 @@ impl proto_demux::HandleProto for SecureChannel { let proto_opcode: OpCode = num::FromPrimitive::from_u8(ctx.rx.get_proto_opcode()).ok_or(Error::Invalid)?; ctx.tx.set_proto_id(PROTO_ID_SECURE_CHANNEL as u16); - info!("Received Data"); + info!("Received Opcode: {:?}", proto_opcode); + info!("Received Data:"); tlv::print_tlv_list(ctx.rx.as_borrow_slice()); let result = match proto_opcode { - OpCode::MRPStandAloneAck => self.mrpstandaloneack_handler(ctx), - OpCode::PBKDFParamRequest => self.pbkdfparamreq_handler(ctx), - OpCode::PASEPake1 => self.pasepake1_handler(ctx), - OpCode::PASEPake3 => self.pasepake3_handler(ctx), - OpCode::CASESigma1 => self.casesigma1_handler(ctx), - OpCode::CASESigma3 => self.casesigma3_handler(ctx), + OpCode::MRPStandAloneAck => Ok(ResponseRequired::No), + OpCode::PBKDFParamRequest => self.pase.pbkdfparamreq_handler(ctx), + OpCode::PASEPake1 => self.pase.pasepake1_handler(ctx), + OpCode::PASEPake3 => self.pase.pasepake3_handler(ctx), + OpCode::CASESigma1 => self.case.casesigma1_handler(ctx), + OpCode::CASESigma3 => self.case.casesigma3_handler(ctx), _ => { error!("OpCode Not Handled: {:?}", proto_opcode); Err(Error::InvalidOpcode) diff --git a/matter/src/secure_channel/pake.rs b/matter/src/secure_channel/pake.rs index 3163f56..2bf7acd 100644 --- a/matter/src/secure_channel/pake.rs +++ b/matter/src/secure_channel/pake.rs @@ -15,7 +15,10 @@ * limitations under the License. */ -use std::time::{Duration, SystemTime}; +use std::{ + sync::{Arc, Mutex}, + time::{Duration, SystemTime}, +}; use super::{ common::{create_sc_status_report, SCStatusCodes}, @@ -24,11 +27,14 @@ use super::{ use crate::{ crypto, error::Error, + mdns::{self, Mdns}, + secure_channel::common::OpCode, + sys::SysMdnsService, tlv::{self, get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType, ToTLV}, transport::{ exchange::ExchangeCtx, network::Address, - proto_demux::ProtoCtx, + proto_demux::{ProtoCtx, ResponseRequired}, queue::{Msg, WorkQ}, session::{CloneData, SessionMode}, }, @@ -36,6 +42,79 @@ use crate::{ use log::{error, info}; use rand::prelude::*; +enum PaseSessionState { + Enabled(PAKE, SysMdnsService), + Disabled, +} + +pub struct PaseMgrInternal { + state: PaseSessionState, +} + +#[derive(Clone)] +// Could this lock be avoided? +pub struct PaseMgr(Arc>); + +impl PaseMgr { + pub fn new() -> Self { + Self(Arc::new(Mutex::new(PaseMgrInternal { + state: PaseSessionState::Disabled, + }))) + } + + pub fn enable_pase_session( + &mut self, + verifier: VerifierData, + discriminator: u16, + ) -> Result<(), Error> { + let mut s = self.0.lock().unwrap(); + let name: u64 = rand::thread_rng().gen_range(0..0xFFFFFFFFFFFFFFFF); + let name = format!("{:016X}", name); + let mdns = Mdns::get()? + .publish_service(&name, mdns::ServiceMode::Commissionable(discriminator))?; + s.state = PaseSessionState::Enabled(PAKE::new(verifier), mdns); + Ok(()) + } + + pub fn disable_pase_session(&mut self) { + let mut s = self.0.lock().unwrap(); + s.state = PaseSessionState::Disabled; + } + + /// If the PASE Session is enabled, execute the closure, + /// if not enabled, generate SC Status Report + fn if_enabled(&mut self, ctx: &mut ProtoCtx, f: F) -> Result<(), Error> + where + F: FnOnce(&mut PAKE, &mut ProtoCtx) -> Result<(), Error>, + { + let mut s = self.0.lock().unwrap(); + if let PaseSessionState::Enabled(pake, _) = &mut s.state { + f(pake, ctx) + } else { + error!("PASE Not enabled"); + create_sc_status_report(&mut ctx.tx, SCStatusCodes::InvalidParameter, None) + } + } + + pub fn pbkdfparamreq_handler(&mut self, ctx: &mut ProtoCtx) -> Result { + ctx.tx.set_proto_opcode(OpCode::PBKDFParamResponse as u8); + self.if_enabled(ctx, |pake, ctx| pake.handle_pbkdfparamrequest(ctx))?; + Ok(ResponseRequired::Yes) + } + + pub fn pasepake1_handler(&mut self, ctx: &mut ProtoCtx) -> Result { + ctx.tx.set_proto_opcode(OpCode::PASEPake2 as u8); + self.if_enabled(ctx, |pake, ctx| pake.handle_pasepake1(ctx))?; + Ok(ResponseRequired::Yes) + } + + pub fn pasepake3_handler(&mut self, ctx: &mut ProtoCtx) -> Result { + self.if_enabled(ctx, |pake, ctx| pake.handle_pasepake3(ctx))?; + self.disable_pase_session(); + Ok(ResponseRequired::Yes) + } +} + // This file basically deals with the handlers for the PASE secure channel protocol // TLV extraction and encoding is done in this file. // We create a Spake2p object and set it up in the exchange-data. This object then