Merge pull request #81 from kedars/bugfix/multiple_ios_fixes
Multiple fixes for iOS support
This commit is contained in:
commit
227bb77ba1
13 changed files with 663 additions and 44 deletions
|
@ -264,8 +264,8 @@ impl<'a> CertConsumer for ASN1Writer<'a> {
|
|||
self.write_str(0x06, oid)
|
||||
}
|
||||
|
||||
fn utctime(&mut self, _tag: &str, epoch: u32) -> Result<(), Error> {
|
||||
let matter_epoch = MATTER_EPOCH_SECS + epoch as u64;
|
||||
fn utctime(&mut self, _tag: &str, epoch: u64) -> Result<(), Error> {
|
||||
let matter_epoch = MATTER_EPOCH_SECS + epoch;
|
||||
|
||||
let dt = OffsetDateTime::from_unix_timestamp(matter_epoch as _).unwrap();
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
crypto::KeyPair,
|
||||
error::{Error, ErrorCode},
|
||||
tlv::{self, FromTLV, OctetStr, TLVArray, TLVElement, TLVWriter, TagType, ToTLV},
|
||||
utils::writebuf::WriteBuf,
|
||||
utils::{epoch::MATTER_CERT_DOESNT_EXPIRE, writebuf::WriteBuf},
|
||||
};
|
||||
use log::error;
|
||||
use num_derive::FromPrimitive;
|
||||
|
@ -650,8 +650,14 @@ impl<'a> Cert<'a> {
|
|||
self.issuer.encode("Issuer:", w)?;
|
||||
|
||||
w.start_seq("Validity:")?;
|
||||
w.utctime("Not Before:", self.not_before)?;
|
||||
w.utctime("Not After:", self.not_after)?;
|
||||
w.utctime("Not Before:", self.not_before.into())?;
|
||||
if self.not_after == 0 {
|
||||
// As per the spec a Not-After value of 0, indicates no well-defined
|
||||
// expiration date and should return in GeneralizedTime of 99991231235959Z
|
||||
w.utctime("Not After:", MATTER_CERT_DOESNT_EXPIRE)?;
|
||||
} else {
|
||||
w.utctime("Not After:", self.not_after.into())?;
|
||||
}
|
||||
w.end_seq()?;
|
||||
|
||||
self.subject.encode("Subject:", w)?;
|
||||
|
@ -710,8 +716,9 @@ impl<'a> CertVerifier<'a> {
|
|||
let k = KeyPair::new_from_public(parent.get_pubkey())?;
|
||||
k.verify_msg(asn1, self.cert.get_signature()).map_err(|e| {
|
||||
error!(
|
||||
"Error in signature verification of certificate: {:x?}",
|
||||
self.cert.get_subject_key_id()
|
||||
"Error in signature verification of certificate: {:x?} by {:x?}",
|
||||
self.cert.get_subject_key_id(),
|
||||
parent.get_subject_key_id()
|
||||
);
|
||||
e
|
||||
})?;
|
||||
|
@ -744,7 +751,7 @@ pub trait CertConsumer {
|
|||
fn start_ctx(&mut self, tag: &str, id: u8) -> Result<(), Error>;
|
||||
fn end_ctx(&mut self) -> Result<(), Error>;
|
||||
fn oid(&mut self, tag: &str, oid: &[u8]) -> Result<(), Error>;
|
||||
fn utctime(&mut self, tag: &str, epoch: u32) -> Result<(), Error>;
|
||||
fn utctime(&mut self, tag: &str, epoch: u64) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
const MAX_DEPTH: usize = 10;
|
||||
|
@ -826,6 +833,16 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_value_of_not_after_field() {
|
||||
let noc = Cert::new(&test_vectors::NOC_NOT_AFTER_ZERO).unwrap();
|
||||
let rca = Cert::new(&test_vectors::RCA_FOR_NOC_NOT_AFTER_ZERO).unwrap();
|
||||
|
||||
let v = noc.verify_chain_start();
|
||||
let v = v.add_cert(&rca).unwrap();
|
||||
v.finalise().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cert_corrupted() {
|
||||
use crate::error::ErrorCode;
|
||||
|
@ -1112,5 +1129,47 @@ mod tests {
|
|||
0x16, 0x80, 0x14, 0x72, 0xc2, 0x01, 0xf7, 0x57, 0x19, 0x13, 0xb3, 0x48, 0xca, 0x00,
|
||||
0xca, 0x7b, 0x45, 0xf4, 0x77, 0x46, 0x68, 0xc9, 0x7e,
|
||||
];
|
||||
|
||||
/// An NOC that contains a Not-After validity field of '0'
|
||||
pub const NOC_NOT_AFTER_ZERO: [u8; 251] = [
|
||||
0x15, 0x30, 0x1, 0x1, 0x1, 0x24, 0x2, 0x1, 0x37, 0x3, 0x27, 0x14, 0xfc, 0x8d, 0xcf,
|
||||
0x45, 0x19, 0xff, 0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x26, 0x4, 0x21, 0x39, 0x5a, 0x2c,
|
||||
0x24, 0x5, 0x0, 0x37, 0x6, 0x24, 0x15, 0x1, 0x26, 0x11, 0x6c, 0x4a, 0x95, 0xd2, 0x18,
|
||||
0x24, 0x7, 0x1, 0x24, 0x8, 0x1, 0x30, 0x9, 0x41, 0x4, 0x41, 0x7f, 0xb1, 0x61, 0xb0,
|
||||
0xbe, 0x19, 0x41, 0x81, 0xb9, 0x9f, 0xe8, 0x7b, 0xdd, 0xdf, 0xc4, 0x46, 0xe0, 0x74,
|
||||
0xba, 0x83, 0x21, 0xda, 0x3d, 0xf7, 0x88, 0x68, 0x14, 0xa6, 0x9d, 0xa9, 0x14, 0x88,
|
||||
0x94, 0x1e, 0xd3, 0x86, 0x62, 0xc7, 0x6f, 0xb4, 0x79, 0xd2, 0xaf, 0x34, 0xe7, 0xd6,
|
||||
0x4d, 0x87, 0x29, 0x67, 0x10, 0x73, 0xb9, 0x81, 0xe0, 0x9, 0xe1, 0x13, 0xbb, 0x6a,
|
||||
0xd2, 0x21, 0xaa, 0x37, 0xa, 0x35, 0x1, 0x28, 0x1, 0x18, 0x24, 0x2, 0x1, 0x36, 0x3,
|
||||
0x4, 0x2, 0x4, 0x1, 0x18, 0x30, 0x4, 0x14, 0x98, 0xaf, 0xa1, 0x3d, 0x41, 0x67, 0x7a,
|
||||
0x34, 0x8c, 0x67, 0x6c, 0xcc, 0x17, 0x6e, 0xd5, 0x58, 0xd8, 0x2b, 0x86, 0x8, 0x30, 0x5,
|
||||
0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe, 0xd1, 0x6f, 0xc5, 0x67, 0xdf, 0x81, 0xd7,
|
||||
0xe9, 0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x18, 0x30, 0xb, 0x40, 0xf9, 0x80, 0x94,
|
||||
0xbf, 0xcf, 0x72, 0xa5, 0x54, 0x87, 0x12, 0x35, 0xc, 0x38, 0x79, 0xa8, 0xb, 0x21, 0x94,
|
||||
0xb5, 0x71, 0x2, 0xcb, 0xb, 0xda, 0xf9, 0x6c, 0x54, 0xcb, 0x50, 0x4b, 0x2, 0x5, 0xea,
|
||||
0xff, 0xfd, 0xb2, 0x1b, 0x24, 0x30, 0x79, 0xb1, 0x69, 0x87, 0xa5, 0x7, 0xc6, 0x76,
|
||||
0x15, 0x70, 0xc0, 0xec, 0x14, 0xd3, 0x9f, 0x1a, 0xa7, 0xe1, 0xca, 0x25, 0x2e, 0x44,
|
||||
0xfc, 0x96, 0x4d, 0x18,
|
||||
];
|
||||
pub const RCA_FOR_NOC_NOT_AFTER_ZERO: [u8; 251] = [
|
||||
0x15, 0x30, 0x1, 0x1, 0x0, 0x24, 0x2, 0x1, 0x37, 0x3, 0x27, 0x14, 0xfc, 0x8d, 0xcf,
|
||||
0x45, 0x19, 0xff, 0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x26, 0x4, 0xb1, 0x2a, 0x38, 0x2c,
|
||||
0x26, 0x5, 0x31, 0x5e, 0x19, 0x2e, 0x37, 0x6, 0x27, 0x14, 0xfc, 0x8d, 0xcf, 0x45, 0x19,
|
||||
0xff, 0x9a, 0x9a, 0x24, 0x15, 0x1, 0x18, 0x24, 0x7, 0x1, 0x24, 0x8, 0x1, 0x30, 0x9,
|
||||
0x41, 0x4, 0x15, 0x69, 0x1e, 0x7b, 0x6a, 0xea, 0x5, 0xdb, 0xf8, 0x4b, 0xfd, 0xdc, 0x6c,
|
||||
0x75, 0x46, 0x74, 0xb0, 0x60, 0xdb, 0x4, 0x71, 0xb6, 0xd0, 0x52, 0xf2, 0xf8, 0xe6,
|
||||
0xbb, 0xd, 0xe5, 0x60, 0x1f, 0x84, 0x66, 0x4f, 0x3c, 0x90, 0x89, 0xa6, 0xc6, 0x99,
|
||||
0x61, 0xfb, 0x89, 0xf7, 0xa, 0xa6, 0xe4, 0xa2, 0x21, 0xd3, 0x37, 0x30, 0x1b, 0xd2,
|
||||
0x11, 0xc5, 0xcc, 0x0, 0xf4, 0x7a, 0x14, 0xfc, 0x3c, 0x37, 0xa, 0x35, 0x1, 0x29, 0x1,
|
||||
0x18, 0x24, 0x2, 0x60, 0x30, 0x4, 0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe, 0xd1, 0x6f,
|
||||
0xc5, 0x67, 0xdf, 0x81, 0xd7, 0xe9, 0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x30, 0x5,
|
||||
0x14, 0xf8, 0xcf, 0xd0, 0x45, 0x6b, 0xe, 0xd1, 0x6f, 0xc5, 0x67, 0xdf, 0x81, 0xd7,
|
||||
0xe9, 0xb7, 0xeb, 0x39, 0x78, 0xec, 0x40, 0x18, 0x30, 0xb, 0x40, 0x4c, 0xae, 0xac,
|
||||
0xc1, 0x26, 0xdd, 0x56, 0xc, 0x85, 0x86, 0xbc, 0xeb, 0xa2, 0xb5, 0xb7, 0xdf, 0x49,
|
||||
0x92, 0x62, 0xcd, 0x2a, 0xb6, 0x4e, 0xc5, 0x31, 0x7c, 0xd9, 0xb, 0x1c, 0xe9, 0x6e,
|
||||
0xe5, 0x82, 0xc7, 0xb8, 0xda, 0x22, 0x31, 0x7b, 0x23, 0x5a, 0x2a, 0xe6, 0x76, 0x28,
|
||||
0xb6, 0xd4, 0xc7, 0x7b, 0x1c, 0x9c, 0x85, 0x71, 0x5f, 0xe6, 0xf6, 0x21, 0x50, 0x5c,
|
||||
0xa7, 0x7c, 0xc7, 0x1d, 0x9a, 0x18,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,8 +122,8 @@ impl<'a, 'b> CertConsumer for CertPrinter<'a, 'b> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
fn utctime(&mut self, tag: &str, epoch: u32) -> Result<(), Error> {
|
||||
let matter_epoch = MATTER_EPOCH_SECS + epoch as u64;
|
||||
fn utctime(&mut self, tag: &str, epoch: u64) -> Result<(), Error> {
|
||||
let matter_epoch = MATTER_EPOCH_SECS + epoch;
|
||||
|
||||
let dt = OffsetDateTime::from_unix_timestamp(matter_epoch as _).unwrap();
|
||||
|
||||
|
|
|
@ -15,8 +15,12 @@ use super::{
|
|||
sdm::{
|
||||
admin_commissioning::{self, AdminCommCluster},
|
||||
dev_att::DevAttDataFetcher,
|
||||
ethernet_nw_diagnostics::{self, EthNwDiagCluster},
|
||||
failsafe::FailSafe,
|
||||
general_commissioning::{self, GenCommCluster},
|
||||
general_diagnostics::{self, GenDiagCluster},
|
||||
group_key_management,
|
||||
group_key_management::GrpKeyMgmtCluster,
|
||||
noc::{self, NocCluster},
|
||||
nw_commissioning::{self, NwCommCluster},
|
||||
},
|
||||
|
@ -33,10 +37,13 @@ pub type RootEndpointHandler<'a> = handler_chain_type!(
|
|||
NwCommCluster,
|
||||
AdminCommCluster<'a>,
|
||||
NocCluster<'a>,
|
||||
AccessControlCluster<'a>
|
||||
AccessControlCluster<'a>,
|
||||
GenDiagCluster,
|
||||
EthNwDiagCluster,
|
||||
GrpKeyMgmtCluster
|
||||
);
|
||||
|
||||
pub const CLUSTERS: [Cluster<'static>; 7] = [
|
||||
pub const CLUSTERS: [Cluster<'static>; 10] = [
|
||||
descriptor::CLUSTER,
|
||||
cluster_basic_information::CLUSTER,
|
||||
general_commissioning::CLUSTER,
|
||||
|
@ -44,6 +51,9 @@ pub const CLUSTERS: [Cluster<'static>; 7] = [
|
|||
admin_commissioning::CLUSTER,
|
||||
noc::CLUSTER,
|
||||
access_control::CLUSTER,
|
||||
general_diagnostics::CLUSTER,
|
||||
ethernet_nw_diagnostics::CLUSTER,
|
||||
group_key_management::CLUSTER,
|
||||
];
|
||||
|
||||
pub const fn endpoint(id: EndptId) -> Endpoint<'static> {
|
||||
|
@ -95,6 +105,21 @@ pub fn wrap<'a>(
|
|||
rand: Rand,
|
||||
) -> RootEndpointHandler<'a> {
|
||||
EmptyHandler
|
||||
.chain(
|
||||
endpoint_id,
|
||||
group_key_management::ID,
|
||||
GrpKeyMgmtCluster::new(rand),
|
||||
)
|
||||
.chain(
|
||||
endpoint_id,
|
||||
ethernet_nw_diagnostics::ID,
|
||||
EthNwDiagCluster::new(rand),
|
||||
)
|
||||
.chain(
|
||||
endpoint_id,
|
||||
general_diagnostics::ID,
|
||||
GenDiagCluster::new(rand),
|
||||
)
|
||||
.chain(
|
||||
endpoint_id,
|
||||
access_control::ID,
|
||||
|
|
146
rs-matter/src/data_model/sdm/ethernet_nw_diagnostics.rs
Normal file
146
rs-matter/src/data_model/sdm/ethernet_nw_diagnostics.rs
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2023 Project CHIP Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
use crate::{
|
||||
attribute_enum, cmd_enter, command_enum, data_model::objects::AttrType, data_model::objects::*,
|
||||
error::Error, tlv::TLVElement, transport::exchange::Exchange, utils::rand::Rand,
|
||||
};
|
||||
use log::info;
|
||||
use strum::{EnumDiscriminants, FromRepr};
|
||||
|
||||
pub const ID: u32 = 0x0037;
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u16)]
|
||||
pub enum Attributes {
|
||||
PacketRxCount(AttrType<u64>) = 0x02,
|
||||
PacketTxCount(AttrType<u64>) = 0x03,
|
||||
}
|
||||
|
||||
attribute_enum!(Attributes);
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u32)]
|
||||
pub enum Commands {
|
||||
ResetCounts = 0x0,
|
||||
}
|
||||
|
||||
command_enum!(Commands);
|
||||
|
||||
pub const CLUSTER: Cluster<'static> = Cluster {
|
||||
id: ID as _,
|
||||
feature_map: 0,
|
||||
attributes: &[
|
||||
FEATURE_MAP,
|
||||
ATTRIBUTE_LIST,
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::PacketRxCount as u16,
|
||||
Access::RV,
|
||||
Quality::NONE,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::PacketTxCount as u16,
|
||||
Access::RV,
|
||||
Quality::FIXED,
|
||||
),
|
||||
],
|
||||
commands: &[CommandsDiscriminants::ResetCounts as _],
|
||||
};
|
||||
|
||||
pub struct EthNwDiagCluster {
|
||||
data_ver: Dataver,
|
||||
}
|
||||
|
||||
impl EthNwDiagCluster {
|
||||
pub fn new(rand: Rand) -> Self {
|
||||
Self {
|
||||
data_ver: Dataver::new(rand),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
if let Some(writer) = encoder.with_dataver(self.data_ver.get())? {
|
||||
if attr.is_system() {
|
||||
CLUSTER.read(attr.attr_id, writer)
|
||||
} else {
|
||||
match attr.attr_id.try_into()? {
|
||||
Attributes::PacketRxCount(codec) => codec.encode(writer, 1),
|
||||
Attributes::PacketTxCount(codec) => codec.encode(writer, 1),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, _attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
let _data = data.with_dataver(self.data_ver.get())?;
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn invoke(
|
||||
&self,
|
||||
_exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
_data: &TLVElement,
|
||||
_encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
match cmd.cmd_id.try_into()? {
|
||||
Commands::ResetCounts => {
|
||||
cmd_enter!("ResetCounts: Not yet supported");
|
||||
}
|
||||
}
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for EthNwDiagCluster {
|
||||
fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
EthNwDiagCluster::read(self, attr, encoder)
|
||||
}
|
||||
|
||||
fn write(&self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
EthNwDiagCluster::write(self, attr, data)
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
&self,
|
||||
exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
data: &TLVElement,
|
||||
encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
EthNwDiagCluster::invoke(self, exchange, cmd, data, encoder)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Might be removed once the `on` member is externalized
|
||||
impl NonBlockingHandler for EthNwDiagCluster {}
|
||||
|
||||
impl ChangeNotifier<()> for EthNwDiagCluster {
|
||||
fn consume_change(&mut self) -> Option<()> {
|
||||
self.data_ver.consume_change(())
|
||||
}
|
||||
}
|
|
@ -121,9 +121,15 @@ struct FailSafeParams {
|
|||
bread_crumb: u8,
|
||||
}
|
||||
|
||||
#[derive(ToTLV)]
|
||||
struct BasicCommissioningInfo {
|
||||
expiry_len: u16,
|
||||
max_cmltv_failsafe_secs: u16,
|
||||
}
|
||||
|
||||
pub struct GenCommCluster<'a> {
|
||||
data_ver: Dataver,
|
||||
expiry_len: u16,
|
||||
basic_comm_info: BasicCommissioningInfo,
|
||||
failsafe: &'a RefCell<FailSafe>,
|
||||
}
|
||||
|
||||
|
@ -133,7 +139,10 @@ impl<'a> GenCommCluster<'a> {
|
|||
data_ver: Dataver::new(rand),
|
||||
failsafe,
|
||||
// TODO: Arch-Specific
|
||||
expiry_len: 120,
|
||||
basic_comm_info: BasicCommissioningInfo {
|
||||
expiry_len: 120,
|
||||
max_cmltv_failsafe_secs: 120,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,10 +166,8 @@ impl<'a> GenCommCluster<'a> {
|
|||
codec.encode(writer, RegLocationType::IndoorOutdoor as _)
|
||||
}
|
||||
Attributes::BasicCommissioningInfo(_) => {
|
||||
writer.start_struct(AttrDataWriter::TAG)?;
|
||||
writer.u16(TagType::Context(0), self.expiry_len)?;
|
||||
writer.end_container()?;
|
||||
|
||||
self.basic_comm_info
|
||||
.to_tlv(&mut writer, AttrDataWriter::TAG)?;
|
||||
writer.complete()
|
||||
}
|
||||
}
|
||||
|
|
157
rs-matter/src/data_model/sdm/general_diagnostics.rs
Normal file
157
rs-matter/src/data_model/sdm/general_diagnostics.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2023 Project CHIP Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
use crate::{
|
||||
attribute_enum, cmd_enter, command_enum,
|
||||
data_model::objects::AttrType,
|
||||
data_model::objects::*,
|
||||
error::{Error, ErrorCode},
|
||||
tlv::TLVElement,
|
||||
transport::exchange::Exchange,
|
||||
utils::rand::Rand,
|
||||
};
|
||||
use log::info;
|
||||
use strum::{EnumDiscriminants, FromRepr};
|
||||
|
||||
pub const ID: u32 = 0x0033;
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u16)]
|
||||
pub enum Attributes {
|
||||
NetworkInterfaces(()) = 0x00,
|
||||
RebootCount(AttrType<u16>) = 0x01,
|
||||
TestEventTriggersEnabled(AttrType<bool>) = 0x08,
|
||||
}
|
||||
|
||||
attribute_enum!(Attributes);
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u32)]
|
||||
pub enum Commands {
|
||||
TestEventTrigger = 0x0,
|
||||
}
|
||||
|
||||
command_enum!(Commands);
|
||||
|
||||
pub const CLUSTER: Cluster<'static> = Cluster {
|
||||
id: ID as _,
|
||||
feature_map: 0,
|
||||
attributes: &[
|
||||
FEATURE_MAP,
|
||||
ATTRIBUTE_LIST,
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::NetworkInterfaces as u16,
|
||||
Access::RV,
|
||||
Quality::NONE,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::RebootCount as u16,
|
||||
Access::RV,
|
||||
Quality::PERSISTENT,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::TestEventTriggersEnabled as u16,
|
||||
Access::RV,
|
||||
Quality::NONE,
|
||||
),
|
||||
],
|
||||
commands: &[CommandsDiscriminants::TestEventTrigger as _],
|
||||
};
|
||||
|
||||
pub struct GenDiagCluster {
|
||||
data_ver: Dataver,
|
||||
}
|
||||
|
||||
impl GenDiagCluster {
|
||||
pub fn new(rand: Rand) -> Self {
|
||||
Self {
|
||||
data_ver: Dataver::new(rand),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
if let Some(writer) = encoder.with_dataver(self.data_ver.get())? {
|
||||
if attr.is_system() {
|
||||
CLUSTER.read(attr.attr_id, writer)
|
||||
} else {
|
||||
match attr.attr_id.try_into()? {
|
||||
Attributes::RebootCount(codec) => codec.encode(writer, 1),
|
||||
_ => Err(ErrorCode::AttributeNotFound.into()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, _attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
let _data = data.with_dataver(self.data_ver.get())?;
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn invoke(
|
||||
&self,
|
||||
_exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
_data: &TLVElement,
|
||||
_encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
match cmd.cmd_id.try_into()? {
|
||||
Commands::TestEventTrigger => {
|
||||
cmd_enter!("TestEventTrigger: Not yet supported");
|
||||
}
|
||||
}
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for GenDiagCluster {
|
||||
fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
GenDiagCluster::read(self, attr, encoder)
|
||||
}
|
||||
|
||||
fn write(&self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
GenDiagCluster::write(self, attr, data)
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
&self,
|
||||
exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
data: &TLVElement,
|
||||
encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
GenDiagCluster::invoke(self, exchange, cmd, data, encoder)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Might be removed once the `on` member is externalized
|
||||
impl NonBlockingHandler for GenDiagCluster {}
|
||||
|
||||
impl ChangeNotifier<()> for GenDiagCluster {
|
||||
fn consume_change(&mut self) -> Option<()> {
|
||||
self.data_ver.consume_change(())
|
||||
}
|
||||
}
|
164
rs-matter/src/data_model/sdm/group_key_management.rs
Normal file
164
rs-matter/src/data_model/sdm/group_key_management.rs
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2023 Project CHIP Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
use crate::{
|
||||
attribute_enum, cmd_enter, command_enum,
|
||||
data_model::objects::AttrType,
|
||||
data_model::objects::*,
|
||||
error::{Error, ErrorCode},
|
||||
tlv::TLVElement,
|
||||
transport::exchange::Exchange,
|
||||
utils::rand::Rand,
|
||||
};
|
||||
use log::info;
|
||||
use strum::{EnumDiscriminants, FromRepr};
|
||||
|
||||
pub const ID: u32 = 0x003F;
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u16)]
|
||||
pub enum Attributes {
|
||||
GroupKeyMap(()) = 0x00,
|
||||
GroupTable(()) = 0x01,
|
||||
MaxGroupsPerFabric(AttrType<u16>) = 0x02,
|
||||
MaxGroupKeysPerFabric(AttrType<u16>) = 0x03,
|
||||
}
|
||||
|
||||
attribute_enum!(Attributes);
|
||||
|
||||
#[derive(FromRepr, EnumDiscriminants)]
|
||||
#[repr(u32)]
|
||||
pub enum Commands {
|
||||
KeySetWrite = 0x0,
|
||||
}
|
||||
|
||||
command_enum!(Commands);
|
||||
|
||||
pub const CLUSTER: Cluster<'static> = Cluster {
|
||||
id: ID as _,
|
||||
feature_map: 0,
|
||||
attributes: &[
|
||||
FEATURE_MAP,
|
||||
ATTRIBUTE_LIST,
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::GroupKeyMap as u16,
|
||||
Access::RWFVM,
|
||||
Quality::PERSISTENT,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::GroupTable as u16,
|
||||
Access::RF,
|
||||
Quality::NONE,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::MaxGroupsPerFabric as u16,
|
||||
Access::READ,
|
||||
Quality::FIXED,
|
||||
),
|
||||
Attribute::new(
|
||||
AttributesDiscriminants::MaxGroupKeysPerFabric as u16,
|
||||
Access::READ,
|
||||
Quality::FIXED,
|
||||
),
|
||||
],
|
||||
commands: &[CommandsDiscriminants::KeySetWrite as _],
|
||||
};
|
||||
|
||||
pub struct GrpKeyMgmtCluster {
|
||||
data_ver: Dataver,
|
||||
}
|
||||
|
||||
impl GrpKeyMgmtCluster {
|
||||
pub fn new(rand: Rand) -> Self {
|
||||
Self {
|
||||
data_ver: Dataver::new(rand),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
if let Some(writer) = encoder.with_dataver(self.data_ver.get())? {
|
||||
if attr.is_system() {
|
||||
CLUSTER.read(attr.attr_id, writer)
|
||||
} else {
|
||||
match attr.attr_id.try_into()? {
|
||||
Attributes::MaxGroupsPerFabric(codec) => codec.encode(writer, 1),
|
||||
Attributes::MaxGroupKeysPerFabric(codec) => codec.encode(writer, 1),
|
||||
_ => Err(ErrorCode::AttributeNotFound.into()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, _attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
let _data = data.with_dataver(self.data_ver.get())?;
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn invoke(
|
||||
&self,
|
||||
_exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
_data: &TLVElement,
|
||||
_encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
match cmd.cmd_id.try_into()? {
|
||||
Commands::KeySetWrite => {
|
||||
cmd_enter!("KeySetWrite: Not yet supported");
|
||||
}
|
||||
}
|
||||
|
||||
self.data_ver.changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for GrpKeyMgmtCluster {
|
||||
fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> {
|
||||
GrpKeyMgmtCluster::read(self, attr, encoder)
|
||||
}
|
||||
|
||||
fn write(&self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> {
|
||||
GrpKeyMgmtCluster::write(self, attr, data)
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
&self,
|
||||
exchange: &Exchange,
|
||||
cmd: &CmdDetails,
|
||||
data: &TLVElement,
|
||||
encoder: CmdDataEncoder,
|
||||
) -> Result<(), Error> {
|
||||
GrpKeyMgmtCluster::invoke(self, exchange, cmd, data, encoder)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Might be removed once the `on` member is externalized
|
||||
impl NonBlockingHandler for GrpKeyMgmtCluster {}
|
||||
|
||||
impl ChangeNotifier<()> for GrpKeyMgmtCluster {
|
||||
fn consume_change(&mut self) -> Option<()> {
|
||||
self.data_ver.consume_change(())
|
||||
}
|
||||
}
|
|
@ -17,7 +17,10 @@
|
|||
|
||||
pub mod admin_commissioning;
|
||||
pub mod dev_att;
|
||||
pub mod ethernet_nw_diagnostics;
|
||||
pub mod failsafe;
|
||||
pub mod general_commissioning;
|
||||
pub mod general_diagnostics;
|
||||
pub mod group_key_management;
|
||||
pub mod noc;
|
||||
pub mod nw_commissioning;
|
||||
|
|
|
@ -186,7 +186,7 @@ struct NocResp<'a> {
|
|||
#[tlvargs(lifetime = "'a")]
|
||||
struct AddNocReq<'a> {
|
||||
noc_value: OctetStr<'a>,
|
||||
icac_value: OctetStr<'a>,
|
||||
icac_value: Option<OctetStr<'a>>,
|
||||
ipk_value: OctetStr<'a>,
|
||||
case_admin_subject: u64,
|
||||
vendor_id: u16,
|
||||
|
@ -358,13 +358,17 @@ impl<'a> NocCluster<'a> {
|
|||
|
||||
let noc = heapless::Vec::from_slice(r.noc_value.0).map_err(|_| NocStatus::InvalidNOC)?;
|
||||
|
||||
let icac = if !r.icac_value.0.is_empty() {
|
||||
let icac_cert = Cert::new(r.icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
|
||||
info!("Received ICAC as: {}", icac_cert);
|
||||
let icac = if let Some(icac_value) = r.icac_value {
|
||||
if !icac_value.0.is_empty() {
|
||||
let icac_cert = Cert::new(icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
|
||||
info!("Received ICAC as: {}", icac_cert);
|
||||
|
||||
let icac =
|
||||
heapless::Vec::from_slice(r.icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
|
||||
Some(icac)
|
||||
let icac =
|
||||
heapless::Vec::from_slice(icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
|
||||
Some(icac)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -601,6 +605,20 @@ impl<'a> NocCluster<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn add_rca_to_session_noc_data(exchange: &Exchange, data: &TLVElement) -> Result<(), Error> {
|
||||
exchange.with_session_mut(|sess| {
|
||||
let noc_data = sess.get_noc_data().ok_or(ErrorCode::NoSession)?;
|
||||
|
||||
let req = CommonReq::from_tlv(data).map_err(Error::map_invalid_command)?;
|
||||
info!("Received Trusted Cert:{:x?}", req.str);
|
||||
|
||||
noc_data.root_ca =
|
||||
heapless::Vec::from_slice(req.str.0).map_err(|_| ErrorCode::BufferTooSmall)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_command_addtrustedrootcert(
|
||||
&self,
|
||||
exchange: &Exchange,
|
||||
|
@ -613,21 +631,12 @@ impl<'a> NocCluster<'a> {
|
|||
|
||||
// This may happen on CASE or PASE. For PASE, the existence of NOC Data is necessary
|
||||
match exchange.with_session(|sess| Ok(sess.get_session_mode().clone()))? {
|
||||
SessionMode::Case(_) => error!("CASE: AddTrustedRootCert handling pending"), // For a CASE Session, we just return success for now,
|
||||
SessionMode::Case(_) => {
|
||||
// TODO - Updating the Trusted RCA of an existing Fabric
|
||||
Self::add_rca_to_session_noc_data(exchange, data)?;
|
||||
}
|
||||
SessionMode::Pase => {
|
||||
exchange.with_session_mut(|sess| {
|
||||
let noc_data = sess.get_noc_data().ok_or(ErrorCode::NoSession)?;
|
||||
|
||||
let req = CommonReq::from_tlv(data).map_err(Error::map_invalid_command)?;
|
||||
info!("Received Trusted Cert:{:x?}", req.str);
|
||||
|
||||
noc_data.root_ca = heapless::Vec::from_slice(req.str.0)
|
||||
.map_err(|_| ErrorCode::BufferTooSmall)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// TODO
|
||||
Self::add_rca_to_session_noc_data(exchange, data)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ use crate::{
|
|||
|
||||
const COMPRESSED_FABRIC_ID_LEN: usize = 8;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, ToTLV)]
|
||||
#[tlvargs(lifetime = "'a", start = 1)]
|
||||
pub struct FabricDescriptor<'a> {
|
||||
|
|
|
@ -2,6 +2,11 @@ use core::time::Duration;
|
|||
|
||||
pub type Epoch = fn() -> Duration;
|
||||
|
||||
// As per the spec, if Not After is 0, it should set the time to GeneralizedTime value of
|
||||
// 99991231235959Z
|
||||
// So CERT_DOESNT_EXPIRE value is calculated as epoch(99991231235959Z) - MATTER_EPOCH_SECS
|
||||
pub const MATTER_CERT_DOESNT_EXPIRE: u64 = 252455615999;
|
||||
|
||||
pub const MATTER_EPOCH_SECS: u64 = 946684800; // Seconds from 1970/01/01 00:00:00 till 2000/01/01 00:00:00 UTC
|
||||
|
||||
pub fn dummy_epoch() -> Duration {
|
||||
|
|
|
@ -19,7 +19,10 @@ use rs_matter::{
|
|||
data_model::{
|
||||
cluster_basic_information as basic_info, cluster_on_off as onoff,
|
||||
objects::{EncodeValue, GlobalElements},
|
||||
sdm::{admin_commissioning as adm_comm, general_commissioning as gen_comm, noc},
|
||||
sdm::{
|
||||
admin_commissioning as adm_comm, general_commissioning as gen_comm, noc,
|
||||
nw_commissioning,
|
||||
},
|
||||
system_model::{access_control as acl, descriptor},
|
||||
},
|
||||
interaction_model::{
|
||||
|
@ -130,6 +133,48 @@ fn wildcard_read_resp(part: u8) -> Vec<AttrResp<'static>> {
|
|||
),
|
||||
attr_data!(0, 49, GlobalElements::FeatureMap, dont_care.clone()),
|
||||
attr_data!(0, 49, GlobalElements::AttributeList, dont_care.clone()),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::MaxNetworks,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::Networks,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::ConnectMaxTimeSecs,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::InterfaceEnabled,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::LastNetworkingStatus,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::LastNetworkID,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(
|
||||
0,
|
||||
49,
|
||||
nw_commissioning::Attributes::LastConnectErrorValue,
|
||||
dont_care.clone()
|
||||
),
|
||||
attr_data!(0, 60, GlobalElements::FeatureMap, dont_care.clone()),
|
||||
attr_data!(0, 60, GlobalElements::AttributeList, dont_care.clone()),
|
||||
attr_data!(
|
||||
|
@ -158,6 +203,9 @@ fn wildcard_read_resp(part: u8) -> Vec<AttrResp<'static>> {
|
|||
noc::AttributesDiscriminants::CurrentFabricIndex,
|
||||
dont_care.clone()
|
||||
),
|
||||
];
|
||||
|
||||
let part2 = vec![
|
||||
attr_data!(
|
||||
0,
|
||||
62,
|
||||
|
@ -185,9 +233,6 @@ fn wildcard_read_resp(part: u8) -> Vec<AttrResp<'static>> {
|
|||
acl::AttributesDiscriminants::Extension,
|
||||
dont_care.clone()
|
||||
),
|
||||
];
|
||||
|
||||
let part2 = vec![
|
||||
attr_data!(
|
||||
0,
|
||||
31,
|
||||
|
|
Loading…
Add table
Reference in a new issue