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
This commit is contained in:
Kedar Sovani 2023-01-10 10:48:20 +05:30
parent ebaf5438cd
commit 95c74ec298
4 changed files with 112 additions and 103 deletions

View file

@ -25,7 +25,7 @@ use crate::{
fabric::FabricMgr, fabric::FabricMgr,
interaction_model::InteractionModel, interaction_model::InteractionModel,
mdns::Mdns, mdns::Mdns,
secure_channel::{core::SecureChannel, spake2p::VerifierData}, secure_channel::{core::SecureChannel, pake::PaseMgr, spake2p::VerifierData},
transport, transport,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -72,11 +72,13 @@ impl Matter {
let interaction_model = let interaction_model =
Box::new(InteractionModel::new(Box::new(matter.data_model.clone()))); Box::new(InteractionModel::new(Box::new(matter.data_model.clone())));
matter.transport_mgr.register_protocol(interaction_model)?; 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 { 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)?; matter.transport_mgr.register_protocol(secure_channel)?;
Ok(matter) Ok(matter)
} }

View file

@ -26,12 +26,12 @@ use crate::{
crypto::{self, CryptoKeyPair, KeyPair, Sha256}, crypto::{self, CryptoKeyPair, KeyPair, Sha256},
error::Error, error::Error,
fabric::{Fabric, FabricMgr, FabricMgrInner}, fabric::{Fabric, FabricMgr, FabricMgrInner},
secure_channel::common,
secure_channel::common::SCStatusCodes, secure_channel::common::SCStatusCodes,
secure_channel::common::{self, OpCode},
tlv::{get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType}, tlv::{get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType},
transport::{ transport::{
network::Address, network::Address,
proto_demux::ProtoCtx, proto_demux::{ProtoCtx, ResponseRequired},
queue::{Msg, WorkQ}, queue::{Msg, WorkQ},
session::{CloneData, SessionMode}, session::{CloneData, SessionMode},
}, },
@ -78,7 +78,7 @@ impl Case {
Self { fabric_mgr } Self { fabric_mgr }
} }
pub fn handle_casesigma3(&mut self, ctx: &mut ProtoCtx) -> Result<(), Error> { pub fn casesigma3_handler(&mut self, ctx: &mut ProtoCtx) -> Result<ResponseRequired, Error> {
let mut case_session = ctx let mut case_session = ctx
.exch_ctx .exch_ctx
.exch .exch
@ -97,7 +97,7 @@ impl Case {
None, None,
)?; )?;
ctx.exch_ctx.exch.close(); ctx.exch_ctx.exch.close();
return Ok(()); return Ok(ResponseRequired::Yes);
} }
// Safe to unwrap here // Safe to unwrap here
let fabric = fabric.as_ref().as_ref().unwrap(); let fabric = fabric.as_ref().as_ref().unwrap();
@ -132,7 +132,7 @@ impl Case {
None, None,
)?; )?;
ctx.exch_ctx.exch.close(); ctx.exch_ctx.exch.close();
return Ok(()); return Ok(ResponseRequired::Yes);
} }
if Case::validate_sigma3_sign( if Case::validate_sigma3_sign(
@ -151,7 +151,7 @@ impl Case {
None, None,
)?; )?;
ctx.exch_ctx.exch.close(); ctx.exch_ctx.exch.close();
return Ok(()); return Ok(ResponseRequired::Yes);
} }
// Only now do we add this message to the TT Hash // 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.clear_data_boxed();
ctx.exch_ctx.exch.close(); 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<ResponseRequired, Error> {
ctx.tx.set_proto_opcode(OpCode::CASESigma2 as u8);
let rx_buf = ctx.rx.as_borrow_slice(); let rx_buf = ctx.rx.as_borrow_slice();
let root = get_root_node_struct(rx_buf)?; let root = get_root_node_struct(rx_buf)?;
let r = Sigma1Req::from_tlv(&root)?; let r = Sigma1Req::from_tlv(&root)?;
@ -193,7 +195,7 @@ impl Case {
None, None,
)?; )?;
ctx.exch_ctx.exch.close(); ctx.exch_ctx.exch.close();
return Ok(()); return Ok(ResponseRequired::Yes);
} }
let local_sessid = ctx.exch_ctx.sess.reserve_new_sess_id(); let local_sessid = ctx.exch_ctx.sess.reserve_new_sess_id();
@ -239,7 +241,7 @@ impl Case {
None, None,
)?; )?;
ctx.exch_ctx.exch.close(); ctx.exch_ctx.exch.close();
return Ok(()); return Ok(ResponseRequired::Yes);
} }
let sign_len = Case::get_sigma2_sign( let sign_len = Case::get_sigma2_sign(
@ -270,7 +272,7 @@ impl Case {
tw.end_container()?; tw.end_container()?;
case_session.tt_hash.update(ctx.tx.as_borrow_slice())?; case_session.tt_hash.update(ctx.tx.as_borrow_slice())?;
ctx.exch_ctx.exch.set_data_boxed(case_session); ctx.exch_ctx.exch.set_data_boxed(case_session);
Ok(()) Ok(ResponseRequired::Yes)
} }
fn get_session_clone_data( fn get_session_clone_data(

View file

@ -20,105 +20,30 @@ use std::sync::Arc;
use crate::{ use crate::{
error::*, error::*,
fabric::FabricMgr, fabric::FabricMgr,
mdns::{self, Mdns}, secure_channel::common::*,
secure_channel::{common::*, pake::PAKE},
sys::SysMdnsService,
tlv, tlv,
transport::proto_demux::{self, ProtoCtx, ResponseRequired}, transport::proto_demux::{self, ProtoCtx, ResponseRequired},
}; };
use log::{error, info}; use log::{error, info};
use num; use num;
use rand::prelude::*;
use super::{case::Case, spake2p::VerifierData}; use super::{case::Case, pake::PaseMgr};
/* Handle messages related to the Secure Channel /* Handle messages related to the Secure Channel
*/ */
pub struct SecureChannel { pub struct SecureChannel {
case: Case, case: Case,
pake: Option<(PAKE, SysMdnsService)>, pase: PaseMgr,
} }
impl SecureChannel { impl SecureChannel {
pub fn new(fabric_mgr: Arc<FabricMgr>) -> SecureChannel { pub fn new(pase: PaseMgr, fabric_mgr: Arc<FabricMgr>) -> SecureChannel {
SecureChannel { SecureChannel {
pake: None, pase,
case: Case::new(fabric_mgr), 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<ResponseRequired, Error> {
info!("In MRP StandAlone ACK Handler");
Ok(ResponseRequired::No)
}
fn pbkdfparamreq_handler(&mut self, ctx: &mut ProtoCtx) -> Result<ResponseRequired, Error> {
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<ResponseRequired, Error> {
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<ResponseRequired, Error> {
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<ResponseRequired, Error> {
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<ResponseRequired, Error> {
info!("In CASE Sigma3 Handler");
self.case.handle_casesigma3(ctx)?;
Ok(ResponseRequired::Yes)
}
} }
impl proto_demux::HandleProto for SecureChannel { impl proto_demux::HandleProto for SecureChannel {
@ -126,15 +51,16 @@ impl proto_demux::HandleProto for SecureChannel {
let proto_opcode: OpCode = let proto_opcode: OpCode =
num::FromPrimitive::from_u8(ctx.rx.get_proto_opcode()).ok_or(Error::Invalid)?; num::FromPrimitive::from_u8(ctx.rx.get_proto_opcode()).ok_or(Error::Invalid)?;
ctx.tx.set_proto_id(PROTO_ID_SECURE_CHANNEL as u16); 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()); tlv::print_tlv_list(ctx.rx.as_borrow_slice());
let result = match proto_opcode { let result = match proto_opcode {
OpCode::MRPStandAloneAck => self.mrpstandaloneack_handler(ctx), OpCode::MRPStandAloneAck => Ok(ResponseRequired::No),
OpCode::PBKDFParamRequest => self.pbkdfparamreq_handler(ctx), OpCode::PBKDFParamRequest => self.pase.pbkdfparamreq_handler(ctx),
OpCode::PASEPake1 => self.pasepake1_handler(ctx), OpCode::PASEPake1 => self.pase.pasepake1_handler(ctx),
OpCode::PASEPake3 => self.pasepake3_handler(ctx), OpCode::PASEPake3 => self.pase.pasepake3_handler(ctx),
OpCode::CASESigma1 => self.casesigma1_handler(ctx), OpCode::CASESigma1 => self.case.casesigma1_handler(ctx),
OpCode::CASESigma3 => self.casesigma3_handler(ctx), OpCode::CASESigma3 => self.case.casesigma3_handler(ctx),
_ => { _ => {
error!("OpCode Not Handled: {:?}", proto_opcode); error!("OpCode Not Handled: {:?}", proto_opcode);
Err(Error::InvalidOpcode) Err(Error::InvalidOpcode)

View file

@ -15,7 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
use std::time::{Duration, SystemTime}; use std::{
sync::{Arc, Mutex},
time::{Duration, SystemTime},
};
use super::{ use super::{
common::{create_sc_status_report, SCStatusCodes}, common::{create_sc_status_report, SCStatusCodes},
@ -24,11 +27,14 @@ use super::{
use crate::{ use crate::{
crypto, crypto,
error::Error, error::Error,
mdns::{self, Mdns},
secure_channel::common::OpCode,
sys::SysMdnsService,
tlv::{self, get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType, ToTLV}, tlv::{self, get_root_node_struct, FromTLV, OctetStr, TLVElement, TLVWriter, TagType, ToTLV},
transport::{ transport::{
exchange::ExchangeCtx, exchange::ExchangeCtx,
network::Address, network::Address,
proto_demux::ProtoCtx, proto_demux::{ProtoCtx, ResponseRequired},
queue::{Msg, WorkQ}, queue::{Msg, WorkQ},
session::{CloneData, SessionMode}, session::{CloneData, SessionMode},
}, },
@ -36,6 +42,79 @@ use crate::{
use log::{error, info}; use log::{error, info};
use rand::prelude::*; 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<Mutex<PaseMgrInternal>>);
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<F>(&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<ResponseRequired, Error> {
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<ResponseRequired, Error> {
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<ResponseRequired, Error> {
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 // This file basically deals with the handlers for the PASE secure channel protocol
// TLV extraction and encoding is done in this file. // 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 // We create a Spake2p object and set it up in the exchange-data. This object then