diff --git a/catalyst-gateway/crates/c509-certificate/src/c509-cert.rs b/catalyst-gateway/crates/c509-certificate/src/c509-cert.rs deleted file mode 100644 index 944a63e0e8..0000000000 --- a/catalyst-gateway/crates/c509-certificate/src/c509-cert.rs +++ /dev/null @@ -1,176 +0,0 @@ -use std::{fmt::Error}; -use regex::Regex; - -enum C509CertificateType { - SignedC509Cert, - C509Cert, -} - -enum AttributesRegistry { - Email, - CommonName, // CN - SurName, // SN - SerialNumber, - Country, // C - Locality, // L - StateOrProvince, // ST - StreetAddress, - Organization, // O - OrganizationUnit, // OU - Title, // T - Business, - PostalCode, // PC - GivenName, - Initials, - GenerationQualifier, - DNQualifier, - Pseudonym, - OrganizationIdentifier, - IncLocality, - IncState, - IncCountry, - DomainComponent, // DC - PostalAddress, // postalAddress - Name, // name - TelephoneNumber, // telephoneNumber - DirManDomainName, // dmdName - UserID, // uid - UnstructuredName, // unstructuredName - UnstructuredAddress, // unstructuredAddress -} - -enum PubKeyAlgoRegistry { - RSA = 0, - Secp256r1 = 1 , - Secp384r1 = 2, - Secp521r1 = 3, - X25519 = 8, - X448 = 9, - Ed25519 = 10, - Ed448 = 11, - HSSLMS = 16, - XMSS = 17, - XMSSMT = 18, - Brainpool256r1 = 24, - Brainpool384r1 = 25, - Brainpool512r1 = 26, - Frp256v1 = 27, - SM2P256v1 = 28, -} - -enum StringType { - UTF8String, - PrintableString, - IA5String -} - -struct Name { - attribute: &str, - value: &str, -} - -struct TbsCertificate { - certificate_type: C509CertificateType, - serial_number: u64, - issuer: Name, - validity_not_before: u64, - validity_not_after: u64, - subject: Name, - subject_public_key_algorithm: String, - subject_public_key: String, - extensions: Vec, - issuer_signature_algorithm: String, -} - -// ASN.1 PrintableString type supports upper case letters "A" through "Z", -// lowercase letters "a" through "z", the digits "0" through "9", space, and -// common punctuation marks. Note that PrintableString does not support -// the "@", "&", and "*" characters. -const PRINTABLESTRINGREGEX = "^[A-Za-z0-9 '()+,-./:=?]*$"; - -// Parse a DER x509 certificate and encode to CBOR -fn parse_x509_cert(input: Vec) { - // x509 certificate fields (sequence of 3 required fields) -} - -// Handle c509 type Name -fn cbor_c509_type_name(names: Vec) { - // Single attribute name with commonName or cn - if names.len() == 1 && (names[0].attribute == "commonName" || names[0].attribute == "cn") { - let pattern = Regex::new(r"^[0-9a-f]+$").unwrap(); - let eui_64_pattern = Regex::new(r"^[\p{XDigit}]{2}(?:-[\p{XDigit}]{2}){7}$").unwrap(); - - if (names[0].value.len() >= 2 && names[0].value.len() % 2 == 0 && pattern.is_match(names[0].value)) { - // encoded as a CBOR byte string, prefixed with an initial byte set to '00'. - } else if (eui_64_pattern.is_match(names[0].value)) { - // encoded as a CBOR byte string prefixed with an initial byte set to '01', for a total length of 7. - } else { - // encoded as a CBOR text string. - } - } else { - for name in names { - // Get the number of the attribute registry - let attribute_type = get_attribute_registry_number(name.attribute); - // Identify the character string type. - // + for UTF8String - for PrintableString - let string_type = get_string_type(name.value); - if string_type == StringType::UTF8String { - // Positive integer - } else { - // Negative integer - } - } - } -} - -fn get_string_type(value: &str) -> StringType { - let pattern = Regex::new(r`$PRINTABLESTRINGREGEX`).unwrap(); - // FIXME - Check for Ia5String - if pattern.is_match(value) { - StringType::PrintableString - } else { - StringType::UTF8String - } -} -fn get_attribute_registry_number(text: &str) -> u32{ - match text { - "emailAddress" | "e-mailAddress" => AttributesRegistry::Email as u32, - "commonName" | "cn" => AttributesRegistry::CommonName as u32, - "surname" | "sn" => AttributesRegistry::SurName as u32, - "serialNumber" => AttributesRegistry::SerialNumber as u32, - "countryName" | "c" => AttributesRegistry::Country as u32, - "localityName" | "locality" | "l" => AttributesRegistry::Locality as u32, - "stateOrProvinceName" | "st" => AttributesRegistry::StateOrProvince as u32, - "streetAddress" | "street" => AttributesRegistry::StreetAddress as u32, - "organizationName" | "o" => AttributesRegistry::Organization as u32, - "title" => AttributesRegistry::Title as u32, - "businessCategory" => AttributesRegistry::Business as u32, - "postalCode" => AttributesRegistry::PostalCode as u32, - "givenName" => AttributesRegistry::GivenName as u32, - "initials" => AttributesRegistry::Initials as u32, - "generationQualifier" => AttributesRegistry::GenerationQualifier as u32, - "dnQualifier" => AttributesRegistry::DNQualifier as u32, - "pseudoNym" => AttributesRegistry::Pseudonym as u32, - "organizationIdentifier" => AttributesRegistry::OrganizationIdentifier as u32, - "jurisdictionOfIncorporationLocalityName" => AttributesRegistry::IncLocality as u32, - "jurisdictionOfIncorporation" => AttributesRegistry::IncState as u32, - "jurisdictionOfIncorporationCountryName" => AttributesRegistry::IncCountry as u32, - "domainComponent" | "dc" => AttributesRegistry::DomainComponent as u32, - "postalAddress" => AttributesRegistry::PostalAddress as u32, - "name" => AttributesRegistry::Name as u32, - "telephoneNumber" => AttributesRegistry::TelephoneNumber as u32, - "dmdName" => AttributesRegistry::DirManDomainName as u32, - "uid" => AttributesRegistry::UserID as u32, - "unstructuredName" => AttributesRegistry::UnstructuredName as u32, - "unstructuredAddress" => AttributesRegistry::UnstructuredAddress as u32, - _ => 0, - } -} - -fn check_version(version: u8) -> Result { - match version { - 0 => Ok(C509CertificateType::C509Cert), - 1 => Ok(C509CertificateType::SignedC509Cert), - _ => Err(Error), - } -} diff --git a/catalyst-gateway/crates/c509-certificate/src/c509_cert.rs b/catalyst-gateway/crates/c509-certificate/src/c509_cert.rs new file mode 100644 index 0000000000..bfbcea2276 --- /dev/null +++ b/catalyst-gateway/crates/c509-certificate/src/c509_cert.rs @@ -0,0 +1,125 @@ +use std::io; + +use minicbor::{Encode, Encoder}; +use regex::Regex; + +use crate::c509_enum::StringType; + +impl<'a> Encode<()> for StringType { + fn encode( + &self, e: &mut Encoder, _: &mut (), + ) -> Result<(), minicbor::encode::Error> { + match self { + StringType::Utf8String(text) + | StringType::PrintableString(text) + | StringType::Ia5String(text) => { + // Convert the result from `Result<&mut Encoder, _>` to `Result<(), _>` + e.str(text).map(|_| ()) + }, + StringType::HexByteString(bytes) | StringType::Eui64ByteString(bytes) => { + // Similarly, handle the return value correctly + e.bytes(&bytes).map(|_| ()) + }, + } + } +} + +#[allow(unused)] +struct AttributeRegistry { + name: String, + value: String, +} + +#[allow(unused)] +// If type Name contain single attribute common-name +fn type_name( + b: Vec, encoder: &mut Encoder<&mut Vec>, +) -> Result, io::Error> { + if b.len() == 1 { + if b[0].name == "CN" { + println!("common-name"); + encode_common_name(&b[0].value, encoder); + } + } + Ok(Vec::new()) +} + +#[allow(unused)] +fn encode_common_name(name: &str, encoder: &mut Encoder<&mut Vec>) { + // Compile Regex only once and handle errors gracefully + let hex_regex = Regex::new(r"^[0-9a-fA-F]+$") + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .unwrap(); + let eui64_regex = Regex::new(r"^([0-9A-Fa-f]{2}-){7}[0-9A-Fa-f]{2}$") + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .unwrap(); + let mac_eui64_regex = + Regex::new(r"^([0-9A-Fa-f]{2}-){3}FF-FE-([0-9A-Fa-f]{2}-){2}[0-9A-Fa-f]{2}$") + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .unwrap(); + + if name.contains('-') { + let clean_name = name.replace("-", ""); + let decoded_bytes = hex::decode(&clean_name) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .unwrap(); + println!("{:?}", decoded_bytes); + println!("name {}", name); + println!("{:?}", hex_regex.is_match(name)); + if hex_regex.is_match(name) && name.len() % 2 == 0 { + let data = [&[0x00], &decoded_bytes[..]].concat(); + encoder.bytes(&data).unwrap(); + } else if mac_eui64_regex.is_match(name) { + let data: Vec = [&[0x01], &decoded_bytes[..3], &decoded_bytes[5..]].concat(); // Skip FF-FE bytes + encoder.bytes(&data).unwrap(); + } else if eui64_regex.is_match(name) { + let data = [&[0x01], &decoded_bytes[..]].concat(); + encoder.bytes(&data).unwrap(); + } + } else { + encoder.str(name).unwrap(); + } +} + +#[cfg(test)] +#[allow(unused)] +mod tests { + + use crate::{c509_enum::PubKeyAlgoRegistry, cbor::cbor_encode_integer_as_bytestring}; + + use super::*; + + #[test] + fn test_generate_c509() { + let version = 1; + let serial_number = 128269; + + let not_before = 1672531200; + let not_after = 1767225600; + // Create a buffer to hold the CBOR data + let mut buffer: Vec = Vec::new(); + + // Create a new encoder, passing the buffer by mutable reference + let mut encoder: Encoder<&mut Vec> = Encoder::new(&mut buffer); + encoder.u8(version).unwrap(); + cbor_encode_integer_as_bytestring(serial_number, &mut encoder); + type_name( + vec![AttributeRegistry { + name: "CN".to_string(), + value: "RFC test CA".to_string(), + }], + &mut encoder, + ); + encoder.u32(not_before).unwrap(); + encoder.u32(not_after).unwrap(); + type_name( + vec![AttributeRegistry { + name: "CN".to_string(), + value: "01-23-45-FF-FE-67-89-AB".to_string(), + }], + &mut encoder, + ); + encoder.u8(PubKeyAlgoRegistry::Secp256r1 as u8).unwrap(); + println!("Encoded: {:?}", buffer); + } +}