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:
parent
ebaf5438cd
commit
95c74ec298
4 changed files with 112 additions and 103 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue