From 9aeecc968efcaf1a53d3965547e22cec9c24f0f9 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 6 Nov 2020 17:12:42 +0800 Subject: [PATCH] cert: add SAN extension --- src/certificate.rs | 23 +++++++- src/main.rs | 13 +++-- src/oid.rs | 3 +- src/parse.rs | 132 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 5 deletions(-) diff --git a/src/certificate.rs b/src/certificate.rs index e7afd53..a333a82 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -106,7 +106,9 @@ pub enum ExtensionValue<'a> { }, // Permitted subtrees and excluded subtrees are not implemented - // SubjectAlternativeName, + SubjectAlternativeName { + general_names: Vec>, + }, BasicConstraints { is_ca: bool, @@ -141,6 +143,25 @@ pub enum ExtensionValue<'a> { Unrecognized, } +#[derive(Debug, Clone)] +pub enum GeneralName<'a> { + OtherName { + type_id: &'a [u8], + value: &'a [u8], + }, + RFC822Name(&'a [u8]), + DNSName(&'a [u8]), + X400Address(&'a [u8]), + DirectoryName(&'a [u8]), + EDIPartyName{ + name_assigner: &'a [u8], + party_name: &'a [u8], + }, + URI(&'a [u8]), + IPAddress(&'a [u8]), + RegisteredID(&'a [u8]), +} + #[derive(Debug, Clone)] pub struct PolicyInformation<'a> { pub id: &'a [u8], diff --git a/src/main.rs b/src/main.rs index 25f3d07..35ba4a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,7 +78,7 @@ fn main() { // tls_socket.tls_connect(&mut sockets).unwrap(); simple_logger::SimpleLogger::new().init().unwrap(); - let (_, certificate) = parse_asn1_der_certificate(&CA_SIGNED_CERT).unwrap(); + let (_, certificate) = parse_asn1_der_certificate(&SELF_SIGNED_WITH_SAN).unwrap(); println!("Certificate print: {:?}", certificate); let modulus = [ @@ -96,8 +96,10 @@ fn main() { cert_rsa_public_key: rsa_public_key }; - certificate.validate_signature_with_trusted(&ca_public_key).unwrap(); - println!("Certificate should be trusted"); + // certificate.validate_signature_with_trusted(&ca_public_key).unwrap(); + // println!("Certificate should be trusted"); + + certificate.validate_self_signed_signature().unwrap(); } @@ -117,3 +119,8 @@ const CA_SIGNED_CERT: [u8; 0x0356] = hex_literal::hex!( "308203523082023a02146048517ee55aabd1e8f2bd7db1d91e679708e644300d06092a864886f70d01010b05003067310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643120301e06035504030c176578616d706c65732e63612e756c666865696d2e6e6574301e170d3230313130363034323035305a170d3230313230363034323035305a3064310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464311d301b06035504030c146578616d706c65732e756c666865696d2e6e657430820122300d06092a864886f70d01010105000382010f003082010a0282010100b2940671bfe7ace7416ba9d34018c229588e9d4eed8bd6623e44ab1239e8f1f0de9050b2f485a98e63f5b483330fb0b5abaeb33d11889033b0b684bf34696d28206bb361782c4b106a8d47874cbbdf971b5ab887bca508bccf250a1a811cee078464638e441941347d4c8885ac9b59d9fc9636276912b04d9e3ab29bd8ad319572ae54f0b6145c4d675a78607dcc4793a4d432f1c2a41ea29dd4f7262b6fe472dfaea51aca992b4624e73fa9901fa364fc5b721052ef3187e659d58d2706770d365380a7ebab6caac5b23271c01531fdf95368ee48af5383035f249be7c18f50ce9e52877558efe4b2e29f61328396e2a3b5e71309ad13d93d6ba3d5c3eb2b650203010001300d06092a864886f70d01010b0500038201010063c9ab0f5d2e164513e8e74b656ae4f48dd004c3ead9f1026b7741cbf02bb0efcf19e0fbf8a788dae059a2393167f016bafc0e3efd5c5b4c43079b6506eb67f17f44f9591503c7d1fdb77bf631894817393ea82610ad5106d23ec6bf1a6d96d749f05c0136cd71256617a51fe862529aee4a37d5f456dc7da8b220ff10ede4e87bc63e4589b3f81133a7f82ab900419e8a2d802d59e99cfbbd268702efd17616168b45b5211da0e644c29dcb92dbbf32b43586bbab05deb0261771605c52836363bd28ff9853d44436349f5ba11f2640bc9c42688e0d5eb6cac9f3f5e5f98652fa4f4ba52604371ec45f09d678e31d463285a4b3734f587f35a339920544f476" ); + +const SELF_SIGNED_WITH_SAN: [u8; 0x03E8] = + hex_literal::hex!( + "308203e4308202cca00302010202145e88e088cb38c6b2b61eb94eae6d2c2429382148300d06092a864886f70d01010b05003070310b3009060355040613025553310b300906035504080c0256413111300f06035504070c08536f6d654369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d301e170d3230313130363039303230345a170d3232313130363039303230345a3070310b3009060355040613025553310b300906035504080c0256413111300f06035504070c08536f6d654369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e1d7d8ddb3ec0e334e7d8e5aff8272384e755488e887b1ac9c520a95fbfb75aff84e5d5bab76fe397d0bd73e9bf5358824ecf26c2040f4f04ccff04e60e5469294fb2b18fa8533d8826d1cac977d37f0673fb102fa583e78cb965271f66160b86889acf7add28804eeaeff385084961c3e60dda38f83dd7f37eead28dfedd715fbc57512e9f7c0b297eea2ad752483bc09d9dfd7d8466a5de3f875bb5b9a86b6f0cc4853bab323c0e31369d36f4e230d498198d800f2fefdc70525e5e8785262d90e67c442dc1c92ea22239dbdb0f5915b0e9ac05fd23a755e92030af606b0bf738bd5d9e7416c278785066057a3a828030229a5e6ec8f1a561fa6d4b03473650203010001a3763074300b0603551d0f04040302043030130603551d25040c300a06082b0601050507030130500603551d1104493047820f7777772e636f6d70616e792e6e6574820b636f6d70616e792e636f6d820b636f6d70616e792e6e6574810b626f6240636f6d70616e79810d616c69636540636f6d70616e79300d06092a864886f70d01010b050003820101008ee6ca325376df41ca6858c5ab6bc2d82d20b8d20bd7a6a007a62047f67e4c5988dc60e6e313a3d4456c87ac9b7d064af61012d9e5e630839471255166fb3f2de460dbf2ff88f2b26d385e605c7f47f8bd0a34e1ab4726e82642c5eba7e2b49a05c829704618362341ce02dca477b76e6d8919a4ec568aafa581a710220c7101d686f36f381b1851c06ed9f2c3de26befb95ea653dc7429c0abe8dd66b2328d7b41222b06237840835a15073d3f314c0d84b812fe7829e42da8174dac600845bf367685c5607196c2bcc06aad54eec531d93cfb6fea7995d65272cab575faaac7c9029a312e664ef0d3880fa4e0acaeee4c144ffb994a64118713def59360f6c" + ); diff --git a/src/oid.rs b/src/oid.rs index 485246a..96b11e4 100644 --- a/src/oid.rs +++ b/src/oid.rs @@ -72,6 +72,7 @@ pub const CERT_POLICIES: &'static [u8] = &[85, 29, 32]; pub const CERT_BASIC_CONSTRAINTS: &'static [u8] = &[85, 29, 19]; // 2.5.29.19 pub const CERT_EXT_KEY_USAGE: &'static [u8] = &[85, 29, 37]; // 2.5.29.37 pub const CERT_INHIBIT_ANY_POLICY: &'static [u8] = &[85, 29, 54]; // 2.5.29.54 +pub const CERT_SUBJECTALTNAME: &'static [u8] = &[85, 29, 17]; // 2.5.29.17 // Extended Key Extensions pub const ANY_EXTENDED_KEY_USAGE: &'static [u8] = &[85, 29, 37, 0]; // 2.5.29.37.0 pub const ID_KP_SERVER_AUTH: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 1]; // 1.3.6.1.5.5.7.3.1 @@ -79,4 +80,4 @@ pub const ID_KP_CLIENT_AUTH: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, pub const ID_KP_CODE_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 3]; // 1.3.6.1.5.5.7.3.3 pub const ID_KP_EMAIL_PROTECTION: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 4]; // 1.3.6.1.5.5.7.3.4 pub const ID_KP_TIME_STAMPING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 8]; // 1.3.6.1.5.5.7.3.8 -pub const ID_KP_OCSP_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 9]; \ No newline at end of file +pub const ID_KP_OCSP_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 9]; \ No newline at end of file diff --git a/src/parse.rs b/src/parse.rs index 6a03a1d..8aea2ae 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -26,6 +26,7 @@ use crate::certificate::{ TBSCertificate as Asn1DerTBSCertificate, Name as Asn1DerName, AttributeTypeAndValue as Asn1DerAttribute, + GeneralName as Asn1DerGeneralName }; use crate::oid; @@ -997,6 +998,12 @@ pub fn parse_asn1_der_extension(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension )(rem_ext_data)?; extension_value }, + oid::CERT_SUBJECTALTNAME => { + let (_, extension_value) = complete( + parse_asn1_der_subject_alternative_name + )(rem_ext_data)?; + extension_value + } // TODO: Parse extension value for recognized extensions _ => Asn1DerExtensionValue::Unrecognized }; @@ -1035,6 +1042,131 @@ pub fn parse_asn1_der_key_usage(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtension )) } +// Parser for Subject Alternative Name +pub fn parse_asn1_der_subject_alternative_name(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { + let (_, mut names) = complete( + parse_asn1_der_sequence + )(bytes)?; + + let mut general_names: Vec = Vec::new(); + + while names.len() != 0 { + let (rest, (tag_val, _, name_value)) = parse_asn1_der_object(names)?; + match tag_val { + 0x80 => { + let (_, seq) = complete( + parse_asn1_der_sequence + )(name_value)?; + let (_, (oid, (inner_tag_val, _, value))) = complete( + tuple(( + parse_asn1_der_oid, + parse_asn1_der_object + )) + )(seq)?; + if inner_tag_val != 0x80 { + return Err(nom::Err::Error((bytes, ErrorKind::Verify))); + } + general_names.push( + Asn1DerGeneralName::OtherName { type_id: oid, value } + ); + }, + + 0x81 => { + general_names.push( + Asn1DerGeneralName::RFC822Name(name_value) + ); + }, + + 0x82 => { + general_names.push( + Asn1DerGeneralName::DNSName(name_value) + ); + }, + + 0x83 => { + general_names.push( + Asn1DerGeneralName::X400Address(name_value) + ); + }, + + 0x84 => { + general_names.push( + Asn1DerGeneralName::DirectoryName(name_value) + ); + }, + + 0x85 => { + let (_, seq) = complete( + parse_asn1_der_sequence + )(name_value)?; + let (_, ( + (name_assigner_tag_val, _, name_assigner), + party_name + )) = complete( + tuple(( + parse_asn1_der_object, + opt(parse_asn1_der_object) + )) + )(seq)?; + + let general_name = if party_name.is_none() && name_assigner_tag_val == 0x81 { + Asn1DerGeneralName::EDIPartyName { + name_assigner: &[], + party_name: name_assigner + } + } else if party_name.is_some() && name_assigner_tag_val == 0x80 { + if let Some((party_name_tag_val, _, party_name_value)) = party_name { + if party_name_tag_val == 0x81 { + Asn1DerGeneralName::EDIPartyName { + name_assigner, + party_name: party_name_value + } + } + else { + return Err(nom::Err::Error((bytes, ErrorKind::Verify))) + } + } else { + return Err(nom::Err::Error((bytes, ErrorKind::Verify))) + } + } else { + return Err(nom::Err::Error((bytes, ErrorKind::Verify))) + }; + + general_names.push( + general_name + ); + }, + + 0x86 => { + general_names.push( + Asn1DerGeneralName::URI(name_value) + ); + }, + + 0x87 => { + general_names.push( + Asn1DerGeneralName::IPAddress(name_value) + ); + }, + + 0x88 => { + general_names.push( + Asn1DerGeneralName::RegisteredID(name_value) + ); + }, + + _ => return Err(nom::Err::Error((bytes, ErrorKind::Verify))) + } + + names = rest; + } + + Ok(( + &[], + Asn1DerExtensionValue::SubjectAlternativeName { general_names } + )) +} + // Parser for CertificatePolicies Extension (sequence: 0x30) pub fn parse_asn1_der_certificate_policies(bytes: &[u8]) -> IResult<&[u8], Asn1DerExtensionValue> { let (rest, (tag_val, _, mut value)) = parse_asn1_der_object(bytes)?;