pase: Create provision to accept either password or verifier for configuring PASE
This commit is contained in:
parent
98fccca392
commit
311cc412e2
9 changed files with 109 additions and 52 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
let mut w0w1s: [u8; (2 * CRYPTO_W_SIZE_BYTES)] = [0; (2 * CRYPTO_W_SIZE_BYTES)];
|
match verifier.data {
|
||||||
Spake2P::get_w0w1s(pw, iter, salt, &mut w0w1s);
|
VerifierOption::Password(pw) => {
|
||||||
self.crypto_spake2 = Some(crypto_spake2_new()?);
|
// Derive w0 and L from the password
|
||||||
|
let mut w0w1s: [u8; (2 * CRYPTO_W_SIZE_BYTES)] = [0; (2 * CRYPTO_W_SIZE_BYTES)];
|
||||||
|
Spake2P::get_w0w1s(pw, verifier.count, &verifier.salt, &mut w0w1s);
|
||||||
|
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(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue