Remove allocations from Cert handling

This commit is contained in:
ivmarkov 2023-04-24 06:10:58 +00:00
parent f7a887c1d2
commit d82e9ec0af
7 changed files with 205 additions and 242 deletions

View file

@ -17,7 +17,7 @@
use super::{CertConsumer, MAX_DEPTH};
use crate::error::Error;
use chrono::{Datelike, TimeZone, Utc};
use chrono::{Datelike, TimeZone, Utc}; // TODO
use core::fmt::Write;
use log::warn;

View file

@ -15,23 +15,22 @@
* limitations under the License.
*/
use core::fmt;
extern crate alloc;
use core::fmt::{self, Write};
use crate::{
crypto::KeyPair,
error::Error,
tlv::{self, FromTLV, TLVArrayOwned, TLVElement, TLVWriter, TagType, ToTLV},
tlv::{self, FromTLV, OctetStr, TLVArray, TLVElement, TLVWriter, TagType, ToTLV},
utils::writebuf::WriteBuf,
};
use alloc::{format, string::String, vec::Vec};
use log::error;
use num_derive::FromPrimitive;
pub use self::asn1_writer::ASN1Writer;
use self::printer::CertPrinter;
pub const MAX_CERT_TLV_LEN: usize = 300; // TODO
// As per https://datatracker.ietf.org/doc/html/rfc5280
const OID_PUB_KEY_ECPUBKEY: [u8; 7] = [0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01];
@ -116,8 +115,10 @@ macro_rules! add_if {
};
}
fn get_print_str(key_usage: u16) -> String {
format!(
fn get_print_str(key_usage: u16) -> heapless::String<256> {
let mut string = heapless::String::new();
write!(
&mut string,
"{}{}{}{}{}{}{}{}{}",
add_if!(key_usage, KEY_USAGE_DIGITAL_SIGN, "digitalSignature "),
add_if!(key_usage, KEY_USAGE_NON_REPUDIATION, "nonRepudiation "),
@ -129,6 +130,9 @@ fn get_print_str(key_usage: u16) -> String {
add_if!(key_usage, KEY_USAGE_ENCIPHER_ONLY, "encipherOnly "),
add_if!(key_usage, KEY_USAGE_DECIPHER_ONLY, "decipherOnly "),
)
.unwrap();
string
}
#[allow(unused_assignments)]
@ -140,7 +144,7 @@ fn encode_key_usage(key_usage: u16, w: &mut dyn CertConsumer) -> Result<(), Erro
}
fn encode_extended_key_usage(
list: &TLVArrayOwned<u8>,
list: impl Iterator<Item = u8>,
w: &mut dyn CertConsumer,
) -> Result<(), Error> {
const OID_SERVER_AUTH: [u8; 8] = [0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01];
@ -160,19 +164,18 @@ fn encode_extended_key_usage(
];
w.start_seq("")?;
for t in list.iter() {
let t = *t as usize;
for t in list {
let t = t as usize;
if t > 0 && t <= encoding.len() {
w.oid(encoding[t].0, encoding[t].1)?;
} else {
error!("Skipping encoding key usage out of bounds");
}
}
w.end_seq()?;
Ok(())
w.end_seq()
}
#[derive(FromTLV, ToTLV, Default)]
#[derive(FromTLV, ToTLV, Default, Debug)]
#[tlvargs(start = 1)]
struct BasicConstraints {
is_ca: bool,
@ -212,18 +215,18 @@ fn encode_extension_end(w: &mut dyn CertConsumer) -> Result<(), Error> {
w.end_seq()
}
#[derive(FromTLV, ToTLV, Default)]
#[tlvargs(start = 1, datatype = "list")]
struct Extensions {
#[derive(FromTLV, ToTLV, Default, Debug)]
#[tlvargs(lifetime = "'a", start = 1, datatype = "list")]
struct Extensions<'a> {
basic_const: Option<BasicConstraints>,
key_usage: Option<u16>,
ext_key_usage: Option<TLVArrayOwned<u8>>,
subj_key_id: Option<Vec<u8>>,
auth_key_id: Option<Vec<u8>>,
future_extensions: Option<Vec<u8>>,
ext_key_usage: Option<TLVArray<'a, u8>>,
subj_key_id: Option<OctetStr<'a>>,
auth_key_id: Option<OctetStr<'a>>,
future_extensions: Option<OctetStr<'a>>,
}
impl Extensions {
impl<'a> Extensions<'a> {
fn encode(&self, w: &mut dyn CertConsumer) -> Result<(), Error> {
const OID_BASIC_CONSTRAINTS: [u8; 3] = [0x55, 0x1D, 0x13];
const OID_KEY_USAGE: [u8; 3] = [0x55, 0x1D, 0x0F];
@ -245,30 +248,29 @@ impl Extensions {
}
if let Some(t) = &self.ext_key_usage {
encode_extension_start("X509v3 Extended Key Usage", true, &OID_EXT_KEY_USAGE, w)?;
encode_extended_key_usage(t, w)?;
encode_extended_key_usage(t.iter(), w)?;
encode_extension_end(w)?;
}
if let Some(t) = &self.subj_key_id {
encode_extension_start("Subject Key ID", false, &OID_SUBJ_KEY_IDENTIFIER, w)?;
w.ostr("", t.as_slice())?;
w.ostr("", t.0)?;
encode_extension_end(w)?;
}
if let Some(t) = &self.auth_key_id {
encode_extension_start("Auth Key ID", false, &OID_AUTH_KEY_ID, w)?;
w.start_seq("")?;
w.ctx("", 0, t.as_slice())?;
w.ctx("", 0, t.0)?;
w.end_seq()?;
encode_extension_end(w)?;
}
if let Some(t) = &self.future_extensions {
error!("Future Extensions Not Yet Supported: {:x?}", t.as_slice())
error!("Future Extensions Not Yet Supported: {:x?}", t.0);
}
w.end_seq()?;
w.end_ctx()?;
Ok(())
}
}
const MAX_DN_ENTRIES: usize = 5;
#[derive(FromPrimitive, Copy, Clone)]
enum DnTags {
@ -296,20 +298,23 @@ enum DnTags {
NocCat = 22,
}
enum DistNameValue {
#[derive(Debug)]
enum DistNameValue<'a> {
Uint(u64),
Utf8Str(Vec<u8>),
PrintableStr(Vec<u8>),
Utf8Str(&'a [u8]),
PrintableStr(&'a [u8]),
}
#[derive(Default)]
struct DistNames {
const MAX_DN_ENTRIES: usize = 5;
#[derive(Default, Debug)]
struct DistNames<'a> {
// The order in which the DNs arrive is important, as the signing
// requires that the ASN1 notation retains the same order
dn: Vec<(u8, DistNameValue)>,
dn: heapless::Vec<(u8, DistNameValue<'a>), MAX_DN_ENTRIES>,
}
impl DistNames {
impl<'a> DistNames<'a> {
fn u64(&self, match_id: DnTags) -> Option<u64> {
self.dn
.iter()
@ -339,24 +344,27 @@ impl DistNames {
const PRINTABLE_STR_THRESHOLD: u8 = 0x80;
impl<'a> FromTLV<'a> for DistNames {
impl<'a> FromTLV<'a> for DistNames<'a> {
fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error> {
let mut d = Self {
dn: Vec::with_capacity(MAX_DN_ENTRIES),
dn: heapless::Vec::new(),
};
let iter = t.confirm_list()?.enter().ok_or(Error::Invalid)?;
for t in iter {
if let TagType::Context(tag) = t.get_tag() {
if let Ok(value) = t.u64() {
d.dn.push((tag, DistNameValue::Uint(value)));
d.dn.push((tag, DistNameValue::Uint(value)))
.map_err(|_| Error::BufferTooSmall)?;
} else if let Ok(value) = t.slice() {
if tag > PRINTABLE_STR_THRESHOLD {
d.dn.push((
tag - PRINTABLE_STR_THRESHOLD,
DistNameValue::PrintableStr(value.to_vec()),
));
DistNameValue::PrintableStr(value),
))
.map_err(|_| Error::BufferTooSmall)?;
} else {
d.dn.push((tag, DistNameValue::Utf8Str(value.to_vec())));
d.dn.push((tag, DistNameValue::Utf8Str(value)))
.map_err(|_| Error::BufferTooSmall)?;
}
}
}
@ -365,24 +373,23 @@ impl<'a> FromTLV<'a> for DistNames {
}
}
impl ToTLV for DistNames {
impl<'a> ToTLV for DistNames<'a> {
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
tw.start_list(tag)?;
for (name, value) in &self.dn {
match value {
DistNameValue::Uint(v) => tw.u64(TagType::Context(*name), *v)?,
DistNameValue::Utf8Str(v) => tw.utf8(TagType::Context(*name), v.as_slice())?,
DistNameValue::PrintableStr(v) => tw.utf8(
TagType::Context(*name + PRINTABLE_STR_THRESHOLD),
v.as_slice(),
)?,
DistNameValue::Utf8Str(v) => tw.utf8(TagType::Context(*name), v)?,
DistNameValue::PrintableStr(v) => {
tw.utf8(TagType::Context(*name + PRINTABLE_STR_THRESHOLD), v)?
}
}
}
tw.end_container()
}
}
impl DistNames {
impl<'a> DistNames<'a> {
fn encode(&self, tag: &str, w: &mut dyn CertConsumer) -> Result<(), Error> {
const OID_COMMON_NAME: [u8; 3] = [0x55_u8, 0x04, 0x03];
const OID_SURNAME: [u8; 3] = [0x55_u8, 0x04, 0x04];
@ -520,38 +527,36 @@ fn encode_dn_value(
}
},
DistNameValue::Utf8Str(v) => {
let str = String::from_utf8(v.to_vec())?;
w.utf8str("", &str)?;
w.utf8str("", core::str::from_utf8(v)?)?;
}
DistNameValue::PrintableStr(v) => {
let str = String::from_utf8(v.to_vec())?;
w.printstr("", &str)?;
w.printstr("", core::str::from_utf8(v)?)?;
}
}
w.end_seq()?;
w.end_set()
}
#[derive(FromTLV, ToTLV, Default)]
#[tlvargs(start = 1)]
pub struct Cert {
serial_no: Vec<u8>,
#[derive(FromTLV, ToTLV, Default, Debug)]
#[tlvargs(lifetime = "'a", start = 1)]
pub struct Cert<'a> {
serial_no: OctetStr<'a>,
sign_algo: u8,
issuer: DistNames,
issuer: DistNames<'a>,
not_before: u32,
not_after: u32,
subject: DistNames,
subject: DistNames<'a>,
pubkey_algo: u8,
ec_curve_id: u8,
pubkey: Vec<u8>,
extensions: Extensions,
signature: Vec<u8>,
pubkey: OctetStr<'a>,
extensions: Extensions<'a>,
signature: OctetStr<'a>,
}
// TODO: Instead of parsing the TLVs everytime, we should just cache this, but the encoding
// rules in terms of sequence may get complicated. Need to look into this
impl Cert {
pub fn new(cert_bin: &[u8]) -> Result<Self, Error> {
impl<'a> Cert<'a> {
pub fn new(cert_bin: &'a [u8]) -> Result<Self, Error> {
let root = tlv::get_root_node(cert_bin)?;
Cert::from_tlv(&root)
}
@ -569,17 +574,21 @@ impl Cert {
}
pub fn get_pubkey(&self) -> &[u8] {
self.pubkey.as_slice()
self.pubkey.0
}
pub fn get_subject_key_id(&self) -> Result<&[u8], Error> {
self.extensions.subj_key_id.as_deref().ok_or(Error::Invalid)
if let Some(id) = self.extensions.subj_key_id.as_ref() {
Ok(id.0)
} else {
Err(Error::Invalid)
}
}
pub fn is_authority(&self, their: &Cert) -> Result<bool, Error> {
if let Some(our_auth_key) = &self.extensions.auth_key_id {
let their_subject = their.get_subject_key_id()?;
if our_auth_key == their_subject {
if our_auth_key.0 == their_subject {
Ok(true)
} else {
Ok(false)
@ -590,7 +599,7 @@ impl Cert {
}
pub fn get_signature(&self) -> &[u8] {
self.signature.as_slice()
self.signature.0
}
pub fn as_tlv(&self, buf: &mut [u8]) -> Result<usize, Error> {
@ -617,7 +626,7 @@ impl Cert {
w.integer("", &[2])?;
w.end_ctx()?;
w.integer("Serial Num:", self.serial_no.as_slice())?;
w.integer("Serial Num:", self.serial_no.0)?;
w.start_seq("Signature Algorithm:")?;
let (str, oid) = match get_sign_algo(self.sign_algo).ok_or(Error::Invalid)? {
@ -647,7 +656,7 @@ impl Cert {
w.oid(str, &curve_id)?;
w.end_seq()?;
w.bitstr("Public-Key:", false, self.pubkey.as_slice())?;
w.bitstr("Public-Key:", false, self.pubkey.0)?;
w.end_seq()?;
self.extensions.encode(w)?;
@ -658,7 +667,7 @@ impl Cert {
}
}
impl fmt::Display for Cert {
impl<'a> fmt::Display for Cert<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut printer = CertPrinter::new(f);
let _ = self
@ -670,7 +679,7 @@ impl fmt::Display for Cert {
}
pub struct CertVerifier<'a> {
cert: &'a Cert,
cert: &'a Cert<'a>,
}
impl<'a> CertVerifier<'a> {
@ -809,6 +818,7 @@ mod tests {
#[test]
fn test_tlv_conversions() {
let _ = env_logger::try_init();
let test_input: [&[u8]; 3] = [
&test_vectors::NOC1_SUCCESS,
&test_vectors::ICAC1_SUCCESS,

View file

@ -19,7 +19,7 @@ use core::cell::RefCell;
use core::convert::TryInto;
use crate::acl::{AclEntry, AclMgr, AuthMode};
use crate::cert::Cert;
use crate::cert::{Cert, MAX_CERT_TLV_LEN};
use crate::crypto::{self, KeyPair};
use crate::data_model::objects::*;
use crate::data_model::sdm::dev_att;
@ -158,14 +158,14 @@ pub const CLUSTER: Cluster<'static> = Cluster {
pub struct NocData {
pub key_pair: KeyPair,
pub root_ca: Cert,
pub root_ca: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
}
impl NocData {
pub fn new(key_pair: KeyPair) -> Self {
Self {
key_pair,
root_ca: Cert::default(),
root_ca: heapless::Vec::new(),
}
}
}
@ -259,8 +259,10 @@ impl<'a> NocCluster<'a> {
writer.start_array(AttrDataWriter::TAG)?;
self.fabric_mgr.borrow().for_each(|entry, fab_idx| {
if !attr.fab_filter || attr.fab_idx == fab_idx {
let root_ca_cert = entry.get_root_ca()?;
entry
.get_fabric_desc(fab_idx)
.get_fabric_desc(fab_idx, &root_ca_cert)?
.to_tlv(&mut writer, TagType::Anonymous)?;
}
@ -351,12 +353,18 @@ impl<'a> NocCluster<'a> {
let r = AddNocReq::from_tlv(data).map_err(|_| NocStatus::InvalidNOC)?;
let noc_value = Cert::new(r.noc_value.0).map_err(|_| NocStatus::InvalidNOC)?;
info!("Received NOC as: {}", noc_value);
let icac_value = if !r.icac_value.0.is_empty() {
let cert = Cert::new(r.icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
info!("Received ICAC as: {}", cert);
Some(cert)
let noc_cert = Cert::new(r.noc_value.0).map_err(|_| NocStatus::InvalidNOC)?;
info!("Received NOC as: {}", noc_cert);
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 =
heapless::Vec::from_slice(r.icac_value.0).map_err(|_| NocStatus::InvalidNOC)?;
Some(icac)
} else {
None
};
@ -364,8 +372,8 @@ impl<'a> NocCluster<'a> {
let fabric = Fabric::new(
noc_data.key_pair,
noc_data.root_ca,
icac_value,
noc_value,
icac,
noc,
r.ipk_value.0,
r.vendor_id,
"",
@ -592,7 +600,9 @@ impl<'a> NocCluster<'a> {
let req = CommonReq::from_tlv(data).map_err(Error::map_invalid_command)?;
info!("Received Trusted Cert:{:x?}", req.str);
noc_data.root_ca = Cert::new(req.str.0)?;
noc_data.root_ca =
heapless::Vec::from_slice(req.str.0).map_err(|_| Error::BufferTooSmall)?;
// TODO
}
_ => (),
}

View file

@ -15,14 +15,11 @@
* limitations under the License.
*/
use alloc::string::FromUtf8Error;
use core::{array::TryFromSliceError, fmt};
use core::{array::TryFromSliceError, fmt, str::Utf8Error};
use async_channel::{SendError, TryRecvError};
use log::error;
extern crate alloc;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Error {
AttributeNotFound,
@ -166,8 +163,8 @@ impl<T> From<SendError<T>> for Error {
}
}
impl From<FromUtf8Error> for Error {
fn from(_e: FromUtf8Error) -> Self {
impl From<Utf8Error> for Error {
fn from(_e: Utf8Error) -> Self {
Self::Utf8Fail
}
}

View file

@ -21,7 +21,7 @@ use byteorder::{BigEndian, ByteOrder, LittleEndian};
use log::{error, info};
use crate::{
cert::Cert,
cert::{Cert, MAX_CERT_TLV_LEN},
crypto::{self, hkdf_sha256, HmacSha256, KeyPair},
error::Error,
group_keys::KeySet,
@ -30,7 +30,6 @@ use crate::{
tlv::{OctetStr, TLVWriter, TagType, ToTLV, UtfStr},
};
const MAX_CERT_TLV_LEN: usize = 300;
const COMPRESSED_FABRIC_ID_LEN: usize = 8;
macro_rules! fb_key {
@ -72,9 +71,9 @@ pub struct Fabric {
fabric_id: u64,
vendor_id: u16,
key_pair: KeyPair,
pub root_ca: Cert,
pub icac: Option<Cert>,
pub noc: Cert,
pub root_ca: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
pub icac: Option<heapless::Vec<u8, { MAX_CERT_TLV_LEN }>>,
pub noc: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
pub ipk: KeySet,
label: heapless::String<32>,
mdns_service_name: heapless::String<33>,
@ -83,20 +82,25 @@ pub struct Fabric {
impl Fabric {
pub fn new(
key_pair: KeyPair,
root_ca: Cert,
icac: Option<Cert>,
noc: Cert,
root_ca: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
icac: Option<heapless::Vec<u8, { MAX_CERT_TLV_LEN }>>,
noc: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
ipk: &[u8],
vendor_id: u16,
label: &str,
) -> Result<Self, Error> {
let node_id = noc.get_node_id()?;
let fabric_id = noc.get_fabric_id()?;
let (node_id, fabric_id) = {
let noc_p = Cert::new(&noc)?;
(noc_p.get_node_id()?, noc_p.get_fabric_id()?)
};
let mut compressed_id = [0_u8; COMPRESSED_FABRIC_ID_LEN];
Fabric::get_compressed_id(root_ca.get_pubkey(), fabric_id, &mut compressed_id)?;
let ipk = KeySet::new(ipk, &compressed_id)?;
let ipk = {
let root_ca_p = Cert::new(&root_ca)?;
Fabric::get_compressed_id(root_ca_p.get_pubkey(), fabric_id, &mut compressed_id)?;
KeySet::new(ipk, &compressed_id)?
};
let mut mdns_service_name = heapless::String::<33>::new();
for c in compressed_id {
@ -144,7 +148,7 @@ impl Fabric {
let mut mac = HmacSha256::new(self.ipk.op_key())?;
mac.update(random)?;
mac.update(self.root_ca.get_pubkey())?;
mac.update(self.get_root_ca()?.get_pubkey())?;
let mut buf: [u8; 8] = [0; 8];
LittleEndian::write_u64(&mut buf, self.fabric_id);
@ -174,15 +178,25 @@ impl Fabric {
self.fabric_id
}
pub fn get_fabric_desc(&self, fab_idx: u8) -> FabricDescriptor {
FabricDescriptor {
root_public_key: OctetStr::new(self.root_ca.get_pubkey()),
pub fn get_root_ca(&self) -> Result<Cert<'_>, Error> {
Cert::new(&self.root_ca)
}
pub fn get_fabric_desc<'a>(
&'a self,
fab_idx: u8,
root_ca_cert: &'a Cert,
) -> Result<FabricDescriptor<'a>, Error> {
let desc = FabricDescriptor {
root_public_key: OctetStr::new(root_ca_cert.get_pubkey()),
vendor_id: self.vendor_id,
fabric_id: self.fabric_id,
node_id: self.node_id,
label: UtfStr(self.label.as_bytes()),
fab_idx: Some(fab_idx),
}
};
Ok(desc)
}
fn store<T>(&self, index: usize, mut psm: T) -> Result<(), Error>
@ -191,19 +205,13 @@ impl Fabric {
{
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let len = self.root_ca.as_tlv(&mut buf)?;
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &buf[..len])?;
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(&[]),
)?;
let len = if let Some(icac) = &self.icac {
icac.as_tlv(&mut buf)?
} else {
0
};
psm.set_kv_slice(fb_key!(index, ST_ICA, _kb), &buf[..len])?;
let len = self.noc.as_tlv(&mut buf)?;
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &buf[..len])?;
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())?;
@ -228,18 +236,21 @@ impl Fabric {
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let root_ca = psm.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)?;
let root_ca = Cert::new(root_ca)?;
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(Cert::new(icac)?)
Some(heapless::Vec::from_slice(icac).unwrap())
} else {
None
};
let noc = psm.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)?;
let noc = Cert::new(noc)?;
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)
@ -293,21 +304,16 @@ impl Fabric {
{
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let len = self.root_ca.as_tlv(&mut buf)?;
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &buf[..len])
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &self.root_ca)
.await?;
let len = if let Some(icac) = &self.icac {
icac.as_tlv(&mut buf)?
} else {
0
};
psm.set_kv_slice(fb_key!(index, ST_ICA, _kb), &buf[..len])
psm.set_kv_slice(
fb_key!(index, ST_ICA, _kb),
self.icac.as_deref().unwrap_or(&[]),
)
.await?;
let len = self.noc.as_tlv(&mut buf)?;
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &buf[..len])
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?;
@ -337,24 +343,27 @@ impl Fabric {
let mut _kb = heapless::String::<32>::new();
let mut buf = [0u8; MAX_CERT_TLV_LEN];
let root_ca = psm
.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)
.await?;
let root_ca = Cert::new(root_ca)?;
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(Cert::new(icac)?)
Some(heapless::Vec::from_slice(icac).unwrap())
} else {
None
};
let noc = psm
.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)
.await?;
let noc = Cert::new(noc)?;
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)

View file

@ -349,7 +349,9 @@ impl<'a> Case<'a> {
verifier = verifier.add_cert(icac)?;
}
verifier.add_cert(&fabric.root_ca)?.finalise()?;
verifier
.add_cert(&Cert::new(&fabric.root_ca)?)?
.finalise()?;
Ok(())
}
@ -481,9 +483,9 @@ impl<'a> Case<'a> {
let mut write_buf = WriteBuf::new(out);
let mut tw = TLVWriter::new(&mut write_buf);
tw.start_struct(TagType::Anonymous)?;
tw.str16_as(TagType::Context(1), |buf| fabric.noc.as_tlv(buf))?;
if let Some(icac_cert) = &fabric.icac {
tw.str16_as(TagType::Context(2), |buf| icac_cert.as_tlv(buf))?
tw.str16(TagType::Context(1), &fabric.noc)?;
if let Some(icac_cert) = fabric.icac.as_ref() {
tw.str16(TagType::Context(2), icac_cert)?
};
tw.str8(TagType::Context(3), signature)?;
@ -523,9 +525,9 @@ impl<'a> Case<'a> {
let mut write_buf = WriteBuf::new(&mut buf);
let mut tw = TLVWriter::new(&mut write_buf);
tw.start_struct(TagType::Anonymous)?;
tw.str16_as(TagType::Context(1), |buf| fabric.noc.as_tlv(buf))?;
if let Some(icac_cert) = &fabric.icac {
tw.str16_as(TagType::Context(2), |buf| icac_cert.as_tlv(buf))?;
tw.str16(TagType::Context(1), &fabric.noc)?;
if let Some(icac_cert) = fabric.icac.as_deref() {
tw.str16(TagType::Context(2), icac_cert)?;
}
tw.str8(TagType::Context(3), our_pub_key)?;
tw.str8(TagType::Context(4), peer_pub_key)?;

View file

@ -17,14 +17,10 @@
use super::{ElementType, TLVContainerIterator, TLVElement, TLVWriter, TagType};
use crate::error::Error;
use alloc::borrow::ToOwned;
use alloc::{string::String, vec::Vec};
use core::fmt::Debug;
use core::slice::Iter;
use log::error;
extern crate alloc;
pub trait FromTLV<'a> {
fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error>
where
@ -118,14 +114,11 @@ totlv_for!(i8 u8 u16 u32 u64 bool);
//
// - UtfStr, OctetStr: These are versions that map to utfstr and ostr in the TLV spec
// - These only have references into the original list
// - String, Vec<u8>: Is the owned version of utfstr and ostr, data is cloned into this
// - String is only partially implemented
//
// - TLVArray: Is an array of entries, with reference within the original list
// - TLVArrayOwned: Is the owned version of this, data is cloned into this
/// Implements UTFString from the spec
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct UtfStr<'a>(pub &'a [u8]);
impl<'a> UtfStr<'a> {
@ -136,10 +129,6 @@ impl<'a> UtfStr<'a> {
pub fn as_str(&self) -> Result<&str, Error> {
core::str::from_utf8(self.0).map_err(|_| Error::Invalid)
}
pub fn to_string(self) -> Result<String, Error> {
String::from_utf8(self.0.to_vec()).map_err(|_| Error::Invalid)
}
}
impl<'a> ToTLV for UtfStr<'a> {
@ -155,7 +144,7 @@ impl<'a> FromTLV<'a> for UtfStr<'a> {
}
/// Implements OctetString from the spec
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct OctetStr<'a>(pub &'a [u8]);
impl<'a> OctetStr<'a> {
@ -176,41 +165,6 @@ impl<'a> ToTLV for OctetStr<'a> {
}
}
/// Implements the Owned version of Octet String
impl FromTLV<'_> for Vec<u8> {
fn from_tlv(t: &TLVElement) -> Result<Vec<u8>, Error> {
t.slice().map(|x| x.to_owned())
}
}
impl ToTLV for Vec<u8> {
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 FromTLV<'_> for String {
fn from_tlv(t: &TLVElement) -> Result<String, Error> {
match t.slice() {
Ok(x) => {
if let Ok(s) = String::from_utf8(x.to_vec()) {
Ok(s)
} else {
Err(Error::Invalid)
}
}
Err(e) => Err(e),
}
}
}
impl ToTLV for String {
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
tw.utf16(tag, self.as_bytes())
}
}
/// Applies to all the Option<> Processing
impl<'a, T: FromTLV<'a>> FromTLV<'a> for Option<T> {
fn from_tlv(t: &TLVElement<'a>) -> Result<Option<T>, Error> {
@ -279,37 +233,6 @@ impl<T: ToTLV> ToTLV for Nullable<T> {
}
}
/// Owned version of a TLVArray
pub struct TLVArrayOwned<T>(Vec<T>);
impl<'a, T: FromTLV<'a>> FromTLV<'a> for TLVArrayOwned<T> {
fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error> {
t.confirm_array()?;
let mut vec = Vec::<T>::new();
if let Some(tlv_iter) = t.enter() {
for element in tlv_iter {
vec.push(T::from_tlv(&element)?);
}
}
Ok(Self(vec))
}
}
impl<T: ToTLV> ToTLV for TLVArrayOwned<T> {
fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
tw.start_array(tag_type)?;
for t in &self.0 {
t.to_tlv(tw, TagType::Anonymous)?;
}
tw.end_container()
}
}
impl<T> TLVArrayOwned<T> {
pub fn iter(&self) -> Iter<T> {
self.0.iter()
}
}
#[derive(Copy, Clone)]
pub enum TLVArray<'a, T> {
// This is used for the to-tlv path
@ -390,18 +313,23 @@ where
}
}
impl<'a, T: ToTLV> ToTLV for TLVArray<'a, T> {
impl<'a, T: FromTLV<'a> + Copy + ToTLV> ToTLV for TLVArray<'a, T> {
fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
match *self {
Self::Slice(s) => {
tw.start_array(tag_type)?;
for a in s {
for a in self.iter() {
a.to_tlv(tw, TagType::Anonymous)?;
}
tw.end_container()
}
Self::Ptr(t) => t.to_tlv(tw, tag_type),
}
// match *self {
// Self::Slice(s) => {
// tw.start_array(tag_type)?;
// for a in s {
// a.to_tlv(tw, TagType::Anonymous)?;
// }
// tw.end_container()
// }
// Self::Ptr(t) => t.to_tlv(tw, tag_type), <-- TODO: this fails the unit tests of Cert from/to TLV
// }
}
}
@ -414,10 +342,17 @@ impl<'a, T> FromTLV<'a> for TLVArray<'a, T> {
impl<'a, T: Debug + ToTLV + FromTLV<'a> + Copy> Debug for TLVArray<'a, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "TLVArray [")?;
let mut first = true;
for i in self.iter() {
writeln!(f, "{:?}", i)?;
if !first {
write!(f, ", ")?;
}
writeln!(f)
write!(f, "{:?}", i)?;
first = false;
}
write!(f, "]")
}
}