Commit 77b76ed8 authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #506 from simias/stack

Implemented a generic Stack API and use it to deal with StackOf(X509) and StackOf(GENERAL_NAME)
parents 7bd4fbb6 8d0090fa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -583,6 +583,7 @@ extern {
    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_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY;
    pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING;
    pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
    pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ::ASN1_STRING) -> c_int;
    pub fn ASN1_STRING_data(x: *mut ::ASN1_STRING) -> *mut c_uchar;
    pub fn CRYPTO_add_lock(pointer: *mut c_int,
+4 −4
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@ pub enum HMAC_CTX {}
pub enum OPENSSL_STACK {}
pub enum RSA {}
pub enum SSL_CTX {}
pub enum _STACK {}
pub enum stack_st_ASN1_OBJECT {}
pub enum stack_st_GENERAL_NAME {}
pub enum stack_st_OPENSSL_STRING {}
@@ -142,12 +141,13 @@ extern {
    pub fn X509_up_ref(x: *mut X509) -> c_int;
    pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int;
    pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION;
    pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
    pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX;
    pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX);

    pub fn OpenSSL_version_num() -> c_ulong;
    pub fn OpenSSL_version(key: c_int) -> *const c_char;
    pub fn OPENSSL_sk_free(st: *mut _STACK);
    pub fn OPENSSL_sk_pop_free(st: *mut _STACK, free: Option<unsafe extern "C" fn (*mut c_void)>);
    pub fn OPENSSL_sk_pop(st: *mut _STACK) -> *mut c_void;
    pub fn OPENSSL_sk_free(st: *mut ::OPENSSL_STACK);
    pub fn OPENSSL_sk_pop_free(st: *mut ::OPENSSL_STACK, free: Option<unsafe extern "C" fn (*mut c_void)>);
    pub fn OPENSSL_sk_pop(st: *mut ::OPENSSL_STACK) -> *mut c_void;
}
+1 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ pub mod ssl;
pub mod symm;
pub mod version;
pub mod x509;
pub mod stack;
#[cfg(any(ossl102, ossl110))]
mod verify;

+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() {

openssl/src/stack.rs

0 → 100644
+319 −0
Original line number Diff line number Diff line
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::iter;
use std::borrow::Borrow;
use std::convert::AsRef;

#[cfg(ossl110)]
use libc::c_int;

use ffi;
use types::{OpenSslType, Ref};

/// Trait implemented by stackable types. This must *only* be
/// implemented on opaque types that can be directly casted into their
/// `CType`.
pub trait Stackable: OpenSslType {
    /// C stack type for this element. Generally called
    /// `stack_st_{ELEMENT_TYPE}`, normally hidden by the
    /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API.
    type StackType;
}

/// An owned stack of `T`.
pub struct Stack<T: Stackable>(*mut T::StackType);

impl<T: Stackable> Stack<T> {
    /// Return a new Stack<T>, taking ownership of the handle
    pub unsafe fn from_ptr(stack: *mut T::StackType) -> Stack<T> {
        Stack(stack)
    }
}

impl<T: Stackable> Drop for Stack<T> {
    #[cfg(ossl10x)]
    fn drop(&mut self) {
        unsafe {
            loop {
                let ptr = ffi::sk_pop(self.as_stack());

                if ptr.is_null() {
                    break;
                }

                // Build the owned version of the object just to run
                // its `drop` implementation and delete the item.
                T::from_ptr(ptr as *mut _);
            }

            ffi::sk_free(self.0 as *mut _);
        }
    }

    #[cfg(ossl110)]
    fn drop(&mut self) {
        unsafe {
            loop {
                let ptr = ffi::OPENSSL_sk_pop(self.as_stack());

                if ptr.is_null() {
                    break;
                }

                // Build the owned version of the object just to run
                // its `drop` implementation and delete the item.
                T::from_ptr(ptr as *mut _);
            }

            ffi::OPENSSL_sk_free(self.0 as *mut _);
        }
    }
}

impl<T: Stackable> AsRef<Ref<Stack<T>>> for Stack<T> {
    fn as_ref(&self) -> &Ref<Stack<T>> {
        &*self
    }
}

impl<T: Stackable> Borrow<Ref<Stack<T>>> for Stack<T> {
    fn borrow(&self) -> &Ref<Stack<T>> {
        &*self
    }
}

unsafe impl<T: Stackable> OpenSslType for Stack<T> {
    type CType = T::StackType;

    unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
        Stack(ptr)
    }

    fn as_ptr(&self) -> *mut T::StackType {
        self.0
    }
}

impl<T: Stackable> Deref for Stack<T> {
    type Target = Ref<Stack<T>>;

    fn deref(&self) -> &Ref<Stack<T>> {
        unsafe { Ref::from_ptr(self.0) }
    }
}

impl<T: Stackable> DerefMut for Stack<T> {
    fn deref_mut(&mut self) -> &mut ::types::Ref<Stack<T>> {
        unsafe { Ref::from_ptr_mut(self.0) }
    }
}

impl<T: Stackable> Ref<Stack<T>> {
    /// OpenSSL stack types are just a (kinda) typesafe wrapper around
    /// a `_STACK` object. We can therefore safely cast it and access
    /// the `_STACK` members without having to worry about the real
    /// layout of `T::StackType`.
    ///
    /// If that sounds unsafe then keep in mind that's exactly how the
    /// OpenSSL 1.1.0 new C stack code works.
    #[cfg(ossl10x)]
    fn as_stack(&self) -> *mut ffi::_STACK {
        self.as_ptr() as *mut _
    }

    /// OpenSSL 1.1.0 replaced the stack macros with a functions and
    /// only exposes an opaque OPENSSL_STACK struct
    /// publicly.
    #[cfg(ossl110)]
    fn as_stack(&self) -> *mut ffi::OPENSSL_STACK {
        self.as_ptr() as *mut _
    }

    /// Returns the number of items in the stack
    pub fn len(&self) -> usize {
        self._len()
    }

    #[cfg(ossl10x)]
    fn _len(&self) -> usize {
        unsafe { (*self.as_stack()).num as usize }
    }

    #[cfg(ossl110)]
    fn _len(&self) -> usize {
        unsafe { ffi::OPENSSL_sk_num(self.as_stack()) as usize }
    }

    pub fn iter(&self) -> Iter<T> {
        // Unfortunately we can't simply convert the stack into a
        // slice and use that because OpenSSL 1.1.0 doesn't directly
        // expose the stack data (we have to use `OPENSSL_sk_value`
        // instead). We have to rewrite the entire iteration framework
        // instead.

        Iter {
            stack: self,
            pos: 0,
        }
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut {
            stack: self,
            pos: 0,
        }
    }

    /// Returns a reference to the element at the given index in the
    /// stack or `None` if the index is out of bounds
    pub fn get(&self, idx: usize) -> Option<&Ref<T>> {
        if idx >= self.len() {
            return None;
        }

        unsafe {
            let r = Ref::from_ptr(self._get(idx));

            Some(r)
        }
    }

    /// Returns a mutable reference to the element at the given index in the
    /// stack or `None` if the index is out of bounds
    pub fn get_mut(&mut self, idx: usize) -> Option<&mut Ref<T>> {
        if idx >= self.len() {
            return None;
        }

        unsafe {
            Some(Ref::from_ptr_mut(self._get(idx)))
        }
    }

    #[cfg(ossl10x)]
    unsafe fn _get(&self, idx: usize) -> *mut T::CType {
        *(*self.as_stack()).data.offset(idx as isize) as *mut _
    }

    #[cfg(ossl110)]
    unsafe fn _get(&self, idx: usize) -> *mut T::CType {
        ffi::OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _
    }
}

impl<T: Stackable> Index<usize> for Ref<Stack<T>> {
    type Output = Ref<T>;

    fn index(&self, index: usize) -> &Ref<T> {
        self.get(index).unwrap()
    }
}

impl<T: Stackable> IndexMut<usize> for Ref<Stack<T>> {
    fn index_mut(&mut self, index: usize) -> &mut Ref<T> {
        self.get_mut(index).unwrap()
    }
}

impl<'a, T: Stackable> iter::IntoIterator for &'a Ref<Stack<T>> {
    type Item = &'a Ref<T>;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

impl<'a, T: Stackable> iter::IntoIterator for &'a mut Ref<Stack<T>> {
    type Item = &'a mut Ref<T>;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

impl<'a, T: Stackable> iter::IntoIterator for &'a Stack<T> {
    type Item = &'a Ref<T>;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack<T> {
    type Item = &'a mut Ref<T>;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

/// An iterator over the stack's contents.
pub struct Iter<'a, T: Stackable>
    where T: 'a {
    stack: &'a Ref<Stack<T>>,
    pos: usize,
}

impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> {
    type Item = &'a Ref<T>;

    fn next(&mut self) -> Option<&'a Ref<T>> {
        let n = self.stack.get(self.pos);

        if n.is_some() {
            self.pos += 1;
        }

        n
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.stack.len() - self.pos;

        (rem, Some(rem))
    }
}

impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> {
}

/// A mutable iterator over the stack's contents.
pub struct IterMut<'a, T: Stackable + 'a> {
    stack: &'a mut Ref<Stack<T>>,
    pos: usize,
}

impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> {
    type Item = &'a mut Ref<T>;

    fn next(&mut self) -> Option<&'a mut Ref<T>> {
        if self.pos >= self.stack.len() {
            None
        } else {
            // Rust won't allow us to get a mutable reference into
            // `stack` in this situation since it can't statically
            // guarantee that we won't return several references to
            // the same object, so we have to use unsafe code for
            // mutable iterators.
            let n = unsafe {
                Some(Ref::from_ptr_mut(self.stack._get(self.pos)))
            };

            self.pos += 1;

            n
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.stack.len() - self.pos;

        (rem, Some(rem))
    }
}

impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> {
}
Loading