Clean up x509 name entries
This commit is contained in:
parent
50d8cca640
commit
dc4098bdd8
|
|
@ -1660,8 +1660,11 @@ extern {
|
|||
|
||||
pub fn X509_NAME_free(x: *mut X509_NAME);
|
||||
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_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);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
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};
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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> {
|
||||
pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> {
|
||||
X509NameEntries {
|
||||
name: self,
|
||||
nid: nid,
|
||||
loc: -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct X509NameEntries<'a> {
|
||||
name: &'a Ref<X509Name>,
|
||||
nid: Nid,
|
||||
loc: c_int,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for X509NameEntries<'a> {
|
||||
type Item = &'a Ref<X509NameEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Ref<X509NameEntry>> {
|
||||
unsafe {
|
||||
let loc = ffi::X509_NAME_get_index_by_NID(self.as_ptr(), nid.as_raw(), -1);
|
||||
if loc == -1 {
|
||||
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 ne = ffi::X509_NAME_get_entry(self.as_ptr(), loc);
|
||||
if ne.is_null() {
|
||||
return None;
|
||||
}
|
||||
let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
|
||||
assert!(!entry.is_null());
|
||||
|
||||
let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne);
|
||||
if asn1_str.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(Ref::from_ptr(entry))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut str_from_asn1: *mut u8 = ptr::null_mut();
|
||||
let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str);
|
||||
type_!(X509NameEntry, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free);
|
||||
|
||||
if len < 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
assert!(!str_from_asn1.is_null());
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!(cn.data().as_slice(), b"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 email = subject.entries_by_nid(nid::PKCS9_EMAILADDRESS).next().unwrap();
|
||||
assert_eq!(email.data().as_slice(), b"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 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…
Reference in New Issue