Replace GeneralNames by the new Stack API
This commit is contained in:
parent
3bdefa987a
commit
36bf0bb387
|
|
@ -256,7 +256,8 @@ mod verify {
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use nid;
|
use nid;
|
||||||
use x509::{X509StoreContext, X509, GeneralNames, X509Name};
|
use x509::{X509StoreContext, X509, X509Name, GeneralName};
|
||||||
|
use stack::Stack;
|
||||||
use types::Ref;
|
use types::Ref;
|
||||||
|
|
||||||
pub fn verify_callback(domain: &str,
|
pub fn verify_callback(domain: &str,
|
||||||
|
|
@ -275,15 +276,16 @@ mod verify {
|
||||||
|
|
||||||
fn verify_hostname(domain: &str, cert: &Ref<X509>) -> bool {
|
fn verify_hostname(domain: &str, cert: &Ref<X509>) -> bool {
|
||||||
match cert.subject_alt_names() {
|
match cert.subject_alt_names() {
|
||||||
Some(names) => verify_subject_alt_names(domain, &names),
|
Some(names) => verify_subject_alt_names(domain, names),
|
||||||
None => verify_subject_name(domain, &cert.subject_name()),
|
None => verify_subject_name(domain, &cert.subject_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_subject_alt_names(domain: &str, names: &GeneralNames) -> bool {
|
fn verify_subject_alt_names(domain: &str,
|
||||||
|
names: Stack<GeneralName>) -> bool {
|
||||||
let ip = domain.parse();
|
let ip = domain.parse();
|
||||||
|
|
||||||
for name in names {
|
for name in &names {
|
||||||
match ip {
|
match ip {
|
||||||
Ok(ip) => {
|
Ok(ip) => {
|
||||||
if let Some(actual) = name.ipaddress() {
|
if let Some(actual) = name.ipaddress() {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
use libc::{c_char, c_int, c_long, c_ulong, c_void};
|
use libc::{c_char, c_int, c_long, c_ulong};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
@ -21,6 +20,7 @@ use error::ErrorStack;
|
||||||
use ffi;
|
use ffi;
|
||||||
use nid::Nid;
|
use nid::Nid;
|
||||||
use types::{OpenSslType, Ref};
|
use types::{OpenSslType, Ref};
|
||||||
|
use stack::{Stack, Stackable};
|
||||||
|
|
||||||
#[cfg(ossl10x)]
|
#[cfg(ossl10x)]
|
||||||
use ffi::{X509_set_notBefore, X509_set_notAfter, ASN1_STRING_data};
|
use ffi::{X509_set_notBefore, X509_set_notAfter, ASN1_STRING_data};
|
||||||
|
|
@ -346,7 +346,7 @@ impl Ref<X509> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this certificate's SAN entries, if they exist.
|
/// Returns this certificate's SAN entries, if they exist.
|
||||||
pub fn subject_alt_names(&self) -> Option<GeneralNames> {
|
pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let stack = ffi::X509_get_ext_d2i(self.as_ptr(),
|
let stack = ffi::X509_get_ext_d2i(self.as_ptr(),
|
||||||
ffi::NID_subject_alt_name,
|
ffi::NID_subject_alt_name,
|
||||||
|
|
@ -356,7 +356,7 @@ impl Ref<X509> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(GeneralNames { stack: stack as *mut _ })
|
Some(Stack::from_ptr(stack as *mut _))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -678,135 +678,18 @@ impl X509VerifyError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of OpenSSL `GENERAL_NAME`s.
|
type_!(GeneralName, ffi::GENERAL_NAME, ffi::GENERAL_NAME_free);
|
||||||
pub struct GeneralNames {
|
|
||||||
stack: *mut ffi::stack_st_GENERAL_NAME,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for GeneralNames {
|
impl Ref<GeneralName> {
|
||||||
#[cfg(ossl10x)]
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
// This transmute is dubious but it's what openssl itself does...
|
|
||||||
let free: unsafe extern "C" fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free;
|
|
||||||
let free: unsafe extern "C" fn(*mut c_void) = mem::transmute(free);
|
|
||||||
ffi::sk_pop_free(&mut (*self.stack).stack, Some(free));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(ossl110)]
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
// This transmute is dubious but it's what openssl itself does...
|
|
||||||
let free: unsafe extern "C" fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free;
|
|
||||||
let free: unsafe extern "C" fn(*mut c_void) = mem::transmute(free);
|
|
||||||
ffi::OPENSSL_sk_pop_free(self.stack as *mut _, Some(free));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GeneralNames {
|
|
||||||
/// Returns the number of `GeneralName`s in this structure.
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self._len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(ossl10x)]
|
|
||||||
fn _len(&self) -> usize {
|
|
||||||
unsafe { (*self.stack).stack.num as usize }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(ossl110)]
|
|
||||||
fn _len(&self) -> usize {
|
|
||||||
unsafe { ffi::OPENSSL_sk_num(self.stack as *const _) as usize }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the specified `GeneralName`.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if `idx` is not less than `len()`.
|
|
||||||
pub fn get<'a>(&'a self, idx: usize) -> GeneralName<'a> {
|
|
||||||
unsafe {
|
|
||||||
assert!(idx < self.len());
|
|
||||||
GeneralName {
|
|
||||||
name: self._get(idx),
|
|
||||||
m: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(ossl10x)]
|
|
||||||
unsafe fn _get(&self, idx: usize) -> *const ffi::GENERAL_NAME {
|
|
||||||
*(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(ossl110)]
|
|
||||||
unsafe fn _get(&self, idx: usize) -> *const ffi::GENERAL_NAME {
|
|
||||||
ffi::OPENSSL_sk_value(self.stack as *const _, idx as c_int) as *mut _
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the `GeneralName`s in this structure.
|
|
||||||
pub fn iter(&self) -> GeneralNamesIter {
|
|
||||||
GeneralNamesIter {
|
|
||||||
names: self,
|
|
||||||
idx: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a GeneralNames {
|
|
||||||
type Item = GeneralName<'a>;
|
|
||||||
type IntoIter = GeneralNamesIter<'a>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> GeneralNamesIter<'a> {
|
|
||||||
self.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over OpenSSL `GENERAL_NAME`s.
|
|
||||||
pub struct GeneralNamesIter<'a> {
|
|
||||||
names: &'a GeneralNames,
|
|
||||||
idx: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for GeneralNamesIter<'a> {
|
|
||||||
type Item = GeneralName<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.idx < self.names.len() {
|
|
||||||
let name = self.names.get(self.idx);
|
|
||||||
self.idx += 1;
|
|
||||||
Some(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
let size = self.names.len() - self.idx;
|
|
||||||
(size, Some(size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ExactSizeIterator for GeneralNamesIter<'a> {}
|
|
||||||
|
|
||||||
/// An OpenSSL `GENERAL_NAME`.
|
|
||||||
pub struct GeneralName<'a> {
|
|
||||||
name: *const ffi::GENERAL_NAME,
|
|
||||||
m: PhantomData<&'a ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GeneralName<'a> {
|
|
||||||
/// Returns the contents of this `GeneralName` if it is a `dNSName`.
|
/// Returns the contents of this `GeneralName` if it is a `dNSName`.
|
||||||
pub fn dnsname(&self) -> Option<&str> {
|
pub fn dnsname(&self) -> Option<&str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if (*self.name).type_ != ffi::GEN_DNS {
|
if (*self.as_ptr()).type_ != ffi::GEN_DNS {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = ASN1_STRING_data((*self.name).d as *mut _);
|
let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _);
|
||||||
let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
|
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
|
||||||
|
|
||||||
let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
|
let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
|
||||||
// dNSNames are stated to be ASCII (specifically IA5). Hopefully
|
// dNSNames are stated to be ASCII (specifically IA5). Hopefully
|
||||||
|
|
@ -819,18 +702,22 @@ impl<'a> GeneralName<'a> {
|
||||||
/// Returns the contents of this `GeneralName` if it is an `iPAddress`.
|
/// Returns the contents of this `GeneralName` if it is an `iPAddress`.
|
||||||
pub fn ipaddress(&self) -> Option<&[u8]> {
|
pub fn ipaddress(&self) -> Option<&[u8]> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if (*self.name).type_ != ffi::GEN_IPADD {
|
if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = ASN1_STRING_data((*self.name).d as *mut _);
|
let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _);
|
||||||
let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
|
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
|
||||||
|
|
||||||
Some(slice::from_raw_parts(ptr as *const u8, len as usize))
|
Some(slice::from_raw_parts(ptr as *const u8, len as usize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Stackable for GeneralName {
|
||||||
|
type StackType = ffi::stack_st_GENERAL_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_negative_serial() {
|
fn test_negative_serial() {
|
||||||
// I guess that's enough to get a random negative number
|
// I guess that's enough to get a random negative number
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,10 @@ fn test_subject_alt_name() {
|
||||||
|
|
||||||
let subject_alt_names = cert.subject_alt_names().unwrap();
|
let subject_alt_names = cert.subject_alt_names().unwrap();
|
||||||
assert_eq!(3, subject_alt_names.len());
|
assert_eq!(3, subject_alt_names.len());
|
||||||
assert_eq!(Some("foobar.com"), subject_alt_names.get(0).dnsname());
|
assert_eq!(Some("foobar.com"), subject_alt_names[0].dnsname());
|
||||||
assert_eq!(subject_alt_names.get(1).ipaddress(),
|
assert_eq!(subject_alt_names[1].ipaddress(),
|
||||||
Some(&[127, 0, 0, 1][..]));
|
Some(&[127, 0, 0, 1][..]));
|
||||||
assert_eq!(subject_alt_names.get(2).ipaddress(),
|
assert_eq!(subject_alt_names[2].ipaddress(),
|
||||||
Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]));
|
Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue