pase: Create provision to accept either password or verifier for configuring PASE

This commit is contained in:
Kedar Sovani 2023-01-08 12:27:27 +05:30
parent 98fccca392
commit 311cc412e2
9 changed files with 109 additions and 52 deletions

View file

@ -19,17 +19,15 @@ mod dev_att;
use matter::core::{self, CommissioningData}; use matter::core::{self, CommissioningData};
use matter::data_model::cluster_basic_information::BasicInfoConfig; use matter::data_model::cluster_basic_information::BasicInfoConfig;
use matter::data_model::device_types::device_type_add_on_off_light; use matter::data_model::device_types::device_type_add_on_off_light;
use rand::prelude::*; use matter::secure_channel::spake2p::VerifierData;
fn main() { fn main() {
env_logger::init(); env_logger::init();
let mut comm_data = CommissioningData { let comm_data = CommissioningData {
// TODO: Hard-coded for now // TODO: Hard-coded for now
passwd: 123456, verifier: VerifierData::new_with_pw(123456),
discriminator: 250, discriminator: 250,
..Default::default()
}; };
rand::thread_rng().fill_bytes(&mut comm_data.salt);
// vid/pid should match those in the DAC // vid/pid should match those in the DAC
let dev_info = BasicInfoConfig { let dev_info = BasicInfoConfig {

View file

@ -25,19 +25,15 @@ use crate::{
fabric::FabricMgr, fabric::FabricMgr,
interaction_model::InteractionModel, interaction_model::InteractionModel,
mdns::Mdns, mdns::Mdns,
secure_channel::core::SecureChannel, secure_channel::{core::SecureChannel, spake2p::VerifierData},
transport, transport,
}; };
use std::sync::Arc; use std::sync::Arc;
#[derive(Default)]
/// Device Commissioning Data /// Device Commissioning Data
pub struct CommissioningData { pub struct CommissioningData {
/// The commissioning salt /// The data like password or verifier that is required to authenticate
pub salt: [u8; 16], pub verifier: VerifierData,
/// The password for commissioning the device
// TODO: We should replace this with verifier instead of password
pub passwd: u32,
/// The 12-bit discriminator used to differentiate between multiple devices /// The 12-bit discriminator used to differentiate between multiple devices
pub discriminator: u16, pub discriminator: u16,
} }
@ -78,11 +74,7 @@ impl Matter {
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 secure_channel = Box::new(SecureChannel::new(matter.fabric_mgr.clone()));
if open_comm_window { if open_comm_window {
secure_channel.open_comm_window( secure_channel.open_comm_window(dev_comm.verifier, dev_comm.discriminator)?;
&dev_comm.salt,
dev_comm.passwd,
dev_comm.discriminator,
)?;
} }
matter.transport_mgr.register_protocol(secure_channel)?; matter.transport_mgr.register_protocol(secure_channel)?;

View file

@ -27,7 +27,7 @@
//! use matter::{Matter, CommissioningData}; //! use matter::{Matter, CommissioningData};
//! use matter::data_model::device_types::device_type_add_on_off_light; //! use matter::data_model::device_types::device_type_add_on_off_light;
//! use matter::data_model::cluster_basic_information::BasicInfoConfig; //! use matter::data_model::cluster_basic_information::BasicInfoConfig;
//! use rand::prelude::*; //! use matter::secure_channel::spake2p::VerifierData;
//! //!
//! # use matter::data_model::sdm::dev_att::{DataType, DevAttDataFetcher}; //! # use matter::data_model::sdm::dev_att::{DataType, DevAttDataFetcher};
//! # use matter::error::Error; //! # use matter::error::Error;
@ -38,12 +38,11 @@
//! # let dev_att = Box::new(DevAtt{}); //! # let dev_att = Box::new(DevAtt{});
//! //!
//! /// The commissioning data for this device //! /// The commissioning data for this device
//! let mut comm_data = CommissioningData { //! let comm_data = CommissioningData {
//! passwd: 123456, //! verifier: VerifierData::new_with_pw(123456),
//! discriminator: 250, //! discriminator: 250,
//! ..Default::default() //!
//! }; //! };
//! rand::thread_rng().fill_bytes(&mut comm_data.salt);
//! //!
//! /// The basic information about this device //! /// The basic information about this device
//! let dev_info = BasicInfoConfig { //! let dev_info = BasicInfoConfig {

View file

@ -30,7 +30,7 @@ use log::{error, info};
use num; use num;
use rand::prelude::*; use rand::prelude::*;
use super::case::Case; use super::{case::Case, spake2p::VerifierData};
/* Handle messages related to the Secure Channel /* Handle messages related to the Secure Channel
*/ */
@ -50,15 +50,14 @@ impl SecureChannel {
pub fn open_comm_window( pub fn open_comm_window(
&mut self, &mut self,
salt: &[u8; 16], verifier: VerifierData,
passwd: u32,
discriminator: u16, discriminator: u16,
) -> Result<(), Error> { ) -> Result<(), Error> {
let name: u64 = rand::thread_rng().gen_range(0..0xFFFFFFFFFFFFFFFF); let name: u64 = rand::thread_rng().gen_range(0..0xFFFFFFFFFFFFFFFF);
let name = format!("{:016X}", name); let name = format!("{:016X}", name);
let mdns = Mdns::get()? let mdns = Mdns::get()?
.publish_service(&name, mdns::ServiceMode::Commissionable(discriminator))?; .publish_service(&name, mdns::ServiceMode::Commissionable(discriminator))?;
self.pake = Some((PAKE::new(salt, passwd), mdns)); self.pake = Some((PAKE::new(verifier), mdns));
Ok(()) Ok(())
} }

View file

@ -38,7 +38,9 @@ pub trait CryptoSpake2 {
fn set_w1(&mut self, w1: &[u8]) -> Result<(), Error>; fn set_w1(&mut self, w1: &[u8]) -> Result<(), Error>;
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn set_L(&mut self, w1s: &[u8]) -> Result<(), Error>; fn set_L(&mut self, l: &[u8]) -> Result<(), Error>;
#[allow(non_snake_case)]
fn set_L_from_w1s(&mut self, w1s: &[u8]) -> Result<(), Error>;
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn get_pB(&mut self, pB: &mut [u8]) -> Result<(), Error>; fn get_pB(&mut self, pB: &mut [u8]) -> Result<(), Error>;
#[allow(non_snake_case)] #[allow(non_snake_case)]

View file

@ -114,9 +114,14 @@ impl CryptoSpake2 for CryptoMbedTLS {
Ok(()) Ok(())
} }
fn set_L(&mut self, l: &[u8]) -> Result<(), Error> {
self.L = EcPoint::from_binary(&mut self.group, l)?;
Ok(())
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(dead_code)] #[allow(dead_code)]
fn set_L(&mut self, w1s: &[u8]) -> Result<(), Error> { fn set_L_from_w1s(&mut self, w1s: &[u8]) -> Result<(), Error> {
// From the Matter spec, // From the Matter spec,
// L = w1 * P // L = w1 * P
// where P is the generator of the underlying elliptic curve // where P is the generator of the underlying elliptic curve

View file

@ -117,9 +117,14 @@ impl CryptoSpake2 for CryptoOpenSSL {
Ok(()) Ok(())
} }
fn set_L(&mut self, l: &[u8]) -> Result<(), Error> {
self.L = EcPoint::from_bytes(&self.group, l, &mut self.bn_ctx)?;
Ok(())
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(dead_code)] #[allow(dead_code)]
fn set_L(&mut self, w1s: &[u8]) -> Result<(), Error> { fn set_L_from_w1s(&mut self, w1s: &[u8]) -> Result<(), Error> {
// From the Matter spec, // From the Matter spec,
// L = w1 * P // L = w1 * P
// where P is the generator of the underlying elliptic curve // where P is the generator of the underlying elliptic curve

View file

@ -19,12 +19,11 @@ use std::time::{Duration, SystemTime};
use super::{ use super::{
common::{create_sc_status_report, SCStatusCodes}, common::{create_sc_status_report, SCStatusCodes},
spake2p::Spake2P, spake2p::{Spake2P, VerifierData},
}; };
use crate::{ use crate::{
crypto, crypto,
error::Error, error::Error,
sys::SPAKE2_ITERATION_COUNT,
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,
@ -111,20 +110,17 @@ impl Default for PakeState {
} }
} }
#[derive(Default)]
pub struct PAKE { pub struct PAKE {
salt: [u8; 16], verifier: VerifierData,
passwd: u32,
state: PakeState, state: PakeState,
} }
impl PAKE { impl PAKE {
pub fn new(salt: &[u8; 16], passwd: u32) -> Self { pub fn new(verifier: VerifierData) -> Self {
// TODO: Can any PBKDF2 calculation be pre-computed here // TODO: Can any PBKDF2 calculation be pre-computed here
PAKE { PAKE {
passwd, verifier,
salt: *salt, state: Default::default(),
..Default::default()
} }
} }
@ -176,8 +172,7 @@ impl PAKE {
let pA = extract_pasepake_1_or_3_params(ctx.rx.as_borrow_slice())?; let pA = extract_pasepake_1_or_3_params(ctx.rx.as_borrow_slice())?;
let mut pB: [u8; 65] = [0; 65]; let mut pB: [u8; 65] = [0; 65];
let mut cB: [u8; 32] = [0; 32]; let mut cB: [u8; 32] = [0; 32];
sd.spake2p sd.spake2p.start_verifier(&self.verifier)?;
.start_verifier(self.passwd, SPAKE2_ITERATION_COUNT, &self.salt)?;
sd.spake2p.handle_pA(pA, &mut pB, &mut cB)?; sd.spake2p.handle_pA(pA, &mut pB, &mut cB)?;
let mut tw = TLVWriter::new(ctx.tx.get_writebuf()?); let mut tw = TLVWriter::new(ctx.tx.get_writebuf()?);
@ -231,8 +226,8 @@ impl PAKE {
}; };
if !a.has_params { if !a.has_params {
let params_resp = PBKDFParamRespParams { let params_resp = PBKDFParamRespParams {
count: SPAKE2_ITERATION_COUNT, count: self.verifier.count,
salt: OctetStr(&self.salt), salt: OctetStr(&self.verifier.salt),
}; };
resp.params = Some(params_resp); resp.params = Some(params_resp);
} }

View file

@ -15,8 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::crypto::{self, HmacSha256}; use crate::{
crypto::{self, HmacSha256},
sys,
};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use log::error;
use rand::prelude::*;
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
use crate::{ use crate::{
@ -74,6 +79,10 @@ const SPAKE2P_KEY_CONFIRM_INFO: [u8; 16] = *b"ConfirmationKeys";
const SPAKE2P_CONTEXT_PREFIX: [u8; 26] = *b"CHIP PAKE V1 Commissioning"; const SPAKE2P_CONTEXT_PREFIX: [u8; 26] = *b"CHIP PAKE V1 Commissioning";
const CRYPTO_GROUP_SIZE_BYTES: usize = 32; const CRYPTO_GROUP_SIZE_BYTES: usize = 32;
const CRYPTO_W_SIZE_BYTES: usize = CRYPTO_GROUP_SIZE_BYTES + 8; const CRYPTO_W_SIZE_BYTES: usize = CRYPTO_GROUP_SIZE_BYTES + 8;
const CRYPTO_PUBLIC_KEY_SIZE_BYTES: usize = (2 * CRYPTO_GROUP_SIZE_BYTES) + 1;
const MAX_SALT_SIZE_BYTES: usize = 32;
const VERIFIER_SIZE_BYTES: usize = CRYPTO_W_SIZE_BYTES + CRYPTO_PUBLIC_KEY_SIZE_BYTES;
#[cfg(feature = "crypto_openssl")] #[cfg(feature = "crypto_openssl")]
fn crypto_spake2_new() -> Result<Box<dyn CryptoSpake2>, Error> { fn crypto_spake2_new() -> Result<Box<dyn CryptoSpake2>, Error> {
@ -96,6 +105,45 @@ impl Default for Spake2P {
} }
} }
pub struct VerifierData {
pub data: VerifierOption,
// For the VerifierOption::Verifier, the following fields only serve
// information purposes
pub salt: [u8; MAX_SALT_SIZE_BYTES],
pub count: u32,
}
pub enum VerifierOption {
/// With Password
Password(u32),
/// With Verifier
Verifier([u8; VERIFIER_SIZE_BYTES]),
}
impl VerifierData {
pub fn new_with_pw(pw: u32) -> Self {
let mut s = Self {
salt: [0; MAX_SALT_SIZE_BYTES],
count: sys::SPAKE2_ITERATION_COUNT,
data: VerifierOption::Password(pw),
};
rand::thread_rng().fill_bytes(&mut s.salt);
s
}
pub fn new(
verifier: [u8; VERIFIER_SIZE_BYTES],
count: u32,
salt: [u8; MAX_SALT_SIZE_BYTES],
) -> Self {
Self {
data: VerifierOption::Verifier(verifier),
count,
salt,
}
}
}
impl Spake2P { impl Spake2P {
pub fn new() -> Self { pub fn new() -> Self {
Spake2P { Spake2P {
@ -132,17 +180,31 @@ impl Spake2P {
let _ = pbkdf2_hmac(&pw_str, iter as usize, salt, w0w1s); let _ = pbkdf2_hmac(&pw_str, iter as usize, salt, w0w1s);
} }
pub fn start_verifier(&mut self, pw: u32, iter: u32, salt: &[u8]) -> Result<(), Error> { pub fn start_verifier(&mut self, verifier: &VerifierData) -> Result<(), Error> {
match verifier.data {
VerifierOption::Password(pw) => {
// Derive w0 and L from the password
let mut w0w1s: [u8; (2 * CRYPTO_W_SIZE_BYTES)] = [0; (2 * CRYPTO_W_SIZE_BYTES)]; let mut w0w1s: [u8; (2 * CRYPTO_W_SIZE_BYTES)] = [0; (2 * CRYPTO_W_SIZE_BYTES)];
Spake2P::get_w0w1s(pw, iter, salt, &mut w0w1s); Spake2P::get_w0w1s(pw, verifier.count, &verifier.salt, &mut w0w1s);
self.crypto_spake2 = Some(crypto_spake2_new()?); self.crypto_spake2 = Some(crypto_spake2_new()?);
let w0s_len = w0w1s.len() / 2; let w0s_len = w0w1s.len() / 2;
if let Some(crypto_spake2) = &mut self.crypto_spake2 { if let Some(crypto_spake2) = &mut self.crypto_spake2 {
crypto_spake2.set_w0_from_w0s(&w0w1s[0..w0s_len])?; crypto_spake2.set_w0_from_w0s(&w0w1s[0..w0s_len])?;
crypto_spake2.set_L(&w0w1s[w0s_len..])?; crypto_spake2.set_L_from_w1s(&w0w1s[w0s_len..])?;
}
}
VerifierOption::Verifier(v) => {
// Extract w0 and L from the verifier
if v.len() != CRYPTO_GROUP_SIZE_BYTES + CRYPTO_PUBLIC_KEY_SIZE_BYTES {
error!("Verifier of invalid length");
}
if let Some(crypto_spake2) = &mut self.crypto_spake2 {
crypto_spake2.set_w0(&v[0..CRYPTO_GROUP_SIZE_BYTES])?;
crypto_spake2.set_L(&v[CRYPTO_GROUP_SIZE_BYTES..])?;
}
}
} }
self.mode = Spake2Mode::Verifier(Spake2VerifierState::Init); self.mode = Spake2Mode::Verifier(Spake2VerifierState::Init);
Ok(()) Ok(())
} }