Loading openssl-sys/src/lib.rs +4 −1 Original line number Diff line number Diff line Loading @@ -1662,6 +1662,9 @@ extern { pub fn X509_NAME_add_entry_by_txt(x: *mut X509_NAME, field: *const c_char, ty: c_int, bytes: *const c_uchar, len: c_int, loc: c_int, set: c_int) -> c_int; pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) -> c_int; pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); Loading openssl/src/asn1.rs +28 −0 Original line number Diff line number Diff line use libc::c_long; use std::{ptr, fmt}; use std::slice; use ffi; use {cvt, cvt_p}; use bio::MemBio; use crypto::CryptoString; use error::ErrorStack; use types::{OpenSslType, Ref}; Loading Loading @@ -35,3 +37,29 @@ impl Asn1Time { Asn1Time::from_period(days as c_long * 60 * 60 * 24) } } type_!(Asn1String, ffi::ASN1_STRING, ffi::ASN1_STRING_free); impl Ref<Asn1String> { pub fn as_utf8(&self) -> Result<CryptoString, ErrorStack> { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); if len < 0 { return Err(ErrorStack::get()); } Ok(CryptoString::from_raw_parts(ptr, len as usize)) } } pub fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(ffi::ASN1_STRING_data(self.as_ptr()), self.len()) } } pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } } } openssl/src/ssl/connector.rs +7 −1 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { #[cfg(not(any(ossl102, ossl110)))] mod verify { use std::net::IpAddr; use std::str; use nid; use x509::{X509StoreContext, X509, GeneralNames, X509Name}; Loading Loading @@ -305,7 +306,12 @@ mod verify { } fn verify_subject_name(domain: &str, subject_name: &Ref<X509Name>) -> bool { if let Some(pattern) = subject_name.text_by_nid(nid::COMMONNAME) { if let Some(pattern) = subject_name.entries_by_nid(nid::COMMONNAME).next() { let pattern = match str::from_utf8(pattern.data().as_slice()) { Ok(pattern) => pattern, Err(_) => return false, }; // Unlike with SANs, IP addresses in the subject name don't have a // different encoding. We need to pass this down to matches_dns to // disallow wildcard matches with bogus patterns like *.0.0.1 Loading openssl/src/x509/mod.rs +36 −21 Original line number Diff line number Diff line Loading @@ -12,9 +12,8 @@ use std::slice; use std::str; use {cvt, cvt_p}; use asn1::Asn1Time; use asn1::{Asn1String, Asn1Time}; use bio::{MemBio, MemBioSlice}; use crypto::CryptoString; use hash::MessageDigest; use pkey::PKey; use rand::rand_bytes; Loading Loading @@ -473,33 +472,49 @@ impl Borrow<Ref<X509>> for X509 { type_!(X509Name, ffi::X509_NAME, ffi::X509_NAME_free); impl Ref<X509Name> { pub fn text_by_nid(&self, nid: Nid) -> Option<CryptoString> { unsafe { let loc = ffi::X509_NAME_get_index_by_NID(self.as_ptr(), nid.as_raw(), -1); if loc == -1 { return None; pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { X509NameEntries { name: self, nid: nid, loc: -1, } } } let ne = ffi::X509_NAME_get_entry(self.as_ptr(), loc); if ne.is_null() { return None; pub struct X509NameEntries<'a> { name: &'a Ref<X509Name>, nid: Nid, loc: c_int, } let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne); if asn1_str.is_null() { impl<'a> Iterator for X509NameEntries<'a> { type Item = &'a Ref<X509NameEntry>; fn next(&mut self) -> Option<&'a Ref<X509NameEntry>> { unsafe { self.loc = ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), self.nid.as_raw(), self.loc); if self.loc == -1 { return None; } let mut str_from_asn1: *mut u8 = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str); let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); assert!(!entry.is_null()); if len < 0 { return None; Some(Ref::from_ptr(entry)) } } } assert!(!str_from_asn1.is_null()); type_!(X509NameEntry, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free); Some(CryptoString::from_raw_parts(str_from_asn1, len as usize)) impl Ref<X509NameEntry> { pub fn data(&self) -> &Ref<Asn1String> { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); Ref::from_ptr(data) } } } Loading openssl/src/x509/tests.rs +16 −32 Original line number Diff line number Diff line Loading @@ -113,58 +113,42 @@ fn test_save_der() { #[test] fn test_subject_read_cn() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::COMMONNAME) { Some(x) => x, None => panic!("Failed to read CN from cert"), }; assert_eq!(&cn as &str, "foobar.com") let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"foobar.com") } #[test] fn test_nid_values() { let cert = include_bytes!("../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::COMMONNAME) { Some(x) => x, None => panic!("Failed to read CN from cert"), }; assert_eq!(&cn as &str, "example.com"); let email = match subject.text_by_nid(nid::PKCS9_EMAILADDRESS) { Some(x) => x, None => panic!("Failed to read subject email address from cert"), }; assert_eq!(&email as &str, "test@example.com"); let friendly = match subject.text_by_nid(nid::FRIENDLYNAME) { Some(x) => x, None => panic!("Failed to read subject friendly name from cert"), }; assert_eq!(&friendly as &str, "Example"); let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"example.com"); let email = subject.entries_by_nid(nid::PKCS9_EMAILADDRESS).next().unwrap(); assert_eq!(email.data().as_slice(), b"test@example.com"); let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap(); assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example"); } #[test] fn test_nid_uid_value() { let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::USERID) { Some(x) => x, None => panic!("Failed to read UID from cert"), }; assert_eq!(&cn as &str, "this is the userId"); let cn = subject.entries_by_nid(nid::USERID).next().unwrap(); assert_eq!(cn.data().as_slice(), b"this is the userId"); } #[test] fn test_subject_alt_name() { let cert = include_bytes!("../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(3, subject_alt_names.len()); Loading Loading
openssl-sys/src/lib.rs +4 −1 Original line number Diff line number Diff line Loading @@ -1662,6 +1662,9 @@ extern { pub fn X509_NAME_add_entry_by_txt(x: *mut X509_NAME, field: *const c_char, ty: c_int, bytes: *const c_uchar, len: c_int, loc: c_int, set: c_int) -> c_int; pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) -> c_int; pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); Loading
openssl/src/asn1.rs +28 −0 Original line number Diff line number Diff line use libc::c_long; use std::{ptr, fmt}; use std::slice; use ffi; use {cvt, cvt_p}; use bio::MemBio; use crypto::CryptoString; use error::ErrorStack; use types::{OpenSslType, Ref}; Loading Loading @@ -35,3 +37,29 @@ impl Asn1Time { Asn1Time::from_period(days as c_long * 60 * 60 * 24) } } type_!(Asn1String, ffi::ASN1_STRING, ffi::ASN1_STRING_free); impl Ref<Asn1String> { pub fn as_utf8(&self) -> Result<CryptoString, ErrorStack> { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); if len < 0 { return Err(ErrorStack::get()); } Ok(CryptoString::from_raw_parts(ptr, len as usize)) } } pub fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(ffi::ASN1_STRING_data(self.as_ptr()), self.len()) } } pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } } }
openssl/src/ssl/connector.rs +7 −1 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { #[cfg(not(any(ossl102, ossl110)))] mod verify { use std::net::IpAddr; use std::str; use nid; use x509::{X509StoreContext, X509, GeneralNames, X509Name}; Loading Loading @@ -305,7 +306,12 @@ mod verify { } fn verify_subject_name(domain: &str, subject_name: &Ref<X509Name>) -> bool { if let Some(pattern) = subject_name.text_by_nid(nid::COMMONNAME) { if let Some(pattern) = subject_name.entries_by_nid(nid::COMMONNAME).next() { let pattern = match str::from_utf8(pattern.data().as_slice()) { Ok(pattern) => pattern, Err(_) => return false, }; // Unlike with SANs, IP addresses in the subject name don't have a // different encoding. We need to pass this down to matches_dns to // disallow wildcard matches with bogus patterns like *.0.0.1 Loading
openssl/src/x509/mod.rs +36 −21 Original line number Diff line number Diff line Loading @@ -12,9 +12,8 @@ use std::slice; use std::str; use {cvt, cvt_p}; use asn1::Asn1Time; use asn1::{Asn1String, Asn1Time}; use bio::{MemBio, MemBioSlice}; use crypto::CryptoString; use hash::MessageDigest; use pkey::PKey; use rand::rand_bytes; Loading Loading @@ -473,33 +472,49 @@ impl Borrow<Ref<X509>> for X509 { type_!(X509Name, ffi::X509_NAME, ffi::X509_NAME_free); impl Ref<X509Name> { pub fn text_by_nid(&self, nid: Nid) -> Option<CryptoString> { unsafe { let loc = ffi::X509_NAME_get_index_by_NID(self.as_ptr(), nid.as_raw(), -1); if loc == -1 { return None; pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { X509NameEntries { name: self, nid: nid, loc: -1, } } } let ne = ffi::X509_NAME_get_entry(self.as_ptr(), loc); if ne.is_null() { return None; pub struct X509NameEntries<'a> { name: &'a Ref<X509Name>, nid: Nid, loc: c_int, } let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne); if asn1_str.is_null() { impl<'a> Iterator for X509NameEntries<'a> { type Item = &'a Ref<X509NameEntry>; fn next(&mut self) -> Option<&'a Ref<X509NameEntry>> { unsafe { self.loc = ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), self.nid.as_raw(), self.loc); if self.loc == -1 { return None; } let mut str_from_asn1: *mut u8 = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str); let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); assert!(!entry.is_null()); if len < 0 { return None; Some(Ref::from_ptr(entry)) } } } assert!(!str_from_asn1.is_null()); type_!(X509NameEntry, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free); Some(CryptoString::from_raw_parts(str_from_asn1, len as usize)) impl Ref<X509NameEntry> { pub fn data(&self) -> &Ref<Asn1String> { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); Ref::from_ptr(data) } } } Loading
openssl/src/x509/tests.rs +16 −32 Original line number Diff line number Diff line Loading @@ -113,58 +113,42 @@ fn test_save_der() { #[test] fn test_subject_read_cn() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::COMMONNAME) { Some(x) => x, None => panic!("Failed to read CN from cert"), }; assert_eq!(&cn as &str, "foobar.com") let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"foobar.com") } #[test] fn test_nid_values() { let cert = include_bytes!("../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::COMMONNAME) { Some(x) => x, None => panic!("Failed to read CN from cert"), }; assert_eq!(&cn as &str, "example.com"); let email = match subject.text_by_nid(nid::PKCS9_EMAILADDRESS) { Some(x) => x, None => panic!("Failed to read subject email address from cert"), }; assert_eq!(&email as &str, "test@example.com"); let friendly = match subject.text_by_nid(nid::FRIENDLYNAME) { Some(x) => x, None => panic!("Failed to read subject friendly name from cert"), }; assert_eq!(&friendly as &str, "Example"); let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"example.com"); let email = subject.entries_by_nid(nid::PKCS9_EMAILADDRESS).next().unwrap(); assert_eq!(email.data().as_slice(), b"test@example.com"); let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap(); assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example"); } #[test] fn test_nid_uid_value() { let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = match subject.text_by_nid(nid::USERID) { Some(x) => x, None => panic!("Failed to read UID from cert"), }; assert_eq!(&cn as &str, "this is the userId"); let cn = subject.entries_by_nid(nid::USERID).next().unwrap(); assert_eq!(cn.data().as_slice(), b"this is the userId"); } #[test] fn test_subject_alt_name() { let cert = include_bytes!("../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(3, subject_alt_names.len()); Loading