Commit 36bf0bb3 authored by Lionel Flandrin's avatar Lionel Flandrin
Browse files

Replace GeneralNames by the new Stack API

parent 3bdefa98
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -256,7 +256,8 @@ mod verify {
    use std::str;

    use nid;
    use x509::{X509StoreContext, X509, GeneralNames, X509Name};
    use x509::{X509StoreContext, X509, X509Name, GeneralName};
    use stack::Stack;
    use types::Ref;

    pub fn verify_callback(domain: &str,
@@ -275,15 +276,16 @@ mod verify {

    fn verify_hostname(domain: &str, cert: &Ref<X509>) -> bool {
        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()),
        }
    }

    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();

        for name in names {
        for name in &names {
            match ip {
                Ok(ip) => {
                    if let Some(actual) = name.ipaddress() {
+16 −129
Original line number Diff line number Diff line
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::cmp;
use std::collections::HashMap;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::slice;
@@ -21,6 +20,7 @@ use error::ErrorStack;
use ffi;
use nid::Nid;
use types::{OpenSslType, Ref};
use stack::{Stack, Stackable};

#[cfg(ossl10x)]
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.
    pub fn subject_alt_names(&self) -> Option<GeneralNames> {
    pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
        unsafe {
            let stack = ffi::X509_get_ext_d2i(self.as_ptr(),
                                              ffi::NID_subject_alt_name,
@@ -356,7 +356,7 @@ impl Ref<X509> {
                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.
pub struct GeneralNames {
    stack: *mut ffi::stack_st_GENERAL_NAME,
}

impl Drop for GeneralNames {
    #[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>;
type_!(GeneralName, ffi::GENERAL_NAME, ffi::GENERAL_NAME_free);

    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> {
impl Ref<GeneralName> {
    /// Returns the contents of this `GeneralName` if it is a `dNSName`.
    pub fn dnsname(&self) -> Option<&str> {
        unsafe {
            if (*self.name).type_ != ffi::GEN_DNS {
            if (*self.as_ptr()).type_ != ffi::GEN_DNS {
                return None;
            }

            let ptr = ASN1_STRING_data((*self.name).d as *mut _);
            let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
            let ptr = ASN1_STRING_data((*self.as_ptr()).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);
            // 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`.
    pub fn ipaddress(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.name).type_ != ffi::GEN_IPADD {
            if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
                return None;
            }

            let ptr = ASN1_STRING_data((*self.name).d as *mut _);
            let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
            let ptr = ASN1_STRING_data((*self.as_ptr()).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))
        }
    }
}

impl Stackable for GeneralName {
    type StackType = ffi::stack_st_GENERAL_NAME;
}

#[test]
fn test_negative_serial() {
    // I guess that's enough to get a random negative number
+3 −3
Original line number Diff line number Diff line
@@ -152,10 +152,10 @@ fn test_subject_alt_name() {

    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).dnsname());
    assert_eq!(subject_alt_names.get(1).ipaddress(),
    assert_eq!(Some("foobar.com"), subject_alt_names[0].dnsname());
    assert_eq!(subject_alt_names[1].ipaddress(),
               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"[..]));
}