diff --git a/rust/c509-certificate/src/algorithm_identifier.rs b/rust/c509-certificate/src/algorithm_identifier.rs index d6a3e1e1ccb..1d2e8c26644 100644 --- a/rust/c509-certificate/src/algorithm_identifier.rs +++ b/rust/c509-certificate/src/algorithm_identifier.rs @@ -17,8 +17,13 @@ use asn1_rs::Oid; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; -use crate::oid::C509oid; - +use crate::{ + helper::{ + decode::{decode_array_len, decode_bytes, decode_datatype}, + encode::{encode_array_len, encode_bytes}, + }, + oid::C509oid, +}; /// A struct represents the `AlgorithmIdentifier` type. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct AlgorithmIdentifier { @@ -58,9 +63,9 @@ impl Encode<()> for AlgorithmIdentifier { match &self.param { // [ algorithm: ~oid, parameters: bytes ] Some(p) => { - e.array(2)?; + encode_array_len(e, "Algorithm Identifier", 2)?; self.c509_oid.encode(e, ctx)?; - e.bytes(p.as_bytes())?; + encode_bytes(e, "Algorithm Identifier", p.as_bytes())?; }, // ~oid None => { @@ -74,16 +79,14 @@ impl Encode<()> for AlgorithmIdentifier { impl Decode<'_, ()> for AlgorithmIdentifier { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { // [ algorithm: ~oid, parameters: bytes ] - if d.datatype()? == minicbor::data::Type::Array { - let len = d.array()?.ok_or(minicbor::decode::Error::message( - "Failed to get array length", - ))?; + if decode_datatype(d, "Algorithm Identifier")? == minicbor::data::Type::Array { + let len = decode_array_len(d, "Algorithm Identifier")?; if len != 2 { return Err(minicbor::decode::Error::message("Array length must be 2")); } let c509_oid = C509oid::decode(d, ctx)?; - let param = - String::from_utf8(d.bytes()?.to_vec()).map_err(minicbor::decode::Error::message)?; + let param = String::from_utf8(decode_bytes(d, "Algorithm Identifier")?) + .map_err(minicbor::decode::Error::message)?; Ok(AlgorithmIdentifier::new( c509_oid.oid().clone(), Some(param), diff --git a/rust/c509-certificate/src/attributes/attribute.rs b/rust/c509-certificate/src/attributes/attribute.rs index b1da9793cc6..9c85ba4e2b8 100644 --- a/rust/c509-certificate/src/attributes/attribute.rs +++ b/rust/c509-certificate/src/attributes/attribute.rs @@ -15,8 +15,13 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Deserializer, Serialize}; use super::data::{get_oid_from_int, ATTRIBUTES_LOOKUP}; -use crate::oid::{C509oid, C509oidRegistered}; - +use crate::{ + helper::{ + decode::{decode_array_len, decode_datatype, decode_helper}, + encode::{encode_array_len, encode_helper}, + }, + oid::{C509oid, C509oidRegistered}, +}; /// A struct of C509 `Attribute` #[derive(Debug, Clone, PartialEq)] pub struct Attribute { @@ -107,7 +112,7 @@ impl Encode<()> for Attribute { .get_map() .get_by_right(self.registered_oid().c509_oid().oid()) { - e.i16(oid)?; + encode_helper(e, "Attribute as OID int", ctx, &oid)?; } else { // Encode unwrapped CBOR OID self.registered_oid().c509_oid().encode(e, ctx)?; @@ -120,7 +125,7 @@ impl Encode<()> for Attribute { // If multi-value attributes, encode it as array if self.multi_value { - e.array(self.value.len() as u64)?; + encode_array_len(e, "Attribute multiple value", self.value.len() as u64)?; } // Encode each value in the attribute @@ -135,8 +140,8 @@ impl Encode<()> for Attribute { impl Decode<'_, ()> for Attribute { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { // Handle CBOR int - let mut attr = if d.datatype()? == minicbor::data::Type::U8 { - let i = d.i16()?; + let mut attr = if decode_datatype(d, "Attribute as OID int")? == minicbor::data::Type::U8 { + let i = decode_helper(d, "Attribute as OID int", ctx)?; let oid = get_oid_from_int(i).map_err(minicbor::decode::Error::message)?; Attribute::new(oid.clone()) } else { @@ -146,11 +151,9 @@ impl Decode<'_, ()> for Attribute { }; // Handle attribute value - if d.datatype()? == minicbor::data::Type::Array { + if decode_datatype(d, "Attribute")? == minicbor::data::Type::Array { // When multi-value attribute - let len = d.array()?.ok_or_else(|| { - minicbor::decode::Error::message("Failed to get array length for attribute value") - })?; + let len = decode_array_len(d, "Attribute multiple value")?; if len == 0 { return Err(minicbor::decode::Error::message("Attribute value is empty")); @@ -183,21 +186,33 @@ pub enum AttributeValue { impl Encode<()> for AttributeValue { fn encode( - &self, e: &mut Encoder, _ctx: &mut (), + &self, e: &mut Encoder, ctx: &mut (), ) -> Result<(), minicbor::encode::Error> { match self { - AttributeValue::Text(text) => e.str(text)?, - AttributeValue::Bytes(bytes) => e.bytes(bytes)?, + AttributeValue::Text(text) => encode_helper(e, "Attribute value", ctx, text)?, + AttributeValue::Bytes(bytes) => encode_helper(e, "Attribute value", ctx, bytes)?, }; Ok(()) } } impl Decode<'_, ()> for AttributeValue { - fn decode(d: &mut Decoder<'_>, _ctx: &mut ()) -> Result { - match d.datatype()? { - minicbor::data::Type::String => Ok(AttributeValue::Text(d.str()?.to_string())), - minicbor::data::Type::Bytes => Ok(AttributeValue::Bytes(d.bytes()?.to_vec())), + fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { + match decode_datatype(d, "Attribute value")? { + minicbor::data::Type::String => { + Ok(AttributeValue::Text(decode_helper( + d, + "Attribute value", + ctx, + )?)) + }, + minicbor::data::Type::Bytes => { + Ok(AttributeValue::Bytes(decode_helper( + d, + "Attribute value", + ctx, + )?)) + }, _ => { Err(minicbor::decode::Error::message( "Invalid AttributeValue, value should be either String or Bytes", diff --git a/rust/c509-certificate/src/attributes/mod.rs b/rust/c509-certificate/src/attributes/mod.rs index 898c3233408..6b830f28dd5 100644 --- a/rust/c509-certificate/src/attributes/mod.rs +++ b/rust/c509-certificate/src/attributes/mod.rs @@ -17,6 +17,8 @@ use attribute::Attribute; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; +use crate::helper::{decode::decode_array_len, encode::encode_array_len}; + pub mod attribute; mod data; @@ -60,7 +62,7 @@ impl Encode<()> for Attributes { )); } // The attribute type should be included in array too - e.array(self.0.len() as u64 * 2)?; + encode_array_len(e, "Attributes", self.0.len() as u64 * 2)?; for attribute in &self.0 { attribute.encode(e, ctx)?; } @@ -69,10 +71,8 @@ impl Encode<()> for Attributes { } impl Decode<'_, ()> for Attributes { - fn decode(d: &mut Decoder<'_>, _ctx: &mut ()) -> Result { - let len = d - .array()? - .ok_or_else(|| minicbor::decode::Error::message("Failed to get array length"))?; + fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { + let len = decode_array_len(d, "Attributes")?; if len == 0 { return Err(minicbor::decode::Error::message("Attributes is empty")); } @@ -81,7 +81,7 @@ impl Decode<'_, ()> for Attributes { // The attribute type is included in an array, so divide by 2 for _ in 0..len / 2 { - let attribute = Attribute::decode(d, &mut ())?; + let attribute = Attribute::decode(d, ctx)?; attributes.add_attribute(attribute); } diff --git a/rust/c509-certificate/src/big_uint.rs b/rust/c509-certificate/src/big_uint.rs index 722965ae08c..9a8cfdb644b 100644 --- a/rust/c509-certificate/src/big_uint.rs +++ b/rust/c509-certificate/src/big_uint.rs @@ -8,6 +8,7 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; +use crate::helper::{decode::decode_bytes, encode::encode_bytes}; /// A struct representing an unwrapped CBOR unsigned bignum. #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] @@ -45,7 +46,7 @@ impl Encode<()> for UnwrappedBigUint { .copied() .collect::>(); - e.bytes(&significant_bytes)?; + encode_bytes(e, "Unwrapped big uint", &significant_bytes)?; Ok(()) } } @@ -53,8 +54,7 @@ impl Encode<()> for UnwrappedBigUint { impl Decode<'_, ()> for UnwrappedBigUint { fn decode(d: &mut Decoder<'_>, _ctx: &mut ()) -> Result { // Turn bytes into u64 - let b = d - .bytes()? + let b = decode_bytes(d, "Unwrapped big uint")? .iter() .fold(0, |acc, &b| (acc << 8) | u64::from(b)); Ok(UnwrappedBigUint::new(b)) diff --git a/rust/c509-certificate/src/c509.rs b/rust/c509-certificate/src/c509.rs index 8c2543d907d..dfd6d7d019f 100644 --- a/rust/c509-certificate/src/c509.rs +++ b/rust/c509-certificate/src/c509.rs @@ -3,7 +3,13 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; -use crate::tbs_cert::TbsCert; +use crate::{ + helper::{ + decode::{decode_bytes, decode_datatype}, + encode::{encode_bytes, encode_null}, + }, + tbs_cert::TbsCert, +}; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] /// A struct represents the `C509` Certificate. @@ -43,8 +49,8 @@ impl Encode<()> for C509 { ) -> Result<(), minicbor::encode::Error> { self.tbs_cert.encode(e, ctx)?; match self.issuer_signature_value { - Some(ref value) => e.bytes(value)?, - None => e.null()?, + Some(ref value) => encode_bytes(e, "C509 Issuer Signature value", value)?, + None => encode_null(e, "C509 Issuer Signature value")?, }; Ok(()) } @@ -53,8 +59,8 @@ impl Encode<()> for C509 { impl Decode<'_, ()> for C509 { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { let tbs_cert = TbsCert::decode(d, ctx)?; - let issuer_signature_value = match d.datatype()? { - minicbor::data::Type::Bytes => Some(d.bytes()?.to_vec()), + let issuer_signature_value = match decode_datatype(d, "C509 Issuer Signature value")? { + minicbor::data::Type::Bytes => Some(decode_bytes(d, "C509 Issuer Signature value")?), _ => None, }; Ok(Self::new(tbs_cert, issuer_signature_value)) diff --git a/rust/c509-certificate/src/extensions/alt_name.rs b/rust/c509-certificate/src/extensions/alt_name.rs index 9681fec63df..0f9896c8588 100644 --- a/rust/c509-certificate/src/extensions/alt_name.rs +++ b/rust/c509-certificate/src/extensions/alt_name.rs @@ -4,9 +4,15 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; -use crate::general_names::{ - general_name::{GeneralName, GeneralNameTypeRegistry, GeneralNameValue}, - GeneralNames, +use crate::{ + general_names::{ + general_name::{GeneralName, GeneralNameTypeRegistry, GeneralNameValue}, + GeneralNames, + }, + helper::{ + decode::{decode_datatype, decode_helper}, + encode::encode_helper, + }, }; /// Alternative Name extension. @@ -45,6 +51,8 @@ impl Decode<'_, ()> for AlternativeName { // ------------------GeneralNamesOrText-------------------- /// Enum for type that can be a `GeneralNames` or a text use in `AlternativeName`. +/// Type `Text` is also considered as a `GeneralNames` with only 1 `DNSName` as +/// a special case. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum GeneralNamesOrText { @@ -63,7 +71,7 @@ impl Encode<()> for GeneralNamesOrText { let gn = gns .general_names() .first() - .ok_or(minicbor::encode::Error::message("GeneralNames is empty"))?; + .ok_or(minicbor::encode::Error::message("General Names is empty"))?; // Check whether there is only 1 item in the array which is a DNSName if gns.general_names().len() == 1 && gn.gn_type().is_dns_name() { gn.gn_value().encode(e, ctx)?; @@ -72,7 +80,7 @@ impl Encode<()> for GeneralNamesOrText { } }, GeneralNamesOrText::Text(text) => { - e.str(text)?; + encode_helper(e, "Alternative Name - General Name Text", ctx, text)?; }, } Ok(()) @@ -81,12 +89,16 @@ impl Encode<()> for GeneralNamesOrText { impl Decode<'_, ()> for GeneralNamesOrText { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - match d.datatype()? { + match decode_datatype(d, "Alternative Name - General Names")? { // If it is a string it is a GeneralNames with only 1 DNSName minicbor::data::Type::String => { let gn_dns = GeneralName::new( GeneralNameTypeRegistry::DNSName, - GeneralNameValue::Text(d.str()?.to_string()), + GeneralNameValue::Text(decode_helper( + d, + "Alternative Name - General Name Text", + ctx, + )?), ); let mut gns = GeneralNames::new(); gns.add_general_name(gn_dns); diff --git a/rust/c509-certificate/src/extensions/extension/mod.rs b/rust/c509-certificate/src/extensions/extension/mod.rs index 3c261af0002..88707936049 100644 --- a/rust/c509-certificate/src/extensions/extension/mod.rs +++ b/rust/c509-certificate/src/extensions/extension/mod.rs @@ -10,7 +10,13 @@ use serde::{Deserialize, Deserializer, Serialize}; use strum_macros::EnumDiscriminants; use super::alt_name::AlternativeName; -use crate::oid::{C509oid, C509oidRegistered}; +use crate::{ + helper::{ + decode::{decode_bytes, decode_datatype, decode_helper}, + encode::{encode_bytes, encode_helper}, + }, + oid::{C509oid, C509oidRegistered}, +}; /// A struct of C509 `Extension` #[derive(Debug, Clone, PartialEq)] @@ -108,12 +114,12 @@ impl Encode<()> for Extension { } else { mapped_oid }; - e.i16(encoded_oid)?; + encode_helper(e, "Extension as OID int", ctx, &encoded_oid)?; } else { // Handle unwrapped CBOR OID self.registered_oid.c509_oid().encode(e, ctx)?; if self.critical { - e.bool(self.critical)?; + encode_helper(e, "Extension critical", ctx, &self.critical)?; } } // Encode the extension value @@ -124,7 +130,7 @@ impl Encode<()> for Extension { impl Decode<'_, ()> for Extension { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - match d.datatype()? { + match decode_datatype(d, "Extension")? { // Check whether OID is an int // Even the encoding is i16, the minicbor decoder doesn't know what type we encoded, // so need to check every possible type. @@ -132,7 +138,7 @@ impl Decode<'_, ()> for Extension { | minicbor::data::Type::U16 | minicbor::data::Type::I8 | minicbor::data::Type::I16 => { - let int_value = d.i16()?; + let int_value: i16 = decode_helper(d, "Extension as OID int", ctx)?; // OID can be negative due to critical flag, so need absolute the value let abs_int_value = int_value.abs(); let oid = @@ -152,14 +158,15 @@ impl Decode<'_, ()> for Extension { // Handle unwrapped CBOR OID let c509_oid = C509oid::decode(d, ctx)?; // Critical flag is optional, so if exist, this mean we have to decode it - let critical = if d.datatype()? == minicbor::data::Type::Bool { - d.bool()? - } else { - false - }; + let critical = + if decode_datatype(d, "Extension critical")? == minicbor::data::Type::Bool { + decode_helper(d, "Extension critical", ctx)? + } else { + false + }; // Decode bytes for extension value - let extension_value = ExtensionValue::Bytes(d.bytes()?.to_vec()); + let extension_value = ExtensionValue::Bytes(decode_bytes(d, "Extension")?); Ok(Extension::new( c509_oid.oid().clone(), @@ -207,10 +214,10 @@ impl Encode<()> for ExtensionValue { ) -> Result<(), minicbor::encode::Error> { match self { ExtensionValue::Int(value) => { - e.i64(*value)?; + encode_helper(e, "Extension Value", ctx, value)?; }, ExtensionValue::Bytes(value) => { - e.bytes(value)?; + encode_bytes(e, "Extension value", value)?; }, ExtensionValue::AlternativeName(value) => { value.encode(e, ctx)?; @@ -231,11 +238,11 @@ where C: ExtensionValueTypeTrait + Debug fn decode(d: &mut Decoder<'_>, ctx: &mut C) -> Result { match ctx.get_type() { ExtensionValueType::Int => { - let value = d.i64()?; + let value = decode_helper(d, "Extension value", ctx)?; Ok(ExtensionValue::Int(value)) }, ExtensionValueType::Bytes => { - let value = d.bytes()?.to_vec(); + let value = decode_bytes(d, "Extension value")?; Ok(ExtensionValue::Bytes(value)) }, ExtensionValueType::AlternativeName => { diff --git a/rust/c509-certificate/src/extensions/mod.rs b/rust/c509-certificate/src/extensions/mod.rs index f97268496d4..1f5ac45801e 100644 --- a/rust/c509-certificate/src/extensions/mod.rs +++ b/rust/c509-certificate/src/extensions/mod.rs @@ -25,6 +25,10 @@ use extension::{Extension, ExtensionValue}; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; +use crate::helper::{ + decode::{decode_array_len, decode_datatype, decode_helper}, + encode::{encode_array_len, encode_helper}, +}; /// OID of `KeyUsage` extension static KEY_USAGE_OID: Oid<'static> = oid!(2.5.29 .15); @@ -68,7 +72,7 @@ impl Encode<()> for Extensions { match extension.value() { ExtensionValue::Int(value) => { let ku_value = if extension.critical() { -value } else { *value }; - e.i64(ku_value)?; + encode_helper(e, "Extensions KeyUsage", ctx, &ku_value)?; return Ok(()); }, _ => { @@ -80,7 +84,7 @@ impl Encode<()> for Extensions { } } // Else handle the array of `Extension` - e.array(self.0.len() as u64)?; + encode_array_len(e, "Extensions", self.0.len() as u64)?; for extension in &self.0 { extension.encode(e, ctx)?; } @@ -91,14 +95,16 @@ impl Encode<()> for Extensions { impl Decode<'_, ()> for Extensions { fn decode(d: &mut Decoder<'_>, _ctx: &mut ()) -> Result { // If only KeyUsage is in the extension -> will only contain an int - if d.datatype()? == minicbor::data::Type::U8 || d.datatype()? == minicbor::data::Type::I8 { + if decode_datatype(d, "Extensions KeyUsage")? == minicbor::data::Type::U8 + || decode_datatype(d, "Extensions KeyUsage")? == minicbor::data::Type::I8 + { // Check if it's a negative number (critical extension) - let critical = d.datatype()? == minicbor::data::Type::I8; + let critical = + decode_datatype(d, "Extensions KeyUsage critical")? == minicbor::data::Type::I8; // Note that 'KeyUsage' BIT STRING is interpreted as an unsigned integer, // so we can absolute the value - let value = d.i64()?.abs(); - - let extension_value = ExtensionValue::Int(value); + let value: i64 = decode_helper(d, "Extensions KeyUsage value", &mut ())?; + let extension_value = ExtensionValue::Int(value.abs()); let mut extensions = Extensions::new(); extensions.add_extension(Extension::new( KEY_USAGE_OID.clone(), @@ -108,9 +114,7 @@ impl Decode<'_, ()> for Extensions { return Ok(extensions); } // Handle array of extensions - let len = d - .array()? - .ok_or_else(|| minicbor::decode::Error::message("Failed to get array length"))?; + let len = decode_array_len(d, "Extensions")?; let mut extensions = Extensions::new(); for _ in 0..len { let extension = Extension::decode(d, &mut ())?; diff --git a/rust/c509-certificate/src/general_names/general_name.rs b/rust/c509-certificate/src/general_names/general_name.rs index 6a15e2ebd70..98b10bd9835 100644 --- a/rust/c509-certificate/src/general_names/general_name.rs +++ b/rust/c509-certificate/src/general_names/general_name.rs @@ -13,7 +13,14 @@ use super::{ data::{get_gn_from_int, get_gn_value_type_from_int, get_int_from_gn}, other_name_hw_module::OtherNameHardwareModuleName, }; -use crate::{name::Name, oid::C509oid}; +use crate::{ + helper::{ + decode::{decode_bytes, decode_datatype, decode_helper}, + encode::{encode_bytes, encode_helper}, + }, + name::Name, + oid::C509oid, +}; /// A struct represents a `GeneralName`. /// ```cddl @@ -54,7 +61,7 @@ impl Encode<()> for GeneralName { ) -> Result<(), minicbor::encode::Error> { // Encode GeneralNameType as int let i = get_int_from_gn(self.gn_type).map_err(minicbor::encode::Error::message)?; - e.i16(i)?; + encode_helper(e, "General Name as OID int", ctx, &i)?; // Encode GeneralNameValue as its type self.value.encode(e, ctx)?; Ok(()) @@ -63,8 +70,10 @@ impl Encode<()> for GeneralName { impl Decode<'_, ()> for GeneralName { fn decode(d: &mut Decoder<'_>, _ctx: &mut ()) -> Result { - if minicbor::data::Type::U8 == d.datatype()? || minicbor::data::Type::I8 == d.datatype()? { - let i = d.i16()?; + if decode_datatype(d, "General Name as OID int")? == minicbor::data::Type::U8 + || decode_datatype(d, "General Name as OID int")? == minicbor::data::Type::I8 + { + let i = decode_helper(d, "General Name as OID int", &mut ())?; let gn = get_gn_from_int(i).map_err(minicbor::decode::Error::message)?; let value_type = get_gn_value_type_from_int(i).map_err(minicbor::decode::Error::message)?; @@ -75,7 +84,7 @@ impl Decode<'_, ()> for GeneralName { } else { // GeneralName is not type int Err(minicbor::decode::Error::message( - "GeneralName id type invalid, expected int", + "GeneralName ID type invalid, expected int", )) } } @@ -149,10 +158,10 @@ impl Encode<()> for GeneralNameValue { ) -> Result<(), minicbor::encode::Error> { match self { GeneralNameValue::Text(value) => { - e.str(value)?; + encode_helper(e, "General Name value", ctx, value)?; }, GeneralNameValue::Bytes(value) => { - e.bytes(value)?; + encode_bytes(e, "General Name value", value)?; }, GeneralNameValue::Oid(value) => { value.encode(e, ctx)?; @@ -178,11 +187,11 @@ where C: GeneralNameValueTrait + Debug fn decode(d: &mut Decoder<'_>, ctx: &mut C) -> Result { match ctx.get_type() { GeneralNameValueType::Text => { - let value = d.str()?.to_string(); + let value = decode_helper(d, "General Name value", ctx)?; Ok(GeneralNameValue::Text(value)) }, GeneralNameValueType::Bytes => { - let value = d.bytes()?.to_vec(); + let value = decode_bytes(d, "General Name value")?; Ok(GeneralNameValue::Bytes(value)) }, GeneralNameValueType::Oid => { diff --git a/rust/c509-certificate/src/general_names/mod.rs b/rust/c509-certificate/src/general_names/mod.rs index d46413ea52e..334ed695a42 100644 --- a/rust/c509-certificate/src/general_names/mod.rs +++ b/rust/c509-certificate/src/general_names/mod.rs @@ -10,6 +10,8 @@ use general_name::GeneralName; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; +use crate::helper::{decode::decode_array_len, encode::encode_array_len}; + /// A struct represents an array of `GeneralName`. /// /// ```cddl @@ -49,11 +51,11 @@ impl Encode<()> for GeneralNames { ) -> Result<(), minicbor::encode::Error> { if self.0.is_empty() { return Err(minicbor::encode::Error::message( - "GeneralNames should not be empty", + "General Names should not be empty", )); } // The general name type should be included in array too - e.array(self.0.len() as u64 * 2)?; + encode_array_len(e, "General Names", self.0.len() as u64 * 2)?; for gn in &self.0 { gn.encode(e, ctx)?; } @@ -63,9 +65,7 @@ impl Encode<()> for GeneralNames { impl Decode<'_, ()> for GeneralNames { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - let len = d.array()?.ok_or(minicbor::decode::Error::message( - "GeneralNames should be an array", - ))?; + let len = decode_array_len(d, "General Names")?; let mut gn = GeneralNames::new(); for _ in 0..len / 2 { gn.add_general_name(GeneralName::decode(d, ctx)?); diff --git a/rust/c509-certificate/src/general_names/other_name_hw_module.rs b/rust/c509-certificate/src/general_names/other_name_hw_module.rs index 9e6ba200005..7e2660cc088 100644 --- a/rust/c509-certificate/src/general_names/other_name_hw_module.rs +++ b/rust/c509-certificate/src/general_names/other_name_hw_module.rs @@ -7,7 +7,13 @@ use asn1_rs::Oid; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; -use crate::oid::C509oid; +use crate::{ + helper::{ + decode::{decode_array_len, decode_bytes}, + encode::{encode_array_len, encode_bytes}, + }, + oid::C509oid, +}; /// A struct represents the hardwareModuleName type of otherName. /// Containing a pair of ( hwType, hwSerialNum ) as mentioned in @@ -47,18 +53,22 @@ impl Encode<()> for OtherNameHardwareModuleName { fn encode( &self, e: &mut Encoder, ctx: &mut (), ) -> Result<(), minicbor::encode::Error> { - e.array(2)?; + encode_array_len(e, "OtherNameHardwareModule", 2)?; self.hw_type.encode(e, ctx)?; - e.bytes(&self.hw_serial_num)?; + encode_bytes( + e, + "OtherNameHardwareModule serial number", + &self.hw_serial_num, + )?; Ok(()) } } impl<'a> Decode<'a, ()> for OtherNameHardwareModuleName { fn decode(d: &mut Decoder<'a>, ctx: &mut ()) -> Result { - d.array()?; + decode_array_len(d, "OtherNameHardwareModule")?; let hw_type = C509oid::decode(d, ctx)?; - let hw_serial_num = d.bytes()?.to_vec(); + let hw_serial_num = decode_bytes(d, "OtherNameHardwareModule serial number")?; Ok(OtherNameHardwareModuleName::new( hw_type.oid().clone(), hw_serial_num, diff --git a/rust/c509-certificate/src/helper/decode.rs b/rust/c509-certificate/src/helper/decode.rs new file mode 100644 index 00000000000..0b760e130e8 --- /dev/null +++ b/rust/c509-certificate/src/helper/decode.rs @@ -0,0 +1,62 @@ +//! Helper functions for decoding CBOR data. + +use minicbor::{decode, Decoder}; + +/// Generic helper function for decoding different types. +pub(crate) fn decode_helper<'a, T, C>( + d: &mut Decoder<'a>, from: &str, context: &mut C, +) -> Result +where T: minicbor::Decode<'a, C> { + T::decode(d, context).map_err(|e| { + decode::Error::message(&format!( + "Failed to decode {:?} in {from}: {e}", + std::any::type_name::() + )) + }) +} + +/// Helper function for decoding bytes. +pub(crate) fn decode_bytes(d: &mut Decoder, from: &str) -> Result, decode::Error> { + d.bytes().map(<[u8]>::to_vec).map_err(|e| { + decode::Error::message(&format!( + "Failed to decode bytes in {from}: + {e}" + )) + }) +} + +/// Helper function for decoding array. +pub(crate) fn decode_array_len(d: &mut Decoder, from: &str) -> Result { + d.array() + .map_err(|e| { + decode::Error::message(&format!( + "Failed to decode array in {from}: + {e}" + )) + })? + .ok_or(decode::Error::message(&format!( + "Failed to decode array in {from}, unexpected indefinite length", + ))) +} + +/// Helper function for decoding null. +pub(crate) fn decode_null(d: &mut Decoder, from: &str) -> Result<(), decode::Error> { + d.null().map_err(|e| { + decode::Error::message(&format!( + "Failed to decode null in {from}: + {e}" + )) + }) +} + +/// Helper function for decoding datatype. +pub(crate) fn decode_datatype( + d: &mut Decoder, from: &str, +) -> Result { + d.datatype().map_err(|e| { + decode::Error::message(&format!( + "Failed to decode datatype in {from}: + {e}" + )) + }) +} diff --git a/rust/c509-certificate/src/helper/encode.rs b/rust/c509-certificate/src/helper/encode.rs new file mode 100644 index 00000000000..0cbfe752878 --- /dev/null +++ b/rust/c509-certificate/src/helper/encode.rs @@ -0,0 +1,54 @@ +//! Helper functions for encoding CBOR data. + +use minicbor::{ + encode::{self, Write}, + Encoder, +}; + +/// Generic helper function for encoding different types. +pub(crate) fn encode_helper( + e: &mut Encoder, from: &str, ctx: &mut C, value: &T, +) -> Result<(), encode::Error> +where T: minicbor::Encode { + T::encode(value, e, ctx).map_err(|err| { + encode::Error::with_message( + err, + &format!( + "Failed to encode {:?} in {from}", + std::any::type_name::() + ), + ) + })?; + + Ok(()) +} + +/// Helper function for encoding bytes. +pub(crate) fn encode_bytes( + e: &mut Encoder, from: &str, value: &[u8], +) -> Result<(), encode::Error> { + e.bytes(value).map_err(|err| { + encode::Error::with_message(err, &format!("Failed to encode bytes in {from}")) + })?; + Ok(()) +} + +/// Helper function for encoding null. +pub(crate) fn encode_null( + e: &mut Encoder, from: &str, +) -> Result<(), encode::Error> { + e.null().map_err(|err| { + encode::Error::with_message(err, &format!("Failed to encode null in {from}")) + })?; + Ok(()) +} + +/// Helper function for encoding array. +pub(crate) fn encode_array_len( + e: &mut Encoder, from: &str, len: u64, +) -> Result<(), encode::Error> { + e.array(len).map_err(|err| { + encode::Error::with_message(err, &format!("Failed to encode array in {from}")) + })?; + Ok(()) +} diff --git a/rust/c509-certificate/src/helper/mod.rs b/rust/c509-certificate/src/helper/mod.rs new file mode 100644 index 00000000000..fc80e075b4e --- /dev/null +++ b/rust/c509-certificate/src/helper/mod.rs @@ -0,0 +1,3 @@ +//! Helper module +pub mod decode; +pub mod encode; diff --git a/rust/c509-certificate/src/issuer_sig_algo/mod.rs b/rust/c509-certificate/src/issuer_sig_algo/mod.rs index db15c1f6884..ce31e8b23fd 100644 --- a/rust/c509-certificate/src/issuer_sig_algo/mod.rs +++ b/rust/c509-certificate/src/issuer_sig_algo/mod.rs @@ -14,7 +14,14 @@ use data::{get_oid_from_int, ISSUER_SIG_ALGO_LOOKUP}; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Deserializer, Serialize}; -use crate::{algorithm_identifier::AlgorithmIdentifier, oid::C509oidRegistered}; +use crate::{ + algorithm_identifier::AlgorithmIdentifier, + helper::{ + decode::{decode_datatype, decode_helper}, + encode::encode_helper, + }, + oid::C509oidRegistered, +}; /// A struct represents the `IssuerSignatureAlgorithm` #[derive(Debug, Clone, PartialEq)] @@ -92,7 +99,7 @@ impl Encode<()> for IssuerSignatureAlgorithm { .get_map() .get_by_right(self.registered_oid.c509_oid().oid()) { - e.i16(i)?; + encode_helper(e, "Issuer Signature Algorithm as OID int", ctx, &i)?; } else { AlgorithmIdentifier::encode(&self.algo_identifier, e, ctx)?; } @@ -102,10 +109,10 @@ impl Encode<()> for IssuerSignatureAlgorithm { impl Decode<'_, ()> for IssuerSignatureAlgorithm { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - match d.datatype()? { + match decode_datatype(d, "Issuer Signature Algorithm")? { // Check i16 for -256 and -256 minicbor::data::Type::U8 | minicbor::data::Type::I16 => { - let i = d.i16()?; + let i = decode_helper(d, "Issuer Signature Algorithm as OID int", ctx)?; let oid = get_oid_from_int(i).map_err(minicbor::decode::Error::message)?; Ok(Self::new(oid, None)) }, diff --git a/rust/c509-certificate/src/lib.rs b/rust/c509-certificate/src/lib.rs index 808de48c1dd..6a0e0821f85 100644 --- a/rust/c509-certificate/src/lib.rs +++ b/rust/c509-certificate/src/lib.rs @@ -46,6 +46,7 @@ pub mod big_uint; pub mod c509; pub mod extensions; pub mod general_names; +mod helper; pub mod issuer_sig_algo; pub mod name; pub mod oid; diff --git a/rust/c509-certificate/src/name/mod.rs b/rust/c509-certificate/src/name/mod.rs index 75c04bc0692..8a51f559210 100644 --- a/rust/c509-certificate/src/name/mod.rs +++ b/rust/c509-certificate/src/name/mod.rs @@ -17,11 +17,16 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use regex::Regex; use serde::{Deserialize, Serialize}; -use crate::attributes::{ - attribute::{Attribute, AttributeValue}, - Attributes, +use crate::{ + attributes::{ + attribute::{Attribute, AttributeValue}, + Attributes, + }, + helper::{ + decode::{decode_bytes, decode_datatype, decode_helper}, + encode::{encode_bytes, encode_helper}, + }, }; - /// OID of `CommonName` attribute. const COMMON_NAME_OID: Oid<'static> = oid!(2.5.4 .3); /// EUI-64 prefix. @@ -114,10 +119,10 @@ impl Encode<()> for NameValue { } }, NameValue::Text(text) => { - e.str(text)?; + encode_helper(e, "Name", ctx, text)?; }, NameValue::Bytes(bytes) => { - e.bytes(bytes)?; + encode_bytes(e, "Name", bytes)?; }, } Ok(()) @@ -126,11 +131,13 @@ impl Encode<()> for NameValue { impl Decode<'_, ()> for NameValue { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - match d.datatype()? { + match decode_datatype(d, "Name")? { minicbor::data::Type::Array => Ok(NameValue::Attributes(Attributes::decode(d, ctx)?)), // If Name is a text string, the attribute is a CommonName - minicbor::data::Type::String => Ok(create_attributes_with_cn(d.str()?.to_string())), - minicbor::data::Type::Bytes => decode_bytes(d), + minicbor::data::Type::String => { + Ok(create_attributes_with_cn(decode_helper(d, "Name", ctx)?)) + }, + minicbor::data::Type::Bytes => decode_bytes_helper(d), _ => { Err(minicbor::decode::Error::message( "Name must be an array, text or bytes", @@ -157,7 +164,11 @@ fn encode_cn_value( // string, prefixed with an initial byte set to '00' if hex_regex.is_match(s) && s.len() % 2 == 0 { let decoded_bytes = hex::decode(s).map_err(minicbor::encode::Error::message)?; - e.bytes(&[&[HEX_PREFIX], &decoded_bytes[..]].concat())?; + encode_bytes( + e, + "Common Name hex", + &[&[HEX_PREFIX], &decoded_bytes[..]].concat(), + )?; // An EUI-64 mapped from a 48-bit MAC address (i.e., of the form // "HH-HH-HH-FF-FE-HH-HH-HH) is encoded as a CBOR byte string prefixed with an @@ -176,7 +187,11 @@ fn encode_cn_value( .ok_or(minicbor::encode::Error::message( "Failed to get MAC EUI-64 bytes index 5 to 6", ))?; - e.bytes(&[&[EUI64_PREFIX], chunk2, chunk3].concat())?; + encode_bytes( + e, + "Common Name EUI-64 MAC", + &[&[EUI64_PREFIX], chunk2, chunk3].concat(), + )?; // an EUI-64 of the form "HH-HH-HH-HH-HH-HH-HH-HH" where 'H' // is one of the symbols '0'–'9' or 'A'–'F' it is encoded as a @@ -186,9 +201,13 @@ fn encode_cn_value( let clean_name = s.replace('-', ""); let decoded_bytes = hex::decode(clean_name).map_err(minicbor::encode::Error::message)?; - e.bytes(&[&[EUI64_PREFIX], &decoded_bytes[..]].concat())?; + encode_bytes( + e, + "Common Name EUI-64", + &[&[EUI64_PREFIX], &decoded_bytes[..]].concat(), + )?; } else { - e.str(s)?; + encode_helper(e, "Common Name", &mut (), s)?; } }, AttributeValue::Bytes(_) => { @@ -209,8 +228,8 @@ fn formatted_eui_bytes(data: &[u8]) -> String { } /// Decode bytes. -fn decode_bytes(d: &mut Decoder<'_>) -> Result { - let bytes = d.bytes()?; +fn decode_bytes_helper(d: &mut Decoder<'_>) -> Result { + let bytes = decode_bytes(d, "Name")?; let first_i = bytes.first().ok_or(minicbor::decode::Error::message( "Failed to get the first index of bytes", @@ -219,10 +238,10 @@ fn decode_bytes(d: &mut Decoder<'_>) -> Result decode_hex_cn_bytes(bytes), + HEX_PREFIX => decode_hex_cn_bytes(&bytes), // 0x01 for EUI - EUI64_PREFIX => decode_eui_cn_bytes(bytes), - _ => Ok(NameValue::Bytes(bytes.to_vec())), + EUI64_PREFIX => decode_eui_cn_bytes(&bytes), + _ => Ok(NameValue::Bytes(bytes)), } } diff --git a/rust/c509-certificate/src/oid.rs b/rust/c509-certificate/src/oid.rs index 6148dcfb43c..4f566394cbb 100644 --- a/rust/c509-certificate/src/oid.rs +++ b/rust/c509-certificate/src/oid.rs @@ -11,7 +11,10 @@ use minicbor::{decode, encode::Write, Decode, Decoder, Encode, Encoder}; use oid_registry::Oid; use serde::{Deserialize, Deserializer, Serialize}; -use crate::tables::IntegerToOidTable; +use crate::{ + helper::{decode::decode_bytes, encode::encode_bytes}, + tables::IntegerToOidTable, +}; /// A strut of C509 OID with Registered Integer. #[derive(Debug, Clone, PartialEq)] @@ -102,8 +105,7 @@ impl Encode<()> for C509oid { &self, e: &mut Encoder, _ctx: &mut (), ) -> Result<(), minicbor::encode::Error> { let oid_bytes = self.0.as_bytes(); - e.bytes(oid_bytes)?; - Ok(()) + encode_bytes(e, "C509 OID", oid_bytes) } } @@ -116,8 +118,8 @@ impl Decode<'_, ()> for C509oid { /// A C509oid instance. /// If the decoding fails, it will return an error. fn decode(d: &mut Decoder, _ctx: &mut ()) -> Result { - let oid_bytes = d.bytes()?; - let oid = Oid::new(oid_bytes.to_owned().into()); + let oid_bytes = decode_bytes(d, "C509 OID")?; + let oid = Oid::new(oid_bytes.into()); Ok(C509oid::new(oid)) } } diff --git a/rust/c509-certificate/src/subject_pub_key_algo/mod.rs b/rust/c509-certificate/src/subject_pub_key_algo/mod.rs index bd59a9b6112..380b2675196 100644 --- a/rust/c509-certificate/src/subject_pub_key_algo/mod.rs +++ b/rust/c509-certificate/src/subject_pub_key_algo/mod.rs @@ -16,7 +16,14 @@ use data::{get_oid_from_int, SUBJECT_PUB_KEY_ALGO_LOOKUP}; use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Deserializer, Serialize}; -use crate::{algorithm_identifier::AlgorithmIdentifier, oid::C509oidRegistered}; +use crate::{ + algorithm_identifier::AlgorithmIdentifier, + helper::{ + decode::{decode_datatype, decode_helper}, + encode::encode_helper, + }, + oid::C509oidRegistered, +}; /// A struct represents the `SubjectPubKeyAlgorithm` #[derive(Debug, Clone, PartialEq)] @@ -94,7 +101,7 @@ impl Encode<()> for SubjectPubKeyAlgorithm { .get_map() .get_by_right(self.registered_oid.c509_oid().oid()) { - e.i16(i)?; + encode_helper(e, "Subject public key algorithm", ctx, &i)?; } else { AlgorithmIdentifier::encode(&self.algo_identifier, e, ctx)?; } @@ -105,8 +112,8 @@ impl Encode<()> for SubjectPubKeyAlgorithm { impl Decode<'_, ()> for SubjectPubKeyAlgorithm { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { // Check u8 for 0 - 28 - if d.datatype()? == minicbor::data::Type::U8 { - let i = d.i16()?; + if decode_datatype(d, "Subject public key algorithm")? == minicbor::data::Type::U8 { + let i = decode_helper(d, "Subject public key algorithm", ctx)?; let oid = get_oid_from_int(i).map_err(minicbor::decode::Error::message)?; Ok(Self::new(oid, None)) } else { diff --git a/rust/c509-certificate/src/tbs_cert.rs b/rust/c509-certificate/src/tbs_cert.rs index e0e10551ebf..edd194b73ac 100644 --- a/rust/c509-certificate/src/tbs_cert.rs +++ b/rust/c509-certificate/src/tbs_cert.rs @@ -4,8 +4,16 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; use crate::{ - big_uint::UnwrappedBigUint, extensions::Extensions, issuer_sig_algo::IssuerSignatureAlgorithm, - name::Name, subject_pub_key_algo::SubjectPubKeyAlgorithm, time::Time, + big_uint::UnwrappedBigUint, + extensions::Extensions, + helper::{ + decode::{decode_bytes, decode_helper}, + encode::{encode_bytes, encode_helper}, + }, + issuer_sig_algo::IssuerSignatureAlgorithm, + name::Name, + subject_pub_key_algo::SubjectPubKeyAlgorithm, + time::Time, }; /// A struct represents a To Be Signed Certificate (TBS Certificate). @@ -131,7 +139,7 @@ impl Encode<()> for TbsCert { fn encode( &self, e: &mut Encoder, ctx: &mut (), ) -> Result<(), minicbor::encode::Error> { - e.u8(self.c509_certificate_type)?; + encode_helper(e, "Certificate type", ctx, &self.c509_certificate_type)?; self.certificate_serial_number.encode(e, ctx)?; self.issuer_signature_algorithm.encode(e, ctx)?; self.issuer.encode(e, ctx)?; @@ -139,7 +147,7 @@ impl Encode<()> for TbsCert { self.validity_not_after.encode(e, ctx)?; self.subject.encode(e, ctx)?; self.subject_public_key_algorithm.encode(e, ctx)?; - e.bytes(&self.subject_public_key)?; + encode_bytes(e, "Subject Public Key", &self.subject_public_key)?; self.extensions.encode(e, ctx)?; Ok(()) } @@ -147,7 +155,7 @@ impl Encode<()> for TbsCert { impl Decode<'_, ()> for TbsCert { fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result { - let cert_type = d.u8()?; + let cert_type = decode_helper(d, "Certificate type", ctx)?; let serial_number = UnwrappedBigUint::decode(d, ctx)?; let issuer_signature_algorithm = IssuerSignatureAlgorithm::decode(d, ctx)?; let issuer = Some(Name::decode(d, ctx)?); @@ -155,7 +163,7 @@ impl Decode<'_, ()> for TbsCert { let not_after = Time::decode(d, ctx)?; let subject = Name::decode(d, ctx)?; let subject_public_key_algorithm = SubjectPubKeyAlgorithm::decode(d, ctx)?; - let subject_public_key = d.bytes()?; + let subject_public_key = decode_bytes(d, "Subject Public Key")?; let extensions = Extensions::decode(d, ctx)?; Ok(TbsCert::new( @@ -167,7 +175,7 @@ impl Decode<'_, ()> for TbsCert { not_after, subject, subject_public_key_algorithm, - subject_public_key.to_vec(), + subject_public_key, extensions, )) } diff --git a/rust/c509-certificate/src/time.rs b/rust/c509-certificate/src/time.rs index 6fb9b0896ee..514687ab230 100644 --- a/rust/c509-certificate/src/time.rs +++ b/rust/c509-certificate/src/time.rs @@ -3,6 +3,11 @@ use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder}; use serde::{Deserialize, Serialize}; +use crate::helper::{ + decode::{decode_datatype, decode_helper, decode_null}, + encode::{encode_helper, encode_null}, +}; + /// A struct representing a time where it accept seconds since the Unix epoch. /// Doesn't support dates before the Unix epoch (January 1, 1970, 00:00:00 UTC) /// so unsigned integer is used. @@ -40,12 +45,12 @@ impl From