Loading openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -794,6 +794,7 @@ extern "C" { pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; pub fn X509_get_ext_d2i(x: *mut X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); Loading openssl/src/x509/extension.rs +0 −38 Original line number Diff line number Diff line use std::fmt; use std::marker::PhantomData; use std::slice; use std::str; use ffi; use nid::Nid; Loading Loading @@ -223,37 +219,3 @@ impl fmt::Display for AltNameOption { }) } } pub struct GeneralName<'a> { name: *const ffi::GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralName<'a> { pub fn dns(&self) -> Option<&str> { unsafe { if (*self.name).type_ != ffi::GEN_DNS { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); Some(str::from_utf8_unchecked(slice)) } } pub fn ipadd(&self) -> Option<&[u8]> { unsafe { if (*self.name).type_ != ffi::GEN_IPADD { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } } openssl/src/x509/mod.rs +77 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use std::fmt; use std::str; use std::slice; use std::collections::HashMap; use std::marker::PhantomData; use asn1::Asn1Time; use bio::MemBio; Loading @@ -21,7 +22,7 @@ use crypto::rand::rand_bytes; use ffi; use ffi_extras; use ssl::error::{SslError, StreamError}; use nid; use nid::Nid; pub mod extension; Loading Loading @@ -464,6 +465,23 @@ impl<'ctx> X509<'ctx> { } } pub fn subject_alt_names<'a>(&'a self) -> Option<GeneralNames<'a>> { unsafe { let stack = ffi::X509_get_ext_d2i(self.handle, Nid::SubjectAltName as c_int, ptr::null_mut(), ptr::null_mut()); if stack.is_null() { return None; } Some(GeneralNames { stack: stack as *const _, m: PhantomData, }) } } pub fn public_key(&self) -> PKey { let pkey = unsafe { ffi::X509_get_pubkey(self.handle) }; assert!(!pkey.is_null()); Loading Loading @@ -544,7 +562,7 @@ pub struct X509NameEntry<'x> { } impl<'x> X509Name<'x> { pub fn text_by_nid(&self, nid: nid::Nid) -> Option<SslString> { pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> { unsafe { let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1); if loc == -1 { Loading Loading @@ -766,6 +784,63 @@ make_validation_error!(X509_V_OK, X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION, ); pub struct GeneralNames<'a> { stack: *const ffi::stack_st_GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralNames<'a> { pub fn len(&self) -> usize { unsafe { (*self.stack).stack.num as usize } } pub fn get(&self, idx: usize) -> GeneralName<'a> { unsafe { assert!(idx < self.len()); GeneralName { name: *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME, m: PhantomData, } } } } pub struct GeneralName<'a> { name: *const ffi::GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralName<'a> { pub fn dns(&self) -> Option<&str> { unsafe { if (*self.name).type_ != ffi::GEN_DNS { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); Some(str::from_utf8_unchecked(slice)) } } pub fn ipadd(&self) -> Option<&[u8]> { unsafe { if (*self.name).type_ != ffi::GEN_IPADD { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } } #[test] fn test_negative_serial() { Loading openssl/src/x509/tests.rs +12 −0 Original line number Diff line number Diff line Loading @@ -157,3 +157,15 @@ fn test_nid_uid_value() { }; assert_eq!(&cn as &str, "this is the userId"); } #[test] fn test_subject_alt_name() { let mut file = File::open("test/alt_name_cert.pem").unwrap(); let cert = X509::from_pem(&mut file).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(3, subject_alt_names.len()); assert_eq!(Some("foobar.com"), subject_alt_names.get(0).dns()); assert_eq!(subject_alt_names.get(1).ipadd(), Some(&[127, 0, 0, 1][..])); assert_eq!(subject_alt_names.get(2).ipadd(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..])); } openssl/test/alt_name_cert.pem 0 → 100644 +25 −0 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- MIIEOjCCAyKgAwIBAgIJAJz42fzGUJGeMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV BAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3IFlvcmsxFTATBgNVBAoM DEV4YW1wbGUsIExMQzEYMBYGA1UEAwwPRXhhbXBsZSBDb21wYW55MR8wHQYJKoZI hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE2MDQzMDA0MDg1NloXDTE3MDQz MDA0MDg1NlowfzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhO ZXcgWW9yazEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRgwFgYDVQQDDA9FeGFtcGxl IENvbXBhbnkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDggl2TbtO5Ewi/q8kV56xK6HBpwsj9 wBoqGi6hkKm/8lhLTkuUG6WbEUepi7n9d7tjI9hwYN7MKtppAnS+d+Zh6sKMgLJn hONkbQBJkYWwuIxRVXORCdyZDNzXP1rlb6ynmj6mItuPTRVNNMaZP+24fgXtwGk8 P2nqA1ONbmyaP27txV+Rd8fmQvW3vSmq7iDob661TOtLZRqqVRpnLDGpLXTCptYz dLN1nDWKjBUFpPGDxvfcSE3Yf9LaQM2uDHRygSgTFusbwarAGrAk8krsm/Tiaumx Ls74MY6OEoLnPbEi5epWLqPmoE1nxrvYLtaWh3TTET3H72yL0+1PZTkpAgMBAAGj gbgwgbUwHQYDVR0OBBYEFAIcHhTPUqVdK85u47vo8z0viJGPMB8GA1UdIwQYMBaA FAIcHhTPUqVdK85u47vo8z0viJGPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMC0G A1UdEQQmMCSCCmZvb2Jhci5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwLAYJ YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMA0GCSqG SIb3DQEBCwUAA4IBAQDeYsuJaxbnxR2wDRSbxMpPp2b6fHPxC1vArKTSrQ/X+5s7 YcQ29jkzD8FbET8iPsCOn/IECBiDKOpckkO6dBWM05ma9HHzWjQOJ7Lo6gEsvk4d +M/jJz5IaJ7hOxp1hGqwNQ+PJQOZMmlruNcOzPU36qaWJ03+NYOKar5VpIrRxCNc uehTArmJqDLQPfgETEhMYfpkqf3s/cGb1uyeCpzgIRPpf4Ki1Oys5cV/BqIn7n5g 7sUrhXboYL4+eYt5V4rcc4rLI5J5IP/a1Z+Z6UVH+Mbiyl0iD8aRr/bo9WvKih3C 2LBO0Apl0tkXUOMWp7G0UYHVEndwPjZnVoM42f11 -----END CERTIFICATE----- Loading
openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -794,6 +794,7 @@ extern "C" { pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; pub fn X509_get_ext_d2i(x: *mut X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); Loading
openssl/src/x509/extension.rs +0 −38 Original line number Diff line number Diff line use std::fmt; use std::marker::PhantomData; use std::slice; use std::str; use ffi; use nid::Nid; Loading Loading @@ -223,37 +219,3 @@ impl fmt::Display for AltNameOption { }) } } pub struct GeneralName<'a> { name: *const ffi::GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralName<'a> { pub fn dns(&self) -> Option<&str> { unsafe { if (*self.name).type_ != ffi::GEN_DNS { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); Some(str::from_utf8_unchecked(slice)) } } pub fn ipadd(&self) -> Option<&[u8]> { unsafe { if (*self.name).type_ != ffi::GEN_IPADD { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } }
openssl/src/x509/mod.rs +77 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use std::fmt; use std::str; use std::slice; use std::collections::HashMap; use std::marker::PhantomData; use asn1::Asn1Time; use bio::MemBio; Loading @@ -21,7 +22,7 @@ use crypto::rand::rand_bytes; use ffi; use ffi_extras; use ssl::error::{SslError, StreamError}; use nid; use nid::Nid; pub mod extension; Loading Loading @@ -464,6 +465,23 @@ impl<'ctx> X509<'ctx> { } } pub fn subject_alt_names<'a>(&'a self) -> Option<GeneralNames<'a>> { unsafe { let stack = ffi::X509_get_ext_d2i(self.handle, Nid::SubjectAltName as c_int, ptr::null_mut(), ptr::null_mut()); if stack.is_null() { return None; } Some(GeneralNames { stack: stack as *const _, m: PhantomData, }) } } pub fn public_key(&self) -> PKey { let pkey = unsafe { ffi::X509_get_pubkey(self.handle) }; assert!(!pkey.is_null()); Loading Loading @@ -544,7 +562,7 @@ pub struct X509NameEntry<'x> { } impl<'x> X509Name<'x> { pub fn text_by_nid(&self, nid: nid::Nid) -> Option<SslString> { pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> { unsafe { let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1); if loc == -1 { Loading Loading @@ -766,6 +784,63 @@ make_validation_error!(X509_V_OK, X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION, ); pub struct GeneralNames<'a> { stack: *const ffi::stack_st_GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralNames<'a> { pub fn len(&self) -> usize { unsafe { (*self.stack).stack.num as usize } } pub fn get(&self, idx: usize) -> GeneralName<'a> { unsafe { assert!(idx < self.len()); GeneralName { name: *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME, m: PhantomData, } } } } pub struct GeneralName<'a> { name: *const ffi::GENERAL_NAME, m: PhantomData<&'a ()>, } impl<'a> GeneralName<'a> { pub fn dns(&self) -> Option<&str> { unsafe { if (*self.name).type_ != ffi::GEN_DNS { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); Some(str::from_utf8_unchecked(slice)) } } pub fn ipadd(&self) -> Option<&[u8]> { unsafe { if (*self.name).type_ != ffi::GEN_IPADD { return None; } let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } } #[test] fn test_negative_serial() { Loading
openssl/src/x509/tests.rs +12 −0 Original line number Diff line number Diff line Loading @@ -157,3 +157,15 @@ fn test_nid_uid_value() { }; assert_eq!(&cn as &str, "this is the userId"); } #[test] fn test_subject_alt_name() { let mut file = File::open("test/alt_name_cert.pem").unwrap(); let cert = X509::from_pem(&mut file).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(3, subject_alt_names.len()); assert_eq!(Some("foobar.com"), subject_alt_names.get(0).dns()); assert_eq!(subject_alt_names.get(1).ipadd(), Some(&[127, 0, 0, 1][..])); assert_eq!(subject_alt_names.get(2).ipadd(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..])); }
openssl/test/alt_name_cert.pem 0 → 100644 +25 −0 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- MIIEOjCCAyKgAwIBAgIJAJz42fzGUJGeMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV BAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3IFlvcmsxFTATBgNVBAoM DEV4YW1wbGUsIExMQzEYMBYGA1UEAwwPRXhhbXBsZSBDb21wYW55MR8wHQYJKoZI hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE2MDQzMDA0MDg1NloXDTE3MDQz MDA0MDg1NlowfzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhO ZXcgWW9yazEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRgwFgYDVQQDDA9FeGFtcGxl IENvbXBhbnkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDggl2TbtO5Ewi/q8kV56xK6HBpwsj9 wBoqGi6hkKm/8lhLTkuUG6WbEUepi7n9d7tjI9hwYN7MKtppAnS+d+Zh6sKMgLJn hONkbQBJkYWwuIxRVXORCdyZDNzXP1rlb6ynmj6mItuPTRVNNMaZP+24fgXtwGk8 P2nqA1ONbmyaP27txV+Rd8fmQvW3vSmq7iDob661TOtLZRqqVRpnLDGpLXTCptYz dLN1nDWKjBUFpPGDxvfcSE3Yf9LaQM2uDHRygSgTFusbwarAGrAk8krsm/Tiaumx Ls74MY6OEoLnPbEi5epWLqPmoE1nxrvYLtaWh3TTET3H72yL0+1PZTkpAgMBAAGj gbgwgbUwHQYDVR0OBBYEFAIcHhTPUqVdK85u47vo8z0viJGPMB8GA1UdIwQYMBaA FAIcHhTPUqVdK85u47vo8z0viJGPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMC0G A1UdEQQmMCSCCmZvb2Jhci5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwLAYJ YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMA0GCSqG SIb3DQEBCwUAA4IBAQDeYsuJaxbnxR2wDRSbxMpPp2b6fHPxC1vArKTSrQ/X+5s7 YcQ29jkzD8FbET8iPsCOn/IECBiDKOpckkO6dBWM05ma9HHzWjQOJ7Lo6gEsvk4d +M/jJz5IaJ7hOxp1hGqwNQ+PJQOZMmlruNcOzPU36qaWJ03+NYOKar5VpIrRxCNc uehTArmJqDLQPfgETEhMYfpkqf3s/cGb1uyeCpzgIRPpf4Ki1Oys5cV/BqIn7n5g 7sUrhXboYL4+eYt5V4rcc4rLI5J5IP/a1Z+Z6UVH+Mbiyl0iD8aRr/bo9WvKih3C 2LBO0Apl0tkXUOMWp7G0UYHVEndwPjZnVoM42f11 -----END CERTIFICATE-----