Skip to content

Commit

Permalink
fix: cbor encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
bkioshn committed May 29, 2024
1 parent ef70902 commit e6cc3f2
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 58 deletions.
60 changes: 40 additions & 20 deletions catalyst-gateway-crates/c509-certificate/src/cbor_encoder.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
use hex::FromHexError;
use minicbor::Encoder;
use oid::ObjectIdentifier;
use regex::Regex;
use thiserror::Error;

use crate::c509_enum::AttributesRegistry;

trait CborEncoder {
fn encoder(&self, encoder: &mut Encoder<&mut Vec<u8>>);
pub(crate) trait CborEncoder {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>);

fn encode_string(&self, encoder: &mut Encoder<&mut Vec<u8>>, s: &str) {
let _unused = encoder.str(s);
}

fn encode_bytes(&self, encoder: &mut Encoder<&mut Vec<u8>>, b: &[u8]) {
let _unused = encoder.bytes(b);
}

fn encode_oid(&self, encoder: &mut Encoder<&mut Vec<u8>>, s: &str) {
let oid = match ObjectIdentifier::try_from(s) {
Ok(oid) => oid,
Err(_) => return,
};
let oid: Vec<u8> = (&oid).into();
let _unused = encoder.bytes(&oid);
}
}

// ---------------------------------------------------
Expand All @@ -17,7 +35,7 @@ pub enum UnwrappedBiguint {
}

impl CborEncoder for UnwrappedBiguint {
fn encoder(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
match self {
UnwrappedBiguint::U64Value(u) => {
// Convert the integer to bytes
Expand All @@ -30,24 +48,26 @@ impl CborEncoder for UnwrappedBiguint {
.collect::<Vec<u8>>();

// Encode the significant bytes as a byte string in CBOR format
let _unused = encoder.bytes(&significant_bytes);
// FIXME - Is it better to just use encoder.bytes(&significant_bytes)?
self.encode_bytes(encoder, &significant_bytes);
},
}
}
}

// ---------------------------------------------------

const NOEXPDATE: u64 = 99991231235959;
pub type Time = u64;

impl CborEncoder for Time {
fn encoder(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
// The value "99991231235959Z" (no expiration date) is encoded as CBOR null
// Also add an option for using 0 as no expiration date
if *self == 0 || *self == 99991231235959 {
let _unused_exp = encoder.null();
if *self == 0 || *self == NOEXPDATE {
let _unused = encoder.null();
} else {
let _unused_time = encoder.u64(*self);
let _unused = encoder.u64(*self);
}
}
}
Expand Down Expand Up @@ -77,16 +97,16 @@ impl CborEncoder for Name {
/// Encode type Name
/// Since it is currently support only natively signed C509 certificates,
/// all text strings are UTF-8 encoded and all attributeType SHALL be non-negative
fn encoder(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
// If type Name contain single attribute common-name
if self.len() == 1 && self[0].name == AttributesRegistry::CommonName {
let _unused = encode_common_name_cn(&self[0].value.str_value, encoder);
} else {
let _unused_arr = encoder.array(self.len() as u64 * 2);
let _unused = encoder.array(self.len() as u64 * 2);
// a (CBOR int, CBOR text string) pair,
for data in self {
let _unused_u8 = encoder.u8(data.name as u8);
let _unused_str = encoder.str(&data.value.str_value);
let _unused = encoder.u8(data.name as u8);
let _unused = encoder.str(&data.value.str_value);
}
}
}
Expand Down Expand Up @@ -141,7 +161,7 @@ mod test_cbor_encoder {
let mut buffer: Vec<u8> = Vec::new();
let mut encoder: Encoder<&mut Vec<u8>> = Encoder::new(&mut buffer);
let number = UnwrappedBiguint::U64Value(128269);
number.encoder(&mut encoder);
number.encode(&mut encoder);
let result = hex::encode(buffer);
assert_eq!(result, "4301f50d");
}
Expand All @@ -151,9 +171,9 @@ mod test_cbor_encoder {
let mut buffer: Vec<u8> = Vec::new();
let mut encoder: Encoder<&mut Vec<u8>> = Encoder::new(&mut buffer);
let time: Time = 1672531200;
time.encoder(&mut encoder);
time.encode(&mut encoder);
let exp_time: Time = 99991231235959;
exp_time.encoder(&mut encoder);
exp_time.encode(&mut encoder);
assert_eq!(hex::encode(buffer), "1a63b0cd00f6");
}

Expand All @@ -168,7 +188,7 @@ mod test_cbor_encoder {
str_value: "RFC test CA".to_string(),
},
}];
name1.encoder(&mut encoder);
name1.encode(&mut encoder);

let name2: Name = vec![RelativeDistinguishedName {
name: AttributesRegistry::CommonName,
Expand All @@ -177,8 +197,8 @@ mod test_cbor_encoder {
str_value: "01-23-45-FF-FE-67-89-AB".to_string(),
},
}];
name2.encoder(&mut encoder);
name2.encode(&mut encoder);

assert_eq!(
hex::encode(buffer),
"6b524643207465737420434147010123456789ab"
Expand All @@ -191,7 +211,7 @@ mod test_cbor_encoder {
let mut encoder: Encoder<&mut Vec<u8>> = Encoder::new(&mut buffer);

// Issuer: C=US, ST=CA, O=Example Inc, OU=certification, CN=802.1AR CA
let name: Name = vec![
let name: Name = vec![
RelativeDistinguishedName {
name: AttributesRegistry::Country,
value: AttributeRegistryValue {
Expand Down Expand Up @@ -228,7 +248,7 @@ mod test_cbor_encoder {
},
},
];
name.encoder(&mut encoder);
name.encode(&mut encoder);
assert_eq!(
hex::encode(buffer),
"8a0462555306624341086b4578616d706c6520496e63096d63657274696669636174696f6e016a3830322e314152204341"
Expand Down
76 changes: 38 additions & 38 deletions catalyst-gateway-crates/c509-certificate/src/extensions/alt_name.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::cbor_encoder::CborEncoder;
use minicbor::Encoder;
use oid::prelude::*;
use oid::ObjectIdentifier;

use super::is_critical;

// Define the GeneralNames enum
/// Define the GeneralNamesRegistry enum
/// Section 9.9 https://datatracker.ietf.org/doc/draft-ietf-cose-cbor-encoded-cert/09/
#[allow(unused)]
#[derive(Debug, PartialEq, Clone)]
enum GeneralNames {
enum GeneralNamesRegistry {
OtherNameBundleEID = -3, // eid-structure from RFC 9171
OtherNameSmtpUTF8Mailbox = -2, // text
OtherNameHardwareModuleName = -1, // [ ~oid, bytes ]
Expand All @@ -21,7 +23,7 @@ enum GeneralNames {

#[allow(unused)]
#[derive(Clone)]
pub(crate) enum GeneralNamesType {
pub(crate) enum GeneralNamesRegistryType {
String(String),
Bytes(Vec<u8>),
Oid(String),
Expand All @@ -36,40 +38,39 @@ pub(crate) struct OtherNameType {
hw_serial_num: Vec<u8>,
}

impl CborEncoder for Vec<OtherNameType> {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
let _unused = encoder.array(self.len() as u64);

for item in self {
let oid = match ObjectIdentifier::try_from(item.hw_type.as_str()) {
Ok(oid) => oid,
Err(_) => return,
};
let oid: Vec<u8> = (&oid).into();
let _unused = encoder.bytes(&oid);
let _unused = encoder.bytes(&item.hw_serial_num);
}
}
}

// Define the GeneralName struct
#[derive(Clone)]
pub(crate) struct GeneralName {
gn_name: GeneralNames,
gn_value: GeneralNamesType,
gn_name: GeneralNamesRegistry,
gn_value: GeneralNamesRegistryType,
}

impl GeneralNamesType {
impl CborEncoder for GeneralNamesRegistryType {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
match self {
GeneralNamesType::String(s) => {
encoder.str(s).unwrap();
},
GeneralNamesType::Bytes(b) => {
encoder.bytes(b).unwrap();
},
GeneralNamesType::Oid(s) => {
let oid = ObjectIdentifier::try_from(s.as_str()).unwrap();
let oid: Vec<u8> = (&oid).into();
encoder.bytes(&oid).unwrap();
},
GeneralNamesType::OidAndBytes(b) => {
encoder.array(b.len() as u64).unwrap();
for x in b {
let oid = ObjectIdentifier::try_from(x.hw_type.clone()).unwrap();
let oid: Vec<u8> = (&oid).into();
encoder.bytes(&oid).unwrap();
encoder.bytes(&x.hw_serial_num).unwrap();
}
},
GeneralNamesRegistryType::String(s) => self.encode_string(encoder, s),
GeneralNamesRegistryType::Bytes(b) => self.encode_bytes(encoder, b),
GeneralNamesRegistryType::Oid(s) => self.encode_oid(encoder, s),
GeneralNamesRegistryType::OidAndBytes(b) => b.encode(encoder),
}
}
}

#[allow(unused)]
impl GeneralName {
fn encode(&self, encoder: &mut Encoder<&mut Vec<u8>>) {
Expand All @@ -82,12 +83,13 @@ impl GeneralName {
fn encode_alt_name(b: Vec<GeneralName>, critical: bool, encoder: &mut Encoder<&mut Vec<u8>>) {
// If subjectAltName contains exactly one dNSName, the array and the int
// are omitted and extensionValue is the dNSName encoded as a CBOR text string.
if b.len() == 1 && b[0].gn_name == GeneralNames::DNSName {
if b.len() == 1 && b[0].gn_name == GeneralNamesRegistry::DNSName {
let c = is_critical(critical);
encoder.i16(b[0].gn_name.clone() as i16 * c);
b[0].gn_value.encode(encoder);
} else {
encoder.array(b.len() as u64);
// A pair of ( hwType, hwSerialNum ) is encoded as a CBOR array of two items.
encoder.array(b.len() as u64 * 2);
for gn in b {
encoder.i8(gn.gn_name.clone() as i8).unwrap();
gn.gn_value.encode(encoder);
Expand All @@ -106,8 +108,8 @@ mod tests {
let mut buffer = Vec::new();
let mut encoder = Encoder::new(&mut buffer);
let general_name = GeneralName {
gn_name: GeneralNames::DNSName,
gn_value: GeneralNamesType::String("example.com".to_string()),
gn_name: GeneralNamesRegistry::DNSName,
gn_value: GeneralNamesRegistryType::String("example.com".to_string()),
};
encode_alt_name(vec![general_name], false, &mut encoder);
println!("{:?}", hex::encode(buffer));
Expand All @@ -120,22 +122,20 @@ mod tests {
// value:
// hwType: 1.3.6.1.4.1.6175.10.1
// hwSerialNum: 01:02:03:04

// 3, [-1, [h'2B06010401B01F0A01', h'01020304']]

// 03 82 20 82 49 2B 06 01 04 01 B0 1F 0A 01 44 01 02 03 04
#[test]
fn test_encode_general_name_hw_module_name() {
fn test() {
let mut buffer = Vec::new();
let mut encoder = Encoder::new(&mut buffer);
let general_name = GeneralName {
gn_name: GeneralNames::OtherNameHardwareModuleName,
gn_value: GeneralNamesType::OidAndBytes(vec![OtherNameType {
gn_name: GeneralNamesRegistry::OtherNameHardwareModuleName,
gn_value: GeneralNamesRegistryType::OidAndBytes(vec![OtherNameType {
hw_type: "1.3.6.1.4.1.6175.10.1".to_string(),
hw_serial_num: vec![0x01, 0x02, 0x03, 0x04],
}]),
};
encode_alt_name(vec![general_name], false, &mut encoder);
println!("{:?}", hex::encode(buffer));
assert_eq!(hex::encode(buffer), "822081492b06010401b01f0a014401020304");
}
}

0 comments on commit e6cc3f2

Please sign in to comment.