Just use time-rs in no_std mode

This commit is contained in:
ivmarkov 2023-05-04 10:57:21 +00:00
parent a4b8b53014
commit 592d1ee028
12 changed files with 63 additions and 155 deletions

View file

@ -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" }

View file

@ -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 }

View file

@ -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())

View file

@ -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<usize, Error> {
pub fn as_asn1(&self, buf: &mut [u8]) -> Result<usize, Error> {
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<UtcCalendar>,
) -> 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<CertVerifier<'a>, 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())

View file

@ -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(())

View file

@ -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<MdnsMgr<'a>>,
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<Rand> for Matter<'a> {
&self.rand
}
}
impl<'a> Borrow<UtcCalendar> for Matter<'a> {
fn borrow(&self) -> &UtcCalendar {
&self.utc_calendar
}
}

View file

@ -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<FabricMgr>,
rand: Rand,
utc_calendar: UtcCalendar,
}
impl<'a> Case<'a> {
pub fn new(fabric_mgr: &'a RefCell<FabricMgr>, rand: Rand, utc_calendar: UtcCalendar) -> Self {
Self {
fabric_mgr,
rand,
utc_calendar,
}
pub fn new(fabric_mgr: &'a RefCell<FabricMgr>, 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<Cert>,
utc_calendar: UtcCalendar,
) -> Result<(), Error> {
let mut verifier = noc.verify_chain_start(utc_calendar);
fn validate_certs(fabric: &Fabric, noc: &Cert, icac: &Option<Cert>) -> Result<(), Error> {
let mut verifier = noc.verify_chain_start();
if fabric.get_fabric_id() != noc.get_fabric_id()? {
Err(ErrorCode::Invalid)?;

View file

@ -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<FabricMgr>,
mdns: &'a RefCell<MdnsMgr<'a>>,
rand: Rand,
utc_calendar: UtcCalendar,
) -> Self {
SecureChannel {
case: Case::new(fabric_mgr, rand, utc_calendar),
case: Case::new(fabric_mgr, rand),
pase,
mdns,
}

View file

@ -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<RefCell<PaseMgr>>
+ Borrow<RefCell<MdnsMgr<'a>>>
+ Borrow<Epoch>
+ Borrow<Rand>
+ Borrow<UtcCalendar>,
+ Borrow<Rand>,
>(
matter: &'a T,
) -> Self {
@ -221,7 +220,6 @@ impl<'a> TransportMgr<'a> {
matter.borrow(),
matter.borrow(),
*matter.borrow(),
*matter.borrow(),
),
*matter.borrow(),
*matter.borrow(),

View file

@ -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 _,
}
}

View file

@ -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

View file

@ -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]);