Simple persistance via TLV
This commit is contained in:
parent
1392810a6c
commit
7437cf2c94
10 changed files with 262 additions and 646 deletions
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue