Add accessors for x509 subject alt names
This commit is contained in:
parent
caf9272c85
commit
32722e1850
|
|
@ -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_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_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_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);
|
pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::slice;
|
|
||||||
use std::str;
|
|
||||||
use ffi;
|
|
||||||
|
|
||||||
use nid::Nid;
|
use nid::Nid;
|
||||||
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use asn1::Asn1Time;
|
use asn1::Asn1Time;
|
||||||
use bio::MemBio;
|
use bio::MemBio;
|
||||||
|
|
@ -21,7 +22,7 @@ use crypto::rand::rand_bytes;
|
||||||
use ffi;
|
use ffi;
|
||||||
use ffi_extras;
|
use ffi_extras;
|
||||||
use ssl::error::{SslError, StreamError};
|
use ssl::error::{SslError, StreamError};
|
||||||
use nid;
|
use nid::Nid;
|
||||||
|
|
||||||
pub mod extension;
|
pub mod extension;
|
||||||
|
|
||||||
|
|
@ -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 {
|
pub fn public_key(&self) -> PKey {
|
||||||
let pkey = unsafe { ffi::X509_get_pubkey(self.handle) };
|
let pkey = unsafe { ffi::X509_get_pubkey(self.handle) };
|
||||||
assert!(!pkey.is_null());
|
assert!(!pkey.is_null());
|
||||||
|
|
@ -544,7 +562,7 @@ pub struct X509NameEntry<'x> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'x> X509Name<'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 {
|
unsafe {
|
||||||
let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1);
|
let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1);
|
||||||
if loc == -1 {
|
if loc == -1 {
|
||||||
|
|
@ -766,6 +784,63 @@ make_validation_error!(X509_V_OK,
|
||||||
X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION,
|
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]
|
#[test]
|
||||||
fn test_negative_serial() {
|
fn test_negative_serial() {
|
||||||
|
|
|
||||||
|
|
@ -157,3 +157,15 @@ fn test_nid_uid_value() {
|
||||||
};
|
};
|
||||||
assert_eq!(&cn as &str, "this is the userId");
|
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"[..]));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
-----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…
Reference in New Issue