diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 1318f7f7..6d7e8ba7 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -11,6 +11,7 @@ use pkey::PKey; use error::ErrorStack; use x509::X509; use types::OpenSslType; +use stack::Stack; /// A PKCS #12 archive. pub struct Pkcs12(*mut ffi::PKCS12); @@ -48,19 +49,12 @@ impl Pkcs12 { let pkey = PKey::from_ptr(pkey); let cert = X509::from_ptr(cert); - let chain = chain as *mut _; - - let mut chain_out = vec![]; - for i in 0..compat::OPENSSL_sk_num(chain) { - let x509 = compat::OPENSSL_sk_value(chain, i); - chain_out.push(X509::from_ptr(x509 as *mut _)); - } - compat::OPENSSL_sk_free(chain as *mut _); + let chain = Stack::from_ptr(chain).into_iter().collect(); Ok(ParsedPkcs12 { pkey: pkey, cert: cert, - chain: chain_out, + chain: chain, }) } } @@ -72,30 +66,6 @@ pub struct ParsedPkcs12 { pub chain: Vec, } -#[cfg(ossl110)] -mod compat { - pub use ffi::OPENSSL_sk_free; - pub use ffi::OPENSSL_sk_num; - pub use ffi::OPENSSL_sk_value; -} - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::{c_int, c_void}; - use ffi; - - pub use ffi::sk_free as OPENSSL_sk_free; - - pub unsafe fn OPENSSL_sk_num(stack: *mut ffi::_STACK) -> c_int { - (*stack).num - } - - pub unsafe fn OPENSSL_sk_value(stack: *const ffi::_STACK, idx: c_int) -> *mut c_void { - *(*stack).data.offset(idx as isize) as *mut c_void - } -} - #[cfg(test)] mod test { use hash::MessageDigest; diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 318791b8..8359f785 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -4,16 +4,16 @@ use std::borrow::Borrow; use std::convert::AsRef; use std::marker::PhantomData; use libc::c_int; +use std::mem; -use ffi; use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; #[cfg(ossl10x)] use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, - sk_value as OPENSSL_sk_value}; + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK}; #[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value}; +use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK}; /// Trait implemented by types which can be placed in a stack. /// @@ -57,6 +57,20 @@ impl Drop for Stack { } } +impl iter::IntoIterator for Stack { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> IntoIter { + let it = IntoIter { + stack: self.0, + idx: 0, + }; + mem::forget(self); + it + } +} + impl AsRef> for Stack { fn as_ref(&self) -> &StackRef { &*self @@ -92,31 +106,66 @@ impl DerefMut for Stack { } } +pub struct IntoIter { + stack: *mut T::StackType, + idx: c_int, +} + +impl IntoIter { + fn stack_len(&self) -> c_int { + unsafe { OPENSSL_sk_num(self.stack as *mut _) } + } + + unsafe fn get(&mut self, i: c_int) -> T { + let ptr = OPENSSL_sk_value(self.stack as *mut _, i); + T::from_ptr(ptr as *mut _) + } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + unsafe { + for i in self.idx..self.stack_len() { + self.get(i); + } + + OPENSSL_sk_free(self.stack as *mut _); + } + } +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + if self.idx == self.stack_len() { + None + } else { + let idx = self.idx; + self.idx += 1; + let v = self.get(idx); + Some(v) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = (self.stack_len() - self.idx) as usize; + (size, Some(size)) + } +} + +impl ExactSizeIterator for IntoIter {} + pub struct StackRef(Opaque, PhantomData); impl OpenSslTypeRef for StackRef { type CType = T::StackType; } - impl StackRef { - /// 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 { + fn as_stack(&self) -> *mut OPENSSL_STACK { self.as_ptr() as *mut _ }