Simple persistance via TLV

This commit is contained in:
ivmarkov 2023-04-29 10:03:34 +00:00
parent 1392810a6c
commit 7437cf2c94
10 changed files with 262 additions and 646 deletions

View file

@ -27,6 +27,7 @@ use matter::data_model::root_endpoint;
use matter::data_model::sdm::dev_att::DevAttDataFetcher; use matter::data_model::sdm::dev_att::DevAttDataFetcher;
use matter::data_model::system_model::descriptor; use matter::data_model::system_model::descriptor;
use matter::interaction_model::core::InteractionModel; use matter::interaction_model::core::InteractionModel;
use matter::persist;
use matter::secure_channel::spake2p::VerifierData; use matter::secure_channel::spake2p::VerifierData;
use matter::transport::{ use matter::transport::{
mgr::RecvAction, mgr::TransportMgr, packet::MAX_RX_BUF_SIZE, packet::MAX_TX_BUF_SIZE, mgr::RecvAction, mgr::TransportMgr, packet::MAX_RX_BUF_SIZE, packet::MAX_TX_BUF_SIZE,
@ -56,6 +57,18 @@ fn main() {
let dev_att = dev_att::HardCodedDevAtt::new(); let dev_att = dev_att::HardCodedDevAtt::new();
let psm = persist::FilePsm::new(std::env::temp_dir().join("matter-iot")).unwrap();
let mut buf = [0; 4096];
if let Some(data) = psm.load("fabrics", &mut buf).unwrap() {
matter.load_fabrics(data).unwrap();
}
if let Some(data) = psm.load("acls", &mut buf).unwrap() {
matter.load_acls(data).unwrap();
}
matter matter
.start::<4096>( .start::<4096>(
CommissioningData { CommissioningData {
@ -63,7 +76,7 @@ fn main() {
verifier: VerifierData::new_with_pw(123456, *matter.borrow()), verifier: VerifierData::new_with_pw(123456, *matter.borrow()),
discriminator: 250, discriminator: 250,
}, },
&mut [0; 4096], &mut buf,
) )
.unwrap(); .unwrap();
@ -114,6 +127,14 @@ fn main() {
} }
} }
} }
if let Some(data) = matter.store_fabrics(&mut buf).unwrap() {
psm.store("fabrics", data).unwrap();
}
if let Some(data) = matter.store_acls(&mut buf).unwrap() {
psm.store("acls", data).unwrap();
}
} }
}); });
} }

View file

@ -22,7 +22,6 @@ use crate::{
error::Error, error::Error,
fabric, fabric,
interaction_model::messages::GenericPath, interaction_model::messages::GenericPath,
persist::Psm,
tlv::{FromTLV, TLVElement, TLVList, TLVWriter, TagType, ToTLV}, tlv::{FromTLV, TLVElement, TLVList, TLVWriter, TagType, ToTLV},
transport::session::{Session, SessionMode, MAX_CAT_IDS_PER_NOC}, transport::session::{Session, SessionMode, MAX_CAT_IDS_PER_NOC},
utils::writebuf::WriteBuf, utils::writebuf::WriteBuf,
@ -390,10 +389,8 @@ impl AclEntry {
} }
const MAX_ACL_ENTRIES: usize = ENTRIES_PER_FABRIC * fabric::MAX_SUPPORTED_FABRICS; const MAX_ACL_ENTRIES: usize = ENTRIES_PER_FABRIC * fabric::MAX_SUPPORTED_FABRICS;
type AclEntries = [Option<AclEntry>; MAX_ACL_ENTRIES];
const ACL_KV_ENTRY: &str = "acl"; type AclEntries = [Option<AclEntry>; MAX_ACL_ENTRIES];
const ACL_KV_MAX_SIZE: usize = 300;
pub struct AclMgr { pub struct AclMgr {
entries: AclEntries, entries: AclEntries,
@ -505,30 +502,8 @@ impl AclMgr {
false false
} }
pub fn store<T>(&mut self, mut psm: T) -> Result<(), Error> pub fn load(&mut self, data: &[u8]) -> Result<(), Error> {
where let root = TLVList::new(data).iter().next().ok_or(Error::Invalid)?;
T: Psm,
{
if self.changed {
let mut buf = [0u8; ACL_KV_MAX_SIZE];
let mut wb = WriteBuf::new(&mut buf);
let mut tw = TLVWriter::new(&mut wb);
self.entries.to_tlv(&mut tw, TagType::Anonymous)?;
psm.set_kv_slice(ACL_KV_ENTRY, wb.as_slice())?;
self.changed = false;
}
Ok(())
}
pub fn load<T>(&mut self, psm: T) -> Result<(), Error>
where
T: Psm,
{
let mut buf = [0u8; ACL_KV_MAX_SIZE];
let acl_tlvs = psm.get_kv_slice(ACL_KV_ENTRY, &mut buf)?;
let root = TLVList::new(acl_tlvs).iter().next().ok_or(Error::Invalid)?;
self.entries = AclEntries::from_tlv(&root)?; self.entries = AclEntries::from_tlv(&root)?;
self.changed = false; self.changed = false;
@ -536,37 +511,20 @@ impl AclMgr {
Ok(()) Ok(())
} }
#[cfg(feature = "nightly")] pub fn store<'a>(&mut self, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
pub async fn store_async<T>(&mut self, mut psm: T) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
if self.changed { if self.changed {
let mut buf = [0u8; ACL_KV_MAX_SIZE]; let mut wb = WriteBuf::new(buf);
let mut wb = WriteBuf::new(&mut buf);
let mut tw = TLVWriter::new(&mut wb); let mut tw = TLVWriter::new(&mut wb);
self.entries.to_tlv(&mut tw, TagType::Anonymous)?; self.entries.to_tlv(&mut tw, TagType::Anonymous)?;
psm.set_kv_slice(ACL_KV_ENTRY, wb.as_slice()).await?;
self.changed = false; self.changed = false;
let len = tw.get_tail();
Ok(Some(&buf[..len]))
} else {
Ok(None)
} }
Ok(())
}
#[cfg(feature = "nightly")]
pub async fn load_async<T>(&mut self, psm: T) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
let mut buf = [0u8; ACL_KV_MAX_SIZE];
let acl_tlvs = psm.get_kv_slice(ACL_KV_ENTRY, &mut buf).await?;
let root = TLVList::new(acl_tlvs).iter().next().ok_or(Error::Invalid)?;
self.entries = AclEntries::from_tlv(&root)?;
self.changed = false;
Ok(())
} }
/// Traverse fabric specific entries to find the index /// Traverse fabric specific entries to find the index

View file

@ -98,6 +98,24 @@ impl<'a> Matter<'a> {
self.dev_det self.dev_det
} }
pub fn load_fabrics(&self, data: &[u8]) -> Result<(), Error> {
self.fabric_mgr
.borrow_mut()
.load(data, &mut self.mdns_mgr.borrow_mut())
}
pub fn load_acls(&self, data: &[u8]) -> Result<(), Error> {
self.acl_mgr.borrow_mut().load(data)
}
pub fn store_fabrics<'b>(&self, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> {
self.fabric_mgr.borrow_mut().store(buf)
}
pub fn store_acls<'b>(&self, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> {
self.acl_mgr.borrow_mut().store(buf)
}
pub fn start<const N: usize>( pub fn start<const N: usize>(
&self, &self,
dev_comm: CommissioningData, dev_comm: CommissioningData,

View file

@ -68,8 +68,6 @@ impl KeyPair {
} }
pub fn new_from_components(_pub_key: &[u8], _priv_key: &[u8]) -> Result<Self, Error> { pub fn new_from_components(_pub_key: &[u8], _priv_key: &[u8]) -> Result<Self, Error> {
error!("This API should never get called");
Ok(Self {}) Ok(Self {})
} }
@ -85,13 +83,11 @@ impl KeyPair {
} }
pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> { pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
error!("This API should never get called"); Ok(0)
Err(Error::Invalid)
} }
pub fn get_private_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> { pub fn get_private_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
error!("This API should never get called"); Ok(0)
Err(Error::Invalid)
} }
pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> { pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> {

View file

@ -70,8 +70,6 @@ impl KeyPair {
} }
pub fn new_from_components(_pub_key: &[u8], priv_key: &[u8]) -> Result<Self, Error> { pub fn new_from_components(_pub_key: &[u8], priv_key: &[u8]) -> Result<Self, Error> {
error!("This API should never get called");
Ok(Self {}) Ok(Self {})
} }
@ -87,8 +85,11 @@ impl KeyPair {
} }
pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> { pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
error!("This API should never get called"); Ok(0)
Err(Error::Invalid) }
pub fn get_private_key(&self, priv_key: &mut [u8]) -> Result<usize, Error> {
Ok(0)
} }
pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> { pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> {

View file

@ -14,6 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
use crate::{
error::Error,
tlv::{FromTLV, TLVWriter, TagType, ToTLV},
};
pub const SYMM_KEY_LEN_BITS: usize = 128; pub const SYMM_KEY_LEN_BITS: usize = 128;
pub const SYMM_KEY_LEN_BYTES: usize = SYMM_KEY_LEN_BITS / 8; pub const SYMM_KEY_LEN_BYTES: usize = SYMM_KEY_LEN_BITS / 8;
@ -68,6 +72,38 @@ pub mod crypto_dummy;
)))] )))]
pub use self::crypto_dummy::*; pub use self::crypto_dummy::*;
impl<'a> FromTLV<'a> for KeyPair {
fn from_tlv(t: &crate::tlv::TLVElement<'a>) -> Result<Self, Error>
where
Self: Sized,
{
t.confirm_array()?.enter();
if let Some(mut array) = t.enter() {
let pub_key = array.next().ok_or(Error::Invalid)?.slice()?;
let priv_key = array.next().ok_or(Error::Invalid)?.slice()?;
KeyPair::new_from_components(pub_key, priv_key)
} else {
Err(Error::Invalid)
}
}
}
impl ToTLV for KeyPair {
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
let mut buf = [0; 1024]; // TODO
tw.start_array(tag)?;
let size = self.get_public_key(&mut buf)?;
tw.str16(TagType::Anonymous, &buf[..size])?;
let size = self.get_private_key(&mut buf)?;
tw.str16(TagType::Anonymous, &buf[..size])
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::error::Error; use crate::error::Error;

View file

@ -18,7 +18,8 @@
use core::fmt::Write; use core::fmt::Write;
use byteorder::{BigEndian, ByteOrder, LittleEndian}; use byteorder::{BigEndian, ByteOrder, LittleEndian};
use log::{error, info}; use heapless::{String, Vec};
use log::info;
use crate::{ use crate::{
cert::{Cert, MAX_CERT_TLV_LEN}, cert::{Cert, MAX_CERT_TLV_LEN},
@ -26,32 +27,12 @@ use crate::{
error::Error, error::Error,
group_keys::KeySet, group_keys::KeySet,
mdns::{MdnsMgr, ServiceMode}, mdns::{MdnsMgr, ServiceMode},
persist::Psm, tlv::{FromTLV, OctetStr, TLVElement, TLVList, TLVWriter, TagType, ToTLV, UtfStr},
tlv::{OctetStr, TLVWriter, TagType, ToTLV, UtfStr}, utils::writebuf::WriteBuf,
}; };
const COMPRESSED_FABRIC_ID_LEN: usize = 8; const COMPRESSED_FABRIC_ID_LEN: usize = 8;
macro_rules! fb_key {
($index:ident, $key:ident, $buf:expr) => {{
use core::fmt::Write;
$buf = "".into();
write!(&mut $buf, "fb{}{}", $index, $key).unwrap();
&$buf
}};
}
const ST_VID: &str = "vid";
const ST_RCA: &str = "rca";
const ST_ICA: &str = "ica";
const ST_NOC: &str = "noc";
const ST_IPK: &str = "ipk";
const ST_LBL: &str = "label";
const ST_PBKEY: &str = "pubkey";
const ST_PRKEY: &str = "privkey";
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, ToTLV)] #[derive(Debug, ToTLV)]
#[tlvargs(lifetime = "'a", start = 1)] #[tlvargs(lifetime = "'a", start = 1)]
@ -66,18 +47,18 @@ pub struct FabricDescriptor<'a> {
pub fab_idx: Option<u8>, pub fab_idx: Option<u8>,
} }
#[derive(Debug)] #[derive(Debug, ToTLV, FromTLV)]
pub struct Fabric { pub struct Fabric {
node_id: u64, node_id: u64,
fabric_id: u64, fabric_id: u64,
vendor_id: u16, vendor_id: u16,
key_pair: KeyPair, key_pair: KeyPair,
pub root_ca: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>, pub root_ca: Vec<u8, { MAX_CERT_TLV_LEN }>,
pub icac: Option<heapless::Vec<u8, { MAX_CERT_TLV_LEN }>>, pub icac: Option<Vec<u8, { MAX_CERT_TLV_LEN }>>,
pub noc: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>, pub noc: Vec<u8, { MAX_CERT_TLV_LEN }>,
pub ipk: KeySet, pub ipk: KeySet,
label: heapless::String<32>, label: String<32>,
mdns_service_name: heapless::String<33>, mdns_service_name: String<33>,
} }
impl Fabric { impl Fabric {
@ -199,234 +180,14 @@ impl Fabric {
Ok(desc) Ok(desc)
} }
fn store<T>(&self, index: usize, mut psm: T) -> Result<(), Error>
where
T: Psm,
{
let mut _kb = heapless::String::<32>::new();
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &self.root_ca)?;
psm.set_kv_slice(
fb_key!(index, ST_ICA, _kb),
self.icac.as_deref().unwrap_or(&[]),
)?;
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &self.noc)?;
psm.set_kv_slice(fb_key!(index, ST_IPK, _kb), self.ipk.epoch_key())?;
psm.set_kv_slice(fb_key!(index, ST_LBL, _kb), self.label.as_bytes())?;
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
let len = self.key_pair.get_public_key(&mut buf)?;
let key = &buf[..len];
psm.set_kv_slice(fb_key!(index, ST_PBKEY, _kb), key)?;
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
let len = self.key_pair.get_private_key(&mut buf)?;
let key = &buf[..len];
psm.set_kv_slice(fb_key!(index, ST_PRKEY, _kb), key)?;
psm.set_kv_u64(fb_key!(index, ST_VID, _kb), self.vendor_id.into())?;
Ok(())
}
fn load<T>(index: usize, psm: T) -> Result<Self, Error>
where
T: Psm,
{
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let root_ca =
heapless::Vec::from_slice(psm.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)?)
.unwrap();
let icac = psm.get_kv_slice(fb_key!(index, ST_ICA, _kb), &mut buf)?;
let icac = if !icac.is_empty() {
Some(heapless::Vec::from_slice(icac).unwrap())
} else {
None
};
let noc =
heapless::Vec::from_slice(psm.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)?)
.unwrap();
let label = psm.get_kv_slice(fb_key!(index, ST_LBL, _kb), &mut buf)?;
let label: heapless::String<32> = core::str::from_utf8(label)
.map_err(|_| {
error!("Couldn't read label");
Error::Invalid
})?
.into();
let ipk = psm.get_kv_slice(fb_key!(index, ST_IPK, _kb), &mut buf)?;
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
let pub_key = psm.get_kv_slice(fb_key!(index, ST_PBKEY, _kb), &mut buf)?;
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
let priv_key = psm.get_kv_slice(fb_key!(index, ST_PRKEY, _kb), &mut buf)?;
let keypair = KeyPair::new_from_components(pub_key, priv_key)?;
let vendor_id = psm.get_kv_u64(fb_key!(index, ST_VID, _kb))?;
Fabric::new(keypair, root_ca, icac, noc, ipk, vendor_id as u16, &label)
}
fn remove<T>(index: usize, mut psm: T) -> Result<(), Error>
where
T: Psm,
{
let mut _kb = heapless::String::<32>::new();
psm.remove(fb_key!(index, ST_RCA, _kb))?;
psm.remove(fb_key!(index, ST_ICA, _kb))?;
psm.remove(fb_key!(index, ST_NOC, _kb))?;
psm.remove(fb_key!(index, ST_LBL, _kb))?;
psm.remove(fb_key!(index, ST_IPK, _kb))?;
psm.remove(fb_key!(index, ST_PBKEY, _kb))?;
psm.remove(fb_key!(index, ST_PRKEY, _kb))?;
psm.remove(fb_key!(index, ST_VID, _kb))?;
Ok(())
}
#[cfg(feature = "nightly")]
async fn store_async<T>(&self, index: usize, mut psm: T) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
let mut _kb = heapless::String::<32>::new();
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &self.root_ca)
.await?;
psm.set_kv_slice(
fb_key!(index, ST_ICA, _kb),
self.icac.as_deref().unwrap_or(&[]),
)
.await?;
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &self.noc)
.await?;
psm.set_kv_slice(fb_key!(index, ST_IPK, _kb), self.ipk.epoch_key())
.await?;
psm.set_kv_slice(fb_key!(index, ST_LBL, _kb), self.label.as_bytes())
.await?;
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
let len = self.key_pair.get_public_key(&mut buf)?;
let key = &buf[..len];
psm.set_kv_slice(fb_key!(index, ST_PBKEY, _kb), key).await?;
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
let len = self.key_pair.get_private_key(&mut buf)?;
let key = &buf[..len];
psm.set_kv_slice(fb_key!(index, ST_PRKEY, _kb), key).await?;
psm.set_kv_u64(fb_key!(index, ST_VID, _kb), self.vendor_id.into())
.await?;
Ok(())
}
#[cfg(feature = "nightly")]
async fn load_async<T>(index: usize, psm: T) -> Result<Self, Error>
where
T: crate::persist::asynch::AsyncPsm,
{
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let root_ca = heapless::Vec::from_slice(
psm.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)
.await?,
)
.unwrap();
let icac = psm
.get_kv_slice(fb_key!(index, ST_ICA, _kb), &mut buf)
.await?;
let icac = if !icac.is_empty() {
Some(heapless::Vec::from_slice(icac).unwrap())
} else {
None
};
let noc = heapless::Vec::from_slice(
psm.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)
.await?,
)
.unwrap();
let label = psm
.get_kv_slice(fb_key!(index, ST_LBL, _kb), &mut buf)
.await?;
let label: heapless::String<32> = core::str::from_utf8(label)
.map_err(|_| {
error!("Couldn't read label");
Error::Invalid
})?
.into();
let ipk = psm
.get_kv_slice(fb_key!(index, ST_IPK, _kb), &mut buf)
.await?;
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
let pub_key = psm
.get_kv_slice(fb_key!(index, ST_PBKEY, _kb), &mut buf)
.await?;
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
let priv_key = psm
.get_kv_slice(fb_key!(index, ST_PRKEY, _kb), &mut buf)
.await?;
let keypair = KeyPair::new_from_components(pub_key, priv_key)?;
let vendor_id = psm.get_kv_u64(fb_key!(index, ST_VID, _kb)).await?;
Fabric::new(keypair, root_ca, icac, noc, ipk, vendor_id as u16, &label)
}
#[cfg(feature = "nightly")]
async fn remove_async<T>(index: usize, mut psm: T) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
let mut _kb = heapless::String::<32>::new();
psm.remove(fb_key!(index, ST_RCA, _kb)).await?;
psm.remove(fb_key!(index, ST_ICA, _kb)).await?;
psm.remove(fb_key!(index, ST_NOC, _kb)).await?;
psm.remove(fb_key!(index, ST_LBL, _kb)).await?;
psm.remove(fb_key!(index, ST_IPK, _kb)).await?;
psm.remove(fb_key!(index, ST_PBKEY, _kb)).await?;
psm.remove(fb_key!(index, ST_PRKEY, _kb)).await?;
psm.remove(fb_key!(index, ST_VID, _kb)).await?;
Ok(())
}
} }
pub const MAX_SUPPORTED_FABRICS: usize = 3; pub const MAX_SUPPORTED_FABRICS: usize = 3;
type FabricEntries = [Option<Fabric>; MAX_SUPPORTED_FABRICS];
pub struct FabricMgr { pub struct FabricMgr {
// The outside world expects Fabric Index to be one more than the actual one fabrics: FabricEntries,
// since 0 is not allowed. Need to handle this cleanly somehow
fabrics: [Option<Fabric>; MAX_SUPPORTED_FABRICS],
changed: bool, changed: bool,
} }
@ -440,110 +201,54 @@ impl FabricMgr {
} }
} }
pub fn store<T>(&mut self, mut psm: T) -> Result<(), Error> pub fn load(&mut self, data: &[u8], mdns_mgr: &mut MdnsMgr) -> Result<(), Error> {
where for fabric in &self.fabrics {
T: Psm, if let Some(fabric) = fabric {
{ mdns_mgr.unpublish_service(&fabric.mdns_service_name, ServiceMode::Commissioned)?;
}
}
let root = TLVList::new(data).iter().next().ok_or(Error::Invalid)?;
self.fabrics = FabricEntries::from_tlv(&root)?;
for fabric in &self.fabrics {
if let Some(fabric) = fabric {
mdns_mgr.publish_service(&fabric.mdns_service_name, ServiceMode::Commissioned)?;
}
}
self.changed = false;
Ok(())
}
pub fn store<'a>(&mut self, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
if self.changed { if self.changed {
for i in 1..MAX_SUPPORTED_FABRICS { let mut wb = WriteBuf::new(buf);
if let Some(fabric) = self.fabrics[i].as_mut() { let mut tw = TLVWriter::new(&mut wb);
info!("Storing fabric at index {}", i); self.fabrics.to_tlv(&mut tw, TagType::Anonymous)?;
fabric.store(i, &mut psm)?;
} else {
let _ = Fabric::remove(i, &mut psm);
}
}
self.changed = false;
}
Ok(())
}
pub fn load<T>(&mut self, mut psm: T, mdns_mgr: &mut MdnsMgr) -> Result<(), Error>
where
T: Psm,
{
for i in 1..MAX_SUPPORTED_FABRICS {
let result = Fabric::load(i, &mut psm);
if let Ok(fabric) = result {
info!("Adding new fabric at index {}", i);
self.fabrics[i] = Some(fabric);
mdns_mgr.publish_service(
&self.fabrics[i].as_ref().unwrap().mdns_service_name,
ServiceMode::Commissioned,
)?;
} else {
self.fabrics[i] = None;
}
}
self.changed = false; self.changed = false;
Ok(()) let len = tw.get_tail();
}
#[cfg(feature = "nightly")] Ok(Some(&buf[..len]))
pub async fn store_async<T>(&mut self, mut psm: T) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
if self.changed {
for i in 1..MAX_SUPPORTED_FABRICS {
if let Some(fabric) = self.fabrics[i].as_mut() {
info!("Storing fabric at index {}", i);
fabric.store_async(i, &mut psm).await?;
} else { } else {
let _ = Fabric::remove_async(i, &mut psm).await; Ok(None)
} }
} }
self.changed = false;
}
Ok(())
}
#[cfg(feature = "nightly")]
pub async fn load_async<T>(
&mut self,
mut psm: T,
mdns_mgr: &mut MdnsMgr<'_>,
) -> Result<(), Error>
where
T: crate::persist::asynch::AsyncPsm,
{
for i in 1..MAX_SUPPORTED_FABRICS {
let result = Fabric::load_async(i, &mut psm).await;
if let Ok(fabric) = result {
info!("Adding new fabric at index {}", i);
self.fabrics[i] = Some(fabric);
mdns_mgr.publish_service(
&self.fabrics[i].as_ref().unwrap().mdns_service_name,
ServiceMode::Commissioned,
)?;
} else {
self.fabrics[i] = None;
}
}
self.changed = false;
Ok(())
}
pub fn add(&mut self, f: Fabric, mdns_mgr: &mut MdnsMgr) -> Result<u8, Error> { pub fn add(&mut self, f: Fabric, mdns_mgr: &mut MdnsMgr) -> Result<u8, Error> {
for i in 1..MAX_SUPPORTED_FABRICS { for (index, fabric) in self.fabrics.iter_mut().enumerate() {
if self.fabrics[i].is_none() { if fabric.is_none() {
self.fabrics[i] = Some(f); mdns_mgr.publish_service(&f.mdns_service_name, ServiceMode::Commissioned)?;
mdns_mgr.publish_service(
&self.fabrics[i].as_ref().unwrap().mdns_service_name, *fabric = Some(f);
ServiceMode::Commissioned,
)?;
self.changed = true; self.changed = true;
return Ok(i as u8); return Ok((index + 1) as u8);
} }
} }
@ -551,20 +256,24 @@ impl FabricMgr {
} }
pub fn remove(&mut self, fab_idx: u8, mdns_mgr: &mut MdnsMgr) -> Result<(), Error> { pub fn remove(&mut self, fab_idx: u8, mdns_mgr: &mut MdnsMgr) -> Result<(), Error> {
if let Some(f) = self.fabrics[fab_idx as usize].take() { if fab_idx > 0 && fab_idx as usize <= self.fabrics.len() {
if let Some(f) = self.fabrics[(fab_idx - 1) as usize].take() {
mdns_mgr.unpublish_service(&f.mdns_service_name, ServiceMode::Commissioned)?; mdns_mgr.unpublish_service(&f.mdns_service_name, ServiceMode::Commissioned)?;
self.changed = true; self.changed = true;
Ok(()) Ok(())
} else { } else {
Err(Error::NotFound) Err(Error::NotFound)
} }
} else {
Err(Error::NotFound)
}
} }
pub fn match_dest_id(&self, random: &[u8], target: &[u8]) -> Result<usize, Error> { pub fn match_dest_id(&self, random: &[u8], target: &[u8]) -> Result<usize, Error> {
for i in 1..MAX_SUPPORTED_FABRICS { for (index, fabric) in self.fabrics.iter().enumerate() {
if let Some(fabric) = &self.fabrics[i] { if let Some(fabric) = fabric {
if fabric.match_dest_id(random, target).is_ok() { if fabric.match_dest_id(random, target).is_ok() {
return Ok(i); return Ok(index + 1);
} }
} }
} }
@ -572,26 +281,19 @@ impl FabricMgr {
} }
pub fn get_fabric(&self, idx: usize) -> Result<Option<&Fabric>, Error> { pub fn get_fabric(&self, idx: usize) -> Result<Option<&Fabric>, Error> {
Ok(self.fabrics[idx].as_ref()) if idx == 0 {
Ok(None)
} else {
Ok(self.fabrics[idx - 1].as_ref())
}
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
for i in 1..MAX_SUPPORTED_FABRICS { !self.fabrics.iter().any(Option::is_some)
if self.fabrics[i].is_some() {
return false;
}
}
true
} }
pub fn used_count(&self) -> usize { pub fn used_count(&self) -> usize {
let mut count = 0; self.fabrics.iter().filter(|f| f.is_some()).count()
for i in 1..MAX_SUPPORTED_FABRICS {
if self.fabrics[i].is_some() {
count += 1;
}
}
count
} }
// Parameters to T are the Fabric and its Fabric Index // Parameters to T are the Fabric and its Fabric Index
@ -599,25 +301,27 @@ impl FabricMgr {
where where
T: FnMut(&Fabric, u8) -> Result<(), Error>, T: FnMut(&Fabric, u8) -> Result<(), Error>,
{ {
for i in 1..MAX_SUPPORTED_FABRICS { for (index, fabric) in self.fabrics.iter().enumerate() {
if let Some(fabric) = &self.fabrics[i] { if let Some(fabric) = fabric {
f(fabric, i as u8)?; f(fabric, (index + 1) as u8)?;
} }
} }
Ok(()) Ok(())
} }
pub fn set_label(&mut self, index: u8, label: &str) -> Result<(), Error> { pub fn set_label(&mut self, index: u8, label: &str) -> Result<(), Error> {
let index = index as usize;
if !label.is_empty() { if !label.is_empty() {
for i in 1..MAX_SUPPORTED_FABRICS { if self
if let Some(fabric) = &self.fabrics[i] { .fabrics
if fabric.label == label { .iter()
.filter_map(|f| f.as_ref())
.any(|f| f.label == label)
{
return Err(Error::Invalid); return Err(Error::Invalid);
} }
} }
}
} let index = (index - 1) as usize;
if let Some(fabric) = &mut self.fabrics[index] { if let Some(fabric) = &mut self.fabrics[index] {
fabric.label = label.into(); fabric.label = label.into();
self.changed = true; self.changed = true;

View file

@ -15,12 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::{crypto, error::Error}; use crate::{
crypto::{self, SYMM_KEY_LEN_BYTES},
error::Error,
tlv::{FromTLV, TLVElement, TLVWriter, TagType, ToTLV},
};
#[derive(Debug, Default)] type KeySetKey = [u8; SYMM_KEY_LEN_BYTES];
#[derive(Debug, Default, FromTLV, ToTLV)]
pub struct KeySet { pub struct KeySet {
pub epoch_key: [u8; crypto::SYMM_KEY_LEN_BYTES], pub epoch_key: KeySetKey,
pub op_key: [u8; crypto::SYMM_KEY_LEN_BYTES], pub op_key: KeySetKey,
} }
impl KeySet { impl KeySet {

View file

@ -14,216 +14,63 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#[cfg(feature = "std")]
use crate::error::Error; pub use file_psm::*;
pub trait Psm {
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error>;
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error>;
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error>;
fn get_kv_u64(&self, key: &str) -> Result<u64, Error>;
fn remove(&mut self, key: &str) -> Result<(), Error>;
}
impl<T> Psm for &mut T
where
T: Psm,
{
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> {
(**self).set_kv_slice(key, val)
}
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
(**self).get_kv_slice(key, buf)
}
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> {
(**self).set_kv_u64(key, val)
}
fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
(**self).get_kv_u64(key)
}
fn remove(&mut self, key: &str) -> Result<(), Error> {
(**self).remove(key)
}
}
#[cfg(feature = "nightly")]
pub mod asynch {
use crate::error::Error;
use super::Psm;
pub trait AsyncPsm {
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error>;
async fn get_kv_slice<'a, 'b>(
&'a self,
key: &'a str,
buf: &'b mut [u8],
) -> Result<&'b [u8], Error>;
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error>;
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error>;
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error>;
}
impl<T> AsyncPsm for &mut T
where
T: AsyncPsm,
{
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error> {
(**self).set_kv_slice(key, val).await
}
async fn get_kv_slice<'a, 'b>(
&'a self,
key: &'a str,
buf: &'b mut [u8],
) -> Result<&'b [u8], Error> {
(**self).get_kv_slice(key, buf).await
}
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error> {
(**self).set_kv_u64(key, val).await
}
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error> {
(**self).get_kv_u64(key).await
}
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error> {
(**self).remove(key).await
}
}
pub struct Asyncify<T>(pub T);
impl<T> AsyncPsm for Asyncify<T>
where
T: Psm,
{
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error> {
self.0.set_kv_slice(key, val)
}
async fn get_kv_slice<'a, 'b>(
&'a self,
key: &'a str,
buf: &'b mut [u8],
) -> Result<&'b [u8], Error> {
self.0.get_kv_slice(key, buf)
}
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error> {
self.0.set_kv_u64(key, val)
}
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error> {
self.0.get_kv_u64(key)
}
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error> {
self.0.remove(key)
}
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod std { mod file_psm {
use std::fs::{self, DirBuilder, File}; use std::fs;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::PathBuf;
use crate::error::Error; use crate::error::Error;
use super::Psm; pub struct FilePsm {
dir: PathBuf,
pub struct FilePsm {}
const PSM_DIR: &str = "/tmp/matter_psm";
macro_rules! psm_path {
($key:ident) => {
format!("{}/{}", PSM_DIR, $key)
};
} }
impl FilePsm { impl FilePsm {
pub fn new() -> Result<Self, Error> { pub fn new(dir: PathBuf) -> Result<Self, Error> {
let result = DirBuilder::new().create(PSM_DIR); fs::create_dir_all(&dir)?;
if let Err(e) = result {
if e.kind() != std::io::ErrorKind::AlreadyExists { Ok(Self { dir })
return Err(e.into());
}
} }
Ok(Self {}) pub fn load<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
} let path = self.dir.join(key);
pub fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> { match fs::File::open(path) {
let mut f = File::create(psm_path!(key))?; Ok(mut file) => {
f.write_all(val)?;
Ok(())
}
pub fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
let mut f = File::open(psm_path!(key))?;
let mut offset = 0; let mut offset = 0;
loop { loop {
let len = f.read(&mut buf[offset..])?; if offset == buf.len() {
offset += len; return Err(Error::NoSpace);
}
let len = file.read(&mut buf[offset..])?;
if len == 0 { if len == 0 {
break; break;
} }
offset += len;
} }
Ok(&buf[..offset]) Ok(Some(&buf[..offset]))
}
Err(_) => Ok(None),
}
} }
pub fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> { pub fn store(&self, key: &str, data: &[u8]) -> Result<(), Error> {
let mut f = File::create(psm_path!(key))?; let path = self.dir.join(key);
f.write_all(&val.to_be_bytes())?;
let mut file = fs::File::create(path)?;
file.write_all(data)?;
Ok(()) Ok(())
} }
pub fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
let mut f = File::open(psm_path!(key))?;
let mut buf = [0; 8];
f.read_exact(&mut buf)?;
Ok(u64::from_be_bytes(buf))
}
pub fn remove(&self, key: &str) -> Result<(), Error> {
fs::remove_file(psm_path!(key))?;
Ok(())
}
}
impl Psm for FilePsm {
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> {
FilePsm::set_kv_slice(self, key, val)
}
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
FilePsm::get_kv_slice(self, key, buf)
}
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> {
FilePsm::set_kv_u64(self, key, val)
}
fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
FilePsm::get_kv_u64(self, key)
}
fn remove(&mut self, key: &str) -> Result<(), Error> {
FilePsm::remove(self, key)
}
} }
} }

View file

@ -35,26 +35,21 @@ pub trait FromTLV<'a> {
} }
} }
impl<'a, T: Default + FromTLV<'a> + Copy, const N: usize> FromTLV<'a> for [T; N] { impl<'a, T: FromTLV<'a>, const N: usize> FromTLV<'a> for [T; N] {
fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error> fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error>
where where
Self: Sized, Self: Sized,
{ {
t.confirm_array()?; t.confirm_array()?;
let mut a: [T; N] = [Default::default(); N];
let mut index = 0; let mut a = heapless::Vec::<T, N>::new();
if let Some(tlv_iter) = t.enter() { if let Some(tlv_iter) = t.enter() {
for element in tlv_iter { for element in tlv_iter {
if index < N { a.push(T::from_tlv(&element)?).map_err(|_| Error::NoSpace)?;
a[index] = T::from_tlv(&element)?;
index += 1;
} else {
error!("Received TLV Array with elements larger than current size");
break;
} }
} }
}
Ok(a) a.into_array().map_err(|_| Error::Invalid)
} }
} }
@ -114,6 +109,8 @@ totlv_for!(i8 u8 u16 u32 u64 bool);
// //
// - UtfStr, OctetStr: These are versions that map to utfstr and ostr in the TLV spec // - UtfStr, OctetStr: These are versions that map to utfstr and ostr in the TLV spec
// - These only have references into the original list // - These only have references into the original list
// - heapless::String<N>, Vheapless::ec<u8, N>: Is the owned version of utfstr and ostr, data is cloned into this
// - heapless::String is only partially implemented
// //
// - TLVArray: Is an array of entries, with reference within the original list // - TLVArray: Is an array of entries, with reference within the original list
@ -165,6 +162,38 @@ impl<'a> ToTLV for OctetStr<'a> {
} }
} }
/// Implements the Owned version of Octet String
impl<const N: usize> FromTLV<'_> for heapless::Vec<u8, N> {
fn from_tlv(t: &TLVElement) -> Result<heapless::Vec<u8, N>, Error> {
heapless::Vec::from_slice(t.slice()?).map_err(|_| Error::NoSpace)
}
}
impl<const N: usize> ToTLV for heapless::Vec<u8, N> {
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
tw.str16(tag, self.as_slice())
}
}
/// Implements the Owned version of UTF String
impl<const N: usize> FromTLV<'_> for heapless::String<N> {
fn from_tlv(t: &TLVElement) -> Result<heapless::String<N>, Error> {
let mut string = heapless::String::new();
string
.push_str(core::str::from_utf8(t.slice()?)?)
.map_err(|_| Error::NoSpace)?;
Ok(string)
}
}
impl<const N: usize> ToTLV for heapless::String<N> {
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
tw.utf16(tag, self.as_bytes())
}
}
/// Applies to all the Option<> Processing /// Applies to all the Option<> Processing
impl<'a, T: FromTLV<'a>> FromTLV<'a> for Option<T> { impl<'a, T: FromTLV<'a>> FromTLV<'a> for Option<T> {
fn from_tlv(t: &TLVElement<'a>) -> Result<Option<T>, Error> { fn from_tlv(t: &TLVElement<'a>) -> Result<Option<T>, Error> {
@ -259,7 +288,7 @@ impl<'a, T: ToTLV> TLVArray<'a, T> {
} }
} }
impl<'a, T: ToTLV + FromTLV<'a> + Copy> TLVArray<'a, T> { impl<'a, T: ToTLV + FromTLV<'a> + Clone> TLVArray<'a, T> {
pub fn get_index(&self, index: usize) -> T { pub fn get_index(&self, index: usize) -> T {
for (curr, element) in self.iter().enumerate() { for (curr, element) in self.iter().enumerate() {
if curr == index { if curr == index {
@ -270,12 +299,12 @@ impl<'a, T: ToTLV + FromTLV<'a> + Copy> TLVArray<'a, T> {
} }
} }
impl<'a, T: FromTLV<'a> + Copy> Iterator for TLVArrayIter<'a, T> { impl<'a, T: FromTLV<'a> + Clone> Iterator for TLVArrayIter<'a, T> {
type Item = T; type Item = T;
/* Code for going to the next Element */ /* Code for going to the next Element */
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match self { match self {
Self::Slice(s_iter) => s_iter.next().copied(), Self::Slice(s_iter) => s_iter.next().cloned(),
Self::Ptr(p_iter) => { Self::Ptr(p_iter) => {
if let Some(tlv_iter) = p_iter.as_mut() { if let Some(tlv_iter) = p_iter.as_mut() {
let e = tlv_iter.next(); let e = tlv_iter.next();
@ -294,7 +323,7 @@ impl<'a, T: FromTLV<'a> + Copy> Iterator for TLVArrayIter<'a, T> {
impl<'a, T> PartialEq<&[T]> for TLVArray<'a, T> impl<'a, T> PartialEq<&[T]> for TLVArray<'a, T>
where where
T: ToTLV + FromTLV<'a> + Copy + PartialEq, T: ToTLV + FromTLV<'a> + Clone + PartialEq,
{ {
fn eq(&self, other: &&[T]) -> bool { fn eq(&self, other: &&[T]) -> bool {
let mut iter1 = self.iter(); let mut iter1 = self.iter();
@ -313,7 +342,7 @@ where
} }
} }
impl<'a, T: FromTLV<'a> + Copy + ToTLV> ToTLV for TLVArray<'a, T> { impl<'a, T: FromTLV<'a> + Clone + ToTLV> ToTLV for TLVArray<'a, T> {
fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> { fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
tw.start_array(tag_type)?; tw.start_array(tag_type)?;
for a in self.iter() { for a in self.iter() {
@ -340,7 +369,7 @@ impl<'a, T> FromTLV<'a> for TLVArray<'a, T> {
} }
} }
impl<'a, T: Debug + ToTLV + FromTLV<'a> + Copy> Debug for TLVArray<'a, T> { impl<'a, T: Debug + ToTLV + FromTLV<'a> + Clone> Debug for TLVArray<'a, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "TLVArray [")?; write!(f, "TLVArray [")?;
let mut first = true; let mut first = true;