diff --git a/Cargo.toml b/Cargo.toml index f785efa..2e96456 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,3 @@ exclude = ["examples/*"] smol = { git = "https://github.com/esp-rs-compat/smol" } polling = { git = "https://github.com/esp-rs-compat/polling" } socket2 = { git = "https://github.com/esp-rs-compat/socket2" } -chrono = { git = "https://github.com/ivmarkov/chrono" } -time = { git = "https://github.com/ivmarkov/time", branch = "master" } diff --git a/matter/Cargo.toml b/matter/Cargo.toml index a1f0840..1e25757 100644 --- a/matter/Cargo.toml +++ b/matter/Cargo.toml @@ -16,7 +16,7 @@ path = "src/lib.rs" [features] default = ["std", "crypto_mbedtls", "backtrace"] -std = ["alloc", "env_logger", "chrono", "time", "rand", "qrcode", "libmdns", "simple-mdns", "simple-dns", "async-io", "smol"] +std = ["alloc", "env_logger", "rand", "qrcode", "libmdns", "simple-mdns", "simple-dns", "async-io", "smol"] backtrace = [] alloc = [] nightly = [] @@ -38,11 +38,10 @@ no-std-net = "0.6" subtle = "2.4.1" safemem = "0.3.3" owo-colors = "3" +time = { version = "0.3", default-features = false } verhoeff = { version = "1", default-features = false } # STD-only dependencies -chrono = { version = "=0.4.19", optional = true, default-features = false, features = ["clock", "std"] } # =0.4.19 for compatibility with ESP IDF -time = { version = "0.1", optional = true, default-features = false } rand = { version = "0.8.5", optional = true } qrcode = { version = "0.12", default-features = false, optional = true } # Print QR code simple-mdns = { version = "0.4", features = ["sync"], optional = true } diff --git a/matter/src/cert/asn1_writer.rs b/matter/src/cert/asn1_writer.rs index 4afd6b6..87fac3c 100644 --- a/matter/src/cert/asn1_writer.rs +++ b/matter/src/cert/asn1_writer.rs @@ -15,12 +15,14 @@ * limitations under the License. */ +use time::OffsetDateTime; + use super::{CertConsumer, MAX_DEPTH}; use crate::{ error::{Error, ErrorCode}, - utils::epoch::{UtcCalendar, MATTER_EPOCH_SECS}, + utils::epoch::MATTER_EPOCH_SECS, }; -use core::{fmt::Write, time::Duration}; +use core::fmt::Write; #[derive(Debug)] pub struct ASN1Writer<'a> { @@ -262,19 +264,24 @@ impl<'a> CertConsumer for ASN1Writer<'a> { self.write_str(0x06, oid) } - fn utctime(&mut self, _tag: &str, epoch: u32, utc_calendar: UtcCalendar) -> Result<(), Error> { + fn utctime(&mut self, _tag: &str, epoch: u32) -> Result<(), Error> { let matter_epoch = MATTER_EPOCH_SECS + epoch as u64; - let dt = utc_calendar(Duration::from_secs(matter_epoch as _)); + let dt = OffsetDateTime::from_unix_timestamp(matter_epoch as _).unwrap(); let mut time_str: heapless::String<32> = heapless::String::<32>::new(); - if dt.year >= 2050 { + if dt.year() >= 2050 { // If year is >= 2050, ASN.1 requires it to be Generalised Time write!( &mut time_str, "{:04}{:02}{:02}{:02}{:02}{:02}Z", - dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second + dt.year(), + dt.month() as u8, + dt.day(), + dt.hour(), + dt.minute(), + dt.second() ) .unwrap(); self.write_str(0x18, time_str.as_bytes()) @@ -282,12 +289,12 @@ impl<'a> CertConsumer for ASN1Writer<'a> { write!( &mut time_str, "{:02}{:02}{:02}{:02}{:02}{:02}Z", - dt.year % 100, - dt.month, - dt.day, - dt.hour, - dt.minute, - dt.second + dt.year() % 100, + dt.month() as u8, + dt.day(), + dt.hour(), + dt.minute(), + dt.second() ) .unwrap(); self.write_str(0x17, time_str.as_bytes()) diff --git a/matter/src/cert/mod.rs b/matter/src/cert/mod.rs index 0ec6dd5..8878622 100644 --- a/matter/src/cert/mod.rs +++ b/matter/src/cert/mod.rs @@ -21,7 +21,7 @@ use crate::{ crypto::KeyPair, error::{Error, ErrorCode}, tlv::{self, FromTLV, OctetStr, TLVArray, TLVElement, TLVWriter, TagType, ToTLV}, - utils::{epoch::UtcCalendar, writebuf::WriteBuf}, + utils::writebuf::WriteBuf, }; use log::error; use num_derive::FromPrimitive; @@ -621,21 +621,17 @@ impl<'a> Cert<'a> { Ok(wb.as_slice().len()) } - pub fn as_asn1(&self, buf: &mut [u8], utc_calendar: UtcCalendar) -> Result { + pub fn as_asn1(&self, buf: &mut [u8]) -> Result { let mut w = ASN1Writer::new(buf); - self.encode(&mut w, Some(utc_calendar))?; + self.encode(&mut w)?; Ok(w.as_slice().len()) } - pub fn verify_chain_start(&self, utc_calendar: UtcCalendar) -> CertVerifier { - CertVerifier::new(self, utc_calendar) + pub fn verify_chain_start(&self) -> CertVerifier { + CertVerifier::new(self) } - fn encode( - &self, - w: &mut dyn CertConsumer, - utc_calendar: Option, - ) -> Result<(), Error> { + fn encode(&self, w: &mut dyn CertConsumer) -> Result<(), Error> { w.start_seq("")?; w.start_ctx("Version:", 0)?; @@ -654,10 +650,8 @@ impl<'a> Cert<'a> { self.issuer.encode("Issuer:", w)?; w.start_seq("Validity:")?; - if let Some(utc_calendar) = utc_calendar { - w.utctime("Not Before:", self.not_before, utc_calendar)?; - w.utctime("Not After:", self.not_after, utc_calendar)?; - } + w.utctime("Not Before:", self.not_before)?; + w.utctime("Not After:", self.not_after)?; w.end_seq()?; self.subject.encode("Subject:", w)?; @@ -689,7 +683,7 @@ impl<'a> fmt::Display for Cert<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut printer = CertPrinter::new(f); let _ = self - .encode(&mut printer, None) + .encode(&mut printer) .map_err(|e| error!("Error decoding certificate: {}", e)); // Signature is not encoded by the Cert Decoder writeln!(f, "Signature: {:x?}", self.get_signature()) @@ -698,12 +692,11 @@ impl<'a> fmt::Display for Cert<'a> { pub struct CertVerifier<'a> { cert: &'a Cert<'a>, - utc_calendar: UtcCalendar, } impl<'a> CertVerifier<'a> { - pub fn new(cert: &'a Cert, utc_calendar: UtcCalendar) -> Self { - Self { cert, utc_calendar } + pub fn new(cert: &'a Cert) -> Self { + Self { cert } } pub fn add_cert(self, parent: &'a Cert) -> Result, Error> { @@ -711,7 +704,7 @@ impl<'a> CertVerifier<'a> { Err(ErrorCode::InvalidAuthKey)?; } let mut asn1 = [0u8; MAX_ASN1_CERT_SIZE]; - let len = self.cert.as_asn1(&mut asn1, self.utc_calendar)?; + let len = self.cert.as_asn1(&mut asn1)?; let asn1 = &asn1[..len]; let k = KeyPair::new_from_public(parent.get_pubkey())?; @@ -724,7 +717,7 @@ impl<'a> CertVerifier<'a> { })?; // TODO: other validation checks - Ok(CertVerifier::new(parent, self.utc_calendar)) + Ok(CertVerifier::new(parent)) } pub fn finalise(self) -> Result<(), Error> { @@ -751,7 +744,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, utc_calendar: UtcCalendar) -> Result<(), Error>; + fn utctime(&mut self, tag: &str, epoch: u32) -> Result<(), Error>; } const MAX_DEPTH: usize = 10; @@ -768,44 +761,36 @@ mod tests { use crate::tlv::{self, FromTLV, TLVWriter, TagType, ToTLV}; use crate::utils::writebuf::WriteBuf; - #[cfg(feature = "std")] #[test] fn test_asn1_encode_success() { { let mut asn1_buf = [0u8; 1000]; let c = Cert::new(&test_vectors::CHIP_CERT_INPUT1).unwrap(); - let len = c - .as_asn1(&mut asn1_buf, crate::utils::epoch::sys_utc_calendar) - .unwrap(); + let len = c.as_asn1(&mut asn1_buf).unwrap(); assert_eq!(&test_vectors::ASN1_OUTPUT1, &asn1_buf[..len]); } { let mut asn1_buf = [0u8; 1000]; let c = Cert::new(&test_vectors::CHIP_CERT_INPUT2).unwrap(); - let len = c - .as_asn1(&mut asn1_buf, crate::utils::epoch::sys_utc_calendar) - .unwrap(); + let len = c.as_asn1(&mut asn1_buf).unwrap(); assert_eq!(&test_vectors::ASN1_OUTPUT2, &asn1_buf[..len]); } { let mut asn1_buf = [0u8; 1000]; let c = Cert::new(&test_vectors::CHIP_CERT_TXT_IN_DN).unwrap(); - let len = c - .as_asn1(&mut asn1_buf, crate::utils::epoch::sys_utc_calendar) - .unwrap(); + let len = c.as_asn1(&mut asn1_buf).unwrap(); assert_eq!(&test_vectors::ASN1_OUTPUT_TXT_IN_DN, &asn1_buf[..len]); } } - #[cfg(feature = "std")] #[test] fn test_verify_chain_success() { let noc = Cert::new(&test_vectors::NOC1_SUCCESS).unwrap(); let icac = Cert::new(&test_vectors::ICAC1_SUCCESS).unwrap(); let rca = Cert::new(&test_vectors::RCA1_SUCCESS).unwrap(); - let a = noc.verify_chain_start(crate::utils::epoch::sys_utc_calendar); + let a = noc.verify_chain_start(); a.add_cert(&icac) .unwrap() .add_cert(&rca) @@ -814,7 +799,6 @@ mod tests { .unwrap(); } - #[cfg(feature = "std")] #[test] fn test_verify_chain_incomplete() { // The chain doesn't lead up to a self-signed certificate @@ -822,35 +806,33 @@ mod tests { use crate::error::ErrorCode; let noc = Cert::new(&test_vectors::NOC1_SUCCESS).unwrap(); let icac = Cert::new(&test_vectors::ICAC1_SUCCESS).unwrap(); - let a = noc.verify_chain_start(crate::utils::epoch::sys_utc_calendar); + let a = noc.verify_chain_start(); assert_eq!( Err(ErrorCode::InvalidAuthKey), a.add_cert(&icac).unwrap().finalise().map_err(|e| e.code()) ); } - #[cfg(feature = "std")] #[test] fn test_auth_key_chain_incorrect() { use crate::error::ErrorCode; let noc = Cert::new(&test_vectors::NOC1_AUTH_KEY_FAIL).unwrap(); let icac = Cert::new(&test_vectors::ICAC1_SUCCESS).unwrap(); - let a = noc.verify_chain_start(crate::utils::epoch::sys_utc_calendar); + let a = noc.verify_chain_start(); assert_eq!( Err(ErrorCode::InvalidAuthKey), a.add_cert(&icac).map(|_| ()).map_err(|e| e.code()) ); } - #[cfg(feature = "std")] #[test] fn test_cert_corrupted() { use crate::error::ErrorCode; let noc = Cert::new(&test_vectors::NOC1_CORRUPT_CERT).unwrap(); let icac = Cert::new(&test_vectors::ICAC1_SUCCESS).unwrap(); - let a = noc.verify_chain_start(crate::utils::epoch::sys_utc_calendar); + let a = noc.verify_chain_start(); assert_eq!( Err(ErrorCode::InvalidSignature), a.add_cert(&icac).map(|_| ()).map_err(|e| e.code()) diff --git a/matter/src/cert/printer.rs b/matter/src/cert/printer.rs index ae07957..a4c4efe 100644 --- a/matter/src/cert/printer.rs +++ b/matter/src/cert/printer.rs @@ -15,12 +15,11 @@ * limitations under the License. */ +use time::OffsetDateTime; + use super::{CertConsumer, MAX_DEPTH}; -use crate::{ - error::Error, - utils::epoch::{UtcCalendar, MATTER_EPOCH_SECS}, -}; -use core::{fmt, time::Duration}; +use crate::{error::Error, utils::epoch::MATTER_EPOCH_SECS}; +use core::fmt; pub struct CertPrinter<'a, 'b> { level: usize, @@ -123,10 +122,10 @@ impl<'a, 'b> CertConsumer for CertPrinter<'a, 'b> { } Ok(()) } - fn utctime(&mut self, tag: &str, epoch: u32, utc_calendar: UtcCalendar) -> Result<(), Error> { + fn utctime(&mut self, tag: &str, epoch: u32) -> Result<(), Error> { let matter_epoch = MATTER_EPOCH_SECS + epoch as u64; - let dt = utc_calendar(Duration::from_secs(matter_epoch as _)); + let dt = OffsetDateTime::from_unix_timestamp(matter_epoch as _).unwrap(); let _ = writeln!(self.f, "{} {} {:?}", SPACE[self.level], tag, dt); Ok(()) diff --git a/matter/src/core.rs b/matter/src/core.rs index 17452e3..bed0e9e 100644 --- a/matter/src/core.rs +++ b/matter/src/core.rs @@ -25,10 +25,7 @@ use crate::{ mdns::{Mdns, MdnsMgr}, pairing::{print_pairing_code_and_qr, DiscoveryCapabilities}, secure_channel::{pake::PaseMgr, spake2p::VerifierData}, - utils::{ - epoch::{Epoch, UtcCalendar}, - rand::Rand, - }, + utils::{epoch::Epoch, rand::Rand}, }; /// Device Commissioning Data @@ -48,17 +45,16 @@ pub struct Matter<'a> { pub mdns_mgr: RefCell>, pub epoch: Epoch, pub rand: Rand, - pub utc_calendar: UtcCalendar, pub dev_det: &'a BasicInfoConfig<'a>, } impl<'a> Matter<'a> { #[cfg(feature = "std")] pub fn new_default(dev_det: &'a BasicInfoConfig, mdns: &'a mut dyn Mdns, port: u16) -> Self { - use crate::utils::epoch::{sys_epoch, sys_utc_calendar}; + use crate::utils::epoch::sys_epoch; use crate::utils::rand::sys_rand; - Self::new(dev_det, mdns, sys_epoch, sys_rand, sys_utc_calendar, port) + Self::new(dev_det, mdns, sys_epoch, sys_rand, port) } /// Creates a new Matter object @@ -72,7 +68,6 @@ impl<'a> Matter<'a> { mdns: &'a mut dyn Mdns, epoch: Epoch, rand: Rand, - utc_calendar: UtcCalendar, port: u16, ) -> Self { Self { @@ -89,7 +84,6 @@ impl<'a> Matter<'a> { )), epoch, rand, - utc_calendar, dev_det, } } @@ -178,9 +172,3 @@ impl<'a> Borrow for Matter<'a> { &self.rand } } - -impl<'a> Borrow for Matter<'a> { - fn borrow(&self) -> &UtcCalendar { - &self.utc_calendar - } -} diff --git a/matter/src/secure_channel/case.rs b/matter/src/secure_channel/case.rs index 3fa9249..fbd6da8 100644 --- a/matter/src/secure_channel/case.rs +++ b/matter/src/secure_channel/case.rs @@ -32,7 +32,7 @@ use crate::{ proto_ctx::ProtoCtx, session::{CaseDetails, CloneData, NocCatIds, SessionMode}, }, - utils::{epoch::UtcCalendar, rand::Rand, writebuf::WriteBuf}, + utils::{rand::Rand, writebuf::WriteBuf}, }; #[derive(PartialEq)] @@ -70,16 +70,11 @@ impl CaseSession { pub struct Case<'a> { fabric_mgr: &'a RefCell, rand: Rand, - utc_calendar: UtcCalendar, } impl<'a> Case<'a> { - pub fn new(fabric_mgr: &'a RefCell, rand: Rand, utc_calendar: UtcCalendar) -> Self { - Self { - fabric_mgr, - rand, - utc_calendar, - } + pub fn new(fabric_mgr: &'a RefCell, rand: Rand) -> Self { + Self { fabric_mgr, rand } } pub fn casesigma3_handler( @@ -133,9 +128,7 @@ impl<'a> Case<'a> { if let Some(icac) = d.initiator_icac { initiator_icac = Some(Cert::new(icac.0)?); } - if let Err(e) = - Case::validate_certs(fabric, &initiator_noc, &initiator_icac, self.utc_calendar) - { + if let Err(e) = Case::validate_certs(fabric, &initiator_noc, &initiator_icac) { error!("Certificate Chain doesn't match: {}", e); common::create_sc_status_report(ctx.tx, common::SCStatusCodes::InvalidParameter, None)?; ctx.exch_ctx.exch.close(); @@ -339,13 +332,8 @@ impl<'a> Case<'a> { Ok(()) } - fn validate_certs( - fabric: &Fabric, - noc: &Cert, - icac: &Option, - utc_calendar: UtcCalendar, - ) -> Result<(), Error> { - let mut verifier = noc.verify_chain_start(utc_calendar); + fn validate_certs(fabric: &Fabric, noc: &Cert, icac: &Option) -> Result<(), Error> { + let mut verifier = noc.verify_chain_start(); if fabric.get_fabric_id() != noc.get_fabric_id()? { Err(ErrorCode::Invalid)?; diff --git a/matter/src/secure_channel/core.rs b/matter/src/secure_channel/core.rs index 653ad74..c2fe059 100644 --- a/matter/src/secure_channel/core.rs +++ b/matter/src/secure_channel/core.rs @@ -24,7 +24,7 @@ use crate::{ secure_channel::common::*, tlv, transport::{proto_ctx::ProtoCtx, session::CloneData}, - utils::{epoch::UtcCalendar, rand::Rand}, + utils::rand::Rand, }; use log::{error, info}; use num; @@ -46,10 +46,9 @@ impl<'a> SecureChannel<'a> { fabric_mgr: &'a RefCell, mdns: &'a RefCell>, rand: Rand, - utc_calendar: UtcCalendar, ) -> Self { SecureChannel { - case: Case::new(fabric_mgr, rand, utc_calendar), + case: Case::new(fabric_mgr, rand), pase, mdns, } diff --git a/matter/src/transport/mgr.rs b/matter/src/transport/mgr.rs index 331c362..eeff6ff 100644 --- a/matter/src/transport/mgr.rs +++ b/matter/src/transport/mgr.rs @@ -29,7 +29,7 @@ use crate::secure_channel::common::PROTO_ID_SECURE_CHANNEL; use crate::secure_channel::core::SecureChannel; use crate::transport::mrp::ReliableMessage; use crate::transport::{exchange, network::Address, packet::Packet}; -use crate::utils::epoch::{Epoch, UtcCalendar}; +use crate::utils::epoch::Epoch; use crate::utils::rand::Rand; use super::proto_ctx::ProtoCtx; @@ -210,8 +210,7 @@ impl<'a> TransportMgr<'a> { + Borrow> + Borrow>> + Borrow - + Borrow - + Borrow, + + Borrow, >( matter: &'a T, ) -> Self { @@ -221,7 +220,6 @@ impl<'a> TransportMgr<'a> { matter.borrow(), matter.borrow(), *matter.borrow(), - *matter.borrow(), ), *matter.borrow(), *matter.borrow(), diff --git a/matter/src/utils/epoch.rs b/matter/src/utils/epoch.rs index 7d08bfe..8236813 100644 --- a/matter/src/utils/epoch.rs +++ b/matter/src/utils/epoch.rs @@ -2,60 +2,15 @@ use core::time::Duration; pub type Epoch = fn() -> Duration; -pub type UtcCalendar = fn(Duration) -> UtcDate; - pub const MATTER_EPOCH_SECS: u64 = 946684800; // Seconds from 1970/01/01 00:00:00 till 2000/01/01 00:00:00 UTC -#[derive(Default, Debug, Clone, Eq, PartialEq)] -pub struct UtcDate { - pub year: u16, - pub month: u8, // 1 - 12 - pub day: u8, // 1 - 31 - pub hour: u8, // 0 - 23 - pub minute: u8, - pub second: u8, - pub millis: u16, -} - pub fn dummy_epoch() -> Duration { Duration::from_secs(0) } -pub fn dummy_utc_calendar(_duration: Duration) -> UtcDate { - Default::default() -} - #[cfg(feature = "std")] pub fn sys_epoch() -> Duration { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() } - -#[cfg(feature = "std")] -pub fn sys_utc_calendar(duration: Duration) -> UtcDate { - use chrono::{Datelike, TimeZone, Timelike}; - use log::warn; - - let dt = match chrono::Utc.timestamp_opt(duration.as_secs() as _, duration.subsec_nanos()) { - chrono::LocalResult::None => panic!("Invalid time"), - chrono::LocalResult::Single(s) => s, - chrono::LocalResult::Ambiguous(_, a) => { - warn!( - "Ambiguous time for epoch {:?}; returning latest timestamp: {a}", - duration - ); - a - } - }; - - UtcDate { - year: dt.year() as _, - month: dt.month() as _, - day: dt.day() as _, - hour: dt.hour() as _, - minute: dt.minute() as _, - second: dt.second() as _, - millis: (dt.nanosecond() / 1000) as _, - } -} diff --git a/matter/tests/common/im_engine.rs b/matter/tests/common/im_engine.rs index 6d398a4..ce608c5 100644 --- a/matter/tests/common/im_engine.rs +++ b/matter/tests/common/im_engine.rs @@ -106,15 +106,11 @@ pub type DmHandler<'a> = handler_chain_type!(OnOffCluster, EchoCluster, Descript pub fn matter(mdns: &mut dyn Mdns) -> Matter<'_> { #[cfg(feature = "std")] use matter::utils::epoch::sys_epoch as epoch; - #[cfg(feature = "std")] - use matter::utils::epoch::sys_utc_calendar as utc_calendar; #[cfg(not(feature = "std"))] use matter::utils::epoch::dummy_epoch as epoch; - #[cfg(not(feature = "std"))] - use matter::utils::epoch::dummy_utc_calendar as utc_calendar; - Matter::new(&BASIC_INFO, mdns, epoch, dummy_rand, utc_calendar, 5540) + Matter::new(&BASIC_INFO, mdns, epoch, dummy_rand, 5540) } /// An Interaction Model Engine to facilitate easy testing diff --git a/tools/tlv_tool/src/main.rs b/tools/tlv_tool/src/main.rs index cc08cb4..54e5374 100644 --- a/tools/tlv_tool/src/main.rs +++ b/tools/tlv_tool/src/main.rs @@ -18,7 +18,6 @@ use clap::{App, Arg}; use matter::cert; use matter::tlv; -use matter::utils::epoch::sys_utc_calendar; use simple_logger::SimpleLogger; use std::process; @@ -95,7 +94,7 @@ fn main() { } else if m.is_present("as-asn1") { let mut asn1_cert = [0_u8; 1024]; let cert = cert::Cert::new(&tlv_list[..index]).unwrap(); - let len = cert.as_asn1(&mut asn1_cert, sys_utc_calendar).unwrap(); + let len = cert.as_asn1(&mut asn1_cert).unwrap(); println!("{:02x?}", &asn1_cert[..len]); } else { tlv::print_tlv_list(&tlv_list[..index]);