diff --git a/src/sample_cert2.pem b/src/sample_cert2.pem new file mode 100644 index 0000000..e1ab52a --- /dev/null +++ b/src/sample_cert2.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFDCCAXWgAwIBAgIUVHKGvbVXHNU88FnAjfsrXQdGDDMwCgYIKoZIzj0EAwIw +ITEfMB0GA1UEAwwWSGF0dGVyIFRlc3QgQ0EgRUMgUm9vdDAeFw0xOTA2MDcwMDAw +MDBaFw0zOTA2MDcwMDAwMDBaMCkxJzAlBgNVBAMMHkhhdHRlciBUZXN0IEludGVy +bWVkaWF0ZSBFQyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABPoKGtj8lGhDKb+l +p2LBIJ7C+UmxiLqg1F0n5w3041lLDq28688HLx6yzFuOnQo6UrbPvjvjifgqukq8 +upIBlfe6MYh5s8HJytwcutaWFrNMXtW+1jTTno9y0LM8cTPA2KNmMGQwDgYDVR0P +AQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHMGwhbHXYJn +eh0XlzTk9zSv+jhVMB8GA1UdIwQYMBaAFLshgqxgJX87yP8C1wIFFoSMtQZuMAoG +CCqGSM49BAMCA4GMADCBiAJCAcHOv7ETFyrc7dyVBllqC/CPX1SggQ92Zwn8Mzya +EW1Y55uJaR/02Q2F+4h4dUtBSLjchyYhWuWC7QD79hFZD6v6AkIAhWZcyoN2n2dG +LPoQrggrN+nP/zhUIlqrkwQLni8Jj2FRc1bUnzP4s5t9W6la7q3c6f8Lj+c5lRvW +DH970YSv9fA= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/x509.rs b/src/x509.rs index fe4b2da..2ea9f54 100644 --- a/src/x509.rs +++ b/src/x509.rs @@ -1,35 +1,107 @@ use x509_parser::parse_x509_certificate; use x509_parser::pem::parse_x509_pem; -use x509_parser::extensions::ParsedExtension; +use x509_parser::extensions::{ParsedExtension, GeneralName}; use x509_parser::der_parser::oid::Oid; use std::str::FromStr; +use rust_util::XResult; +use x509_parser::der_parser::der::parse_der_bitstring; +use x509_parser::der_parser::parse_der; lazy_static! { static ref OID_COMMON_NAME: Oid<'static> = Oid::from_str("2.5.4.3").unwrap(); static ref OID_RSA_WITH_SHA256: Oid<'static> = Oid::from_str("1.2.840.113549.1.1.11").unwrap(); + static ref OID_ECDSA_WITH_SHA256: Oid<'static> = Oid::from_str("1.2.840.10045.4.3.2").unwrap(); + + static ref OID_EC_PUBLIC_KEY: Oid<'static> = Oid::from_str("1.2.840.10045.2.1").unwrap(); + + static ref OID_SECP256R1: Oid<'static> = Oid::from_str("1.2.840.10045.3.1.7").unwrap(); + static ref OID_SECP384R1: Oid<'static> = Oid::from_str("1.3.132.0.34").unwrap(); + static ref OID_SECP521R1: Oid<'static> = Oid::from_str("1.3.132.0.35").unwrap(); +} + +#[derive(Debug, Clone, Copy)] +pub enum X509IssuerAlgo { + RsaWithSha256, + EcdsaWithSha256, +} + +pub enum X509EcPublicKeyAlgo { + Secp256r1, + Secp384r1, + Secp521r1, +} + +pub enum X509PublicKeyAlgo { + EcKey(X509EcPublicKeyAlgo) +} + +#[derive(Debug, Clone)] +pub struct X509Certificate { + pub issuer_algo: X509IssuerAlgo, + pub common_name: String, + pub alt_names: Vec, +} + +pub fn parse_x500(pem_id: &str, pem: &str) -> XResult { + let (_, der) = opt_result!(parse_x509_pem(pem.as_bytes()), "Parse pem: {} to der failed: {}", pem_id); + let (_, cert) = opt_result!(parse_x509_certificate(der.contents.as_slice()), "Parse cert: {} failed: {}", pem_id); + + let mut common_name = None; + cert.subject().iter_common_name().for_each(|c| { + if c.attr_type == *OID_COMMON_NAME { + common_name = c.attr_value.content.as_str().ok(); + } + }); + let cert_algorithm_oid = &cert.signature_algorithm.algorithm; + let issuer_algo = if cert_algorithm_oid == &*OID_RSA_WITH_SHA256 { + X509IssuerAlgo::RsaWithSha256 + } else if cert_algorithm_oid == &*OID_ECDSA_WITH_SHA256 { + X509IssuerAlgo::EcdsaWithSha256 + } else { + return simple_error!("Unknown x509 algorithm oid: {:?}", cert_algorithm_oid); + }; + let common_name = match common_name { + None => return simple_error!("Cannot find common name from: {}", pem_id), + Some(common_name) => common_name.to_string(), + }; + let mut alt_names = vec![]; + for (oid, ext) in cert.extensions().iter() { + if let ParsedExtension::SubjectAlternativeName(san) = ext.parsed_extension() { + for name in &san.general_names { + match name { + GeneralName::DNSName(dns_name) => alt_names.push(dns_name.to_string()), + n => warning!("Unknown general name from: {}, name: {:?}", pem_id, n), + } + } + } + } + let public_key_algo_oid = &cert.tbs_certificate.subject_pki.algorithm.algorithm; + let public_key_algo = if public_key_algo_oid == &*OID_EC_PUBLIC_KEY { + // TODO ... + let ec_public_key_algo_oid = cert.tbs_certificate.subject_pki.algorithm.parameters.unwrap().content.as_oid().unwrap(); + }; + + + Ok(X509Certificate { + issuer_algo, + common_name, + alt_names, + }) } #[test] fn test_x509() { - let pem = include_str!("sample_cert.pem"); + let pem = include_str!("sample_cert2.pem"); let (_, parsed_pem) = parse_x509_pem(pem.as_bytes()).unwrap(); let (_, cert) = parse_x509_certificate(parsed_pem.contents.as_slice()).unwrap(); - // println!("{:?}", cert); - // println!("{:#?}", cert.subject().iter_common_name()); - cert.subject().iter_common_name().for_each(|c| { - if c.attr_type == *OID_COMMON_NAME { - println!("{:?}", c.attr_value.content.as_str().unwrap()); - } - }); - // println!("{:#?}", cert.extensions()); - for (oid, ext) in cert.extensions().iter() { - match ext.parsed_extension() { - ParsedExtension::SubjectAlternativeName(san) => { - println!("{:?}", san); - } - _ => {} - } - } - println!("{:?}", cert.signature_algorithm.algorithm); - println!("{:?}", cert.signature_algorithm.algorithm.bytes()); + + println!("{:#?}", parse_x500("id", pem)); + + println!("{:?}", cert.tbs_certificate.signature); + println!("{:?}", cert.tbs_certificate.subject_pki); + println!("{:?}", cert.tbs_certificate.subject_pki.algorithm.algorithm); + println!("{:?}", cert.tbs_certificate.subject_pki.algorithm.parameters.unwrap().content.as_oid().unwrap()); + + let a = parse_der(cert.tbs_certificate.subject_pki.subject_public_key.data); + println!("{:?}", a); } \ No newline at end of file