Commit 8ae76106 authored by Sam Scott's avatar Sam Scott
Browse files

Address comments.

parent 2dd37364
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ impl MemBio {
        }
    }

    pub fn from_ptr(bio: *mut ffi::BIO) -> MemBio {
    pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio {
        MemBio(bio)
    }
}
+126 −130
Original line number Diff line number Diff line
@@ -6,112 +6,49 @@ use error::ErrorStack;
use stack::Stack;
use foreign_types::ForeignType;
use symm::Cipher;
use pkey::{HasPrivate, Public, PKeyRef};
use pkey::{HasPrivate, PKeyRef};
use libc::c_int;
use std::ptr::null_mut;
use foreign_types::ForeignTypeRef;
use {cvt, cvt_p};

generic_foreign_type_and_impl_send_sync! {
foreign_type_and_impl_send_sync! {
    type CType = ffi::PKCS7;
    fn drop = ffi::PKCS7_free;

    /// A PKCS#7 structure.
    ///
    /// Contains signed and/or encrypted data.
    pub struct Pkcs7<T>;
    pub struct Pkcs7;

    /// Reference to `Pkcs7`
    pub struct Pkcs7Ref<T>;
    pub struct Pkcs7Ref;
}

bitflags! {
    pub struct PKCS7Flags: c_int {
        const PKCS7_TEXT = ffi::PKCS7_TEXT;
        const PKCS7_NOCERTS = ffi::PKCS7_NOCERTS;
        const PKCS7_NOSIGS = ffi::PKCS7_NOSIGS;
        const PKCS7_NOCHAIN = ffi::PKCS7_NOCHAIN;
        const PKCS7_NOINTERN = ffi::PKCS7_NOINTERN;
        const PKCS7_NOVERIFY = ffi::PKCS7_NOVERIFY;
        const PKCS7_DETACHED = ffi::PKCS7_DETACHED;
        const PKCS7_BINARY = ffi::PKCS7_BINARY;
        const PKCS7_NOATTR = ffi::PKCS7_NOATTR;
        const PKCS7_NOSMIMECAP = ffi::PKCS7_NOSMIMECAP;
        const PKCS7_NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE;
        const PKCS7_CRLFEOL = ffi::PKCS7_CRLFEOL;
        const PKCS7_STREAM = ffi::PKCS7_STREAM;
        const PKCS7_NOCRL = ffi::PKCS7_NOCRL;
        const PKCS7_PARTIAL = ffi::PKCS7_PARTIAL;
        const PKCS7_REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST;
    pub struct Pkcs7Flags: c_int {
        const TEXT = ffi::PKCS7_TEXT;
        const NOCERTS = ffi::PKCS7_NOCERTS;
        const NOSIGS = ffi::PKCS7_NOSIGS;
        const NOCHAIN = ffi::PKCS7_NOCHAIN;
        const NOINTERN = ffi::PKCS7_NOINTERN;
        const NOVERIFY = ffi::PKCS7_NOVERIFY;
        const DETACHED = ffi::PKCS7_DETACHED;
        const BINARY = ffi::PKCS7_BINARY;
        const NOATTR = ffi::PKCS7_NOATTR;
        const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP;
        const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE;
        const CRLFEOL = ffi::PKCS7_CRLFEOL;
        const STREAM = ffi::PKCS7_STREAM;
        const NOCRL = ffi::PKCS7_NOCRL;
        const PARTIAL = ffi::PKCS7_PARTIAL;
        const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST;
        #[cfg(not(any(ossl101, ossl102, libressl)))]
        const PKCS7_NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT;
        const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT;
    }
}

impl Pkcs7<Public> {
    /// Converts PKCS#7 structure to S/MIME format
    ///
    /// This corresponds to [`SMIME_write_PKCS7`].
    ///
    /// [`SMIME_write_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_write_PKCS7.html
    pub fn to_smime(
        &self,
        input: &[u8],
        flags: PKCS7Flags
    ) -> Result<Vec<u8>, ErrorStack>
    {
        ffi::init();

        let input_bio = MemBioSlice::new(input)?;
        let output = MemBio::new()?;
        unsafe {
            cvt(
                ffi::SMIME_write_PKCS7(
                    output.as_ptr(),
                    self.0,
                    input_bio.as_ptr(),
                    flags.bits)
            ).and(
                Ok(output.get_buf().to_owned())
            )
        }
    }

    /// Parses a message in S/MIME format.
    ///
    /// This corresponds to [`SMIME_read_PKCS7`].
    ///
    /// [`SMIME_read_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_read_PKCS7.html
    pub fn from_smime(input: &[u8], bcont: &mut Vec<u8>) -> Result<Self, ErrorStack> {
        ffi::init();

        let input_bio = MemBioSlice::new(input)?;
        let mut bcount_bio = null_mut();
        let pkcs7 = unsafe {
            cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcount_bio))?
        };
        bcont.clear();
        if !bcount_bio.is_null() {
            let bcount_bio = MemBio::from_ptr(bcount_bio);
            bcont.append(&mut bcount_bio.get_buf().to_vec());
        }
        unsafe {
            Ok(Pkcs7::from_ptr(pkcs7))
        }
    }

    to_pem! {
        /// Serializes the data into a PEM-encoded PKCS#7 structure.
        ///
        /// The output will have a header of `-----BEGIN PKCS7-----`.
        ///
        /// This corresponds to [`PEM_write_bio_PKCS7`].
        ///
        /// [`PEM_write_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS7.html
        to_pem,
        ffi::PEM_write_bio_PKCS7
    }

impl Pkcs7 {
    from_pem! {
        /// Deserializes a PEM-encoded PKCS#7 signature
        ///
@@ -121,31 +58,32 @@ impl Pkcs7<Public> {
        ///
        /// [`PEM_read_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PKCS7.html
        from_pem,
        Pkcs7<Public>,
        Pkcs7,
        ffi::PEM_read_bio_PKCS7
    }

    /// Decrypts data using the provided private key.
    ///
    /// `pkey` is the recipient's private key, and `cert` is the recipient's
    /// certificate.
    /// Parses a message in S/MIME format.
    /// 
    /// Returns the decrypted message.
    /// Returns the loaded signature, along with the cleartext message (if
    /// available).
    ///
    /// This corresponds to [`PKCS7_decrypt`].
    /// This corresponds to [`SMIME_read_PKCS7`].
    ///
    /// [`PKCS7_decrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_decrypt.html
    pub fn decrypt<PT>(&self, pkey: &PKeyRef<PT>, cert: &X509Ref) -> Result<Vec<u8>, ErrorStack>
        where
            PT: HasPrivate
    {
    /// [`SMIME_read_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_read_PKCS7.html
    pub fn from_smime(input: &[u8]) -> Result<(Self, Option<Vec<u8>>), ErrorStack> {
        ffi::init();

        let output = MemBio::new()?;

        let input_bio = MemBioSlice::new(input)?;
        let mut bcont_bio = null_mut();
        unsafe {
            cvt(ffi::PKCS7_decrypt(self.0, pkey.as_ptr(), cert.as_ptr(), output.as_ptr(), 0))
                .and(Ok(output.get_buf().to_owned()))
            let pkcs7= cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio))?;
            let out = if !bcont_bio.is_null() {
                let bcont_bio = MemBio::from_ptr(bcont_bio);
                Some(bcont_bio.get_buf().to_vec())
            } else {
                None
            };
            Ok((Pkcs7::from_ptr(pkcs7), out))
        }
    }

@@ -158,7 +96,7 @@ impl Pkcs7<Public> {
    /// This corresponds to [`PKCS7_encrypt`].
    ///
    /// [`PKCS7_encrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_encrypt.html
    pub fn encrypt(certs: &Stack<X509>, input: &[u8], cipher: Cipher, flags: PKCS7Flags) -> Result<Self, ErrorStack> {
    pub fn encrypt(certs: &Stack<X509>, input: &[u8], cipher: Cipher, flags: Pkcs7Flags) -> Result<Self, ErrorStack> {
        ffi::init();

        let input_bio = MemBioSlice::new(input)?;
@@ -188,7 +126,7 @@ impl Pkcs7<Public> {
        pkey: &PKeyRef<PT>,
        certs: &Stack<X509>,
        input: &[u8],
        flags: PKCS7Flags
        flags: Pkcs7Flags
    ) -> Result<Self, ErrorStack>
    where
        PT: HasPrivate
@@ -206,6 +144,72 @@ impl Pkcs7<Public> {
            ).map(|p| Pkcs7::from_ptr(p))
        }
    }
}

impl Pkcs7Ref {
    /// Converts PKCS#7 structure to S/MIME format
    ///
    /// This corresponds to [`SMIME_write_PKCS7`].
    ///
    /// [`SMIME_write_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_write_PKCS7.html
    pub fn to_smime(
        &self,
        input: &[u8],
        flags: Pkcs7Flags
    ) -> Result<Vec<u8>, ErrorStack>
    {
        ffi::init();

        let input_bio = MemBioSlice::new(input)?;
        let output = MemBio::new()?;
        unsafe {
            cvt(
                ffi::SMIME_write_PKCS7(
                    output.as_ptr(),
                    self.as_ptr(),
                    input_bio.as_ptr(),
                    flags.bits)
            ).and(
                Ok(output.get_buf().to_owned())
            )
        }
    }

    to_pem! {
        /// Serializes the data into a PEM-encoded PKCS#7 structure.
        ///
        /// The output will have a header of `-----BEGIN PKCS7-----`.
        ///
        /// This corresponds to [`PEM_write_bio_PKCS7`].
        ///
        /// [`PEM_write_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS7.html
        to_pem,
        ffi::PEM_write_bio_PKCS7
    }

    /// Decrypts data using the provided private key.
    ///
    /// `pkey` is the recipient's private key, and `cert` is the recipient's
    /// certificate.
    ///
    /// Returns the decrypted message.
    ///
    /// This corresponds to [`PKCS7_decrypt`].
    ///
    /// [`PKCS7_decrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_decrypt.html
    pub fn decrypt<PT>(&self, pkey: &PKeyRef<PT>, cert: &X509Ref) -> Result<Vec<u8>, ErrorStack>
        where
            PT: HasPrivate
    {
        ffi::init();

        let output = MemBio::new()?;

        unsafe {
            cvt(ffi::PKCS7_decrypt(self.as_ptr(), pkey.as_ptr(), cert.as_ptr(), output.as_ptr(), 0))
                .and(Ok(output.get_buf().to_owned()))
        }
    }

    /// Verifies the PKCS#7 `signedData` structure contained by `&self`.
    ///
@@ -223,8 +227,8 @@ impl Pkcs7<Public> {
        store: &X509Store,
        indata: Option<&[u8]>,
        out: Option<&mut Vec<u8>>,
        flags: PKCS7Flags
    ) -> Result<bool, ErrorStack> {
        flags: Pkcs7Flags
    ) -> Result<(), ErrorStack> {
        ffi::init();

        let out_bio = MemBio::new()?;
@@ -237,13 +241,13 @@ impl Pkcs7<Public> {

        let result = unsafe {
            cvt(ffi::PKCS7_verify(
                self.0,
                self.as_ptr(),
                certs.as_ptr(),
                store.as_ptr(),
                indata_bio_ptr,
                out_bio.as_ptr(),
                flags.bits))
            .map(|r| r == 1)
            .map(|_r| ())
        };

        if let Some(data) = out {
@@ -260,8 +264,8 @@ mod tests {
    use x509::X509;
    use x509::store::X509StoreBuilder;
    use symm::Cipher;
    use pkcs7::{Pkcs7, PKCS7Flags};
    use pkey::{PKey, Public};
    use pkcs7::{Pkcs7, Pkcs7Flags};
    use pkey::PKey;
    use stack::Stack;

    #[test]
@@ -272,7 +276,7 @@ mod tests {
        certs.push(cert.clone()).unwrap();
        let message: String = String::from("foo");
        let cypher = Cipher::des_ede3_cbc();
        let flags = PKCS7Flags::PKCS7_STREAM;
        let flags = Pkcs7Flags::STREAM;
        let pkey = include_bytes!("../test/key.pem");
        let pkey = PKey::private_key_from_pem(pkey).unwrap();

@@ -280,8 +284,7 @@ mod tests {

        let encrypted = pkcs7.to_smime(message.as_bytes(), flags).expect("should succeed");

        let mut bcount = Vec::new();
        let pkcs7_decoded = Pkcs7::from_smime(encrypted.as_slice(), &mut bcount).expect("should succeed");
        let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed");

        let decoded = pkcs7_decoded.decrypt(&pkey, &cert).expect("should succeed");

@@ -294,7 +297,7 @@ mod tests {
        let cert = X509::from_pem(cert).unwrap();
        let certs = Stack::new().unwrap();
        let message: String = String::from("foo");
        let flags = PKCS7Flags::PKCS7_STREAM | PKCS7Flags::PKCS7_DETACHED;
        let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED;
        let pkey = include_bytes!("../test/key.pem");
        let pkey = PKey::private_key_from_pem(pkey).unwrap();
        let mut store_builder = X509StoreBuilder::new().expect("should succeed");
@@ -309,16 +312,14 @@ mod tests {

        let signed = pkcs7.to_smime(message.as_bytes(), flags).expect("should succeed");
        println!("{:?}", String::from_utf8(signed.clone()).unwrap());
        let mut bcount = Vec::new();
        let pkcs7_decoded = Pkcs7::from_smime(signed.as_slice(), &mut bcount).expect("should succeed");
        let (pkcs7_decoded, content) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed");

        let mut output = Vec::new();
        let result = pkcs7_decoded.verify(&certs, &store, Some(message.as_bytes()), Some(&mut output), flags)
        pkcs7_decoded.verify(&certs, &store, Some(message.as_bytes()), Some(&mut output), flags)
            .expect("should succeed");

        assert!(result);
        assert_eq!(message.clone().into_bytes(), output);
        assert_eq!(message.clone().into_bytes(), bcount);
        assert_eq!(message.clone().into_bytes(), content.expect("should be non-empty"));
    }

    #[test]
@@ -327,7 +328,7 @@ mod tests {
        let cert = X509::from_pem(cert).unwrap();
        let certs = Stack::new().unwrap();
        let message: String = String::from("foo");
        let flags = PKCS7Flags::PKCS7_STREAM;
        let flags = Pkcs7Flags::STREAM;
        let pkey = include_bytes!("../test/key.pem");
        let pkey = PKey::private_key_from_pem(pkey).unwrap();
        let mut store_builder = X509StoreBuilder::new().expect("should succeed");
@@ -342,24 +343,19 @@ mod tests {

        let signed = pkcs7.to_smime(message.as_bytes(), flags).expect("should succeed");

        let mut bcount = Vec::new();
        let pkcs7_decoded = Pkcs7::<Public>::from_smime(signed.as_slice(), &mut bcount).expect("should succeed");
        let (pkcs7_decoded, content) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed");

        let mut output = Vec::new();
        let result = pkcs7_decoded.verify(&certs, &store, None, Some(&mut output), flags).expect("should succeed");
        pkcs7_decoded.verify(&certs, &store, None, Some(&mut output), flags).expect("should succeed");

        assert!(result);
        assert_eq!(message.clone().into_bytes(), output);
        let empty: Vec<u8> = Vec::new();
        assert_eq!(empty, bcount);
        assert!(content.is_none());
    }

    #[test]
    fn invalid_from_smime() {
        let input = String::from("Invalid SMIME Message");
        let mut bcount = Vec::new();

        let result = Pkcs7::from_smime(input.as_bytes(), &mut bcount);
        let result = Pkcs7::from_smime(input.as_bytes());

        assert_eq!(result.is_err(), true)
    }
+0 −2
Original line number Diff line number Diff line
@@ -94,8 +94,6 @@ fn main() {
        s == "PasswordCallback" || s == "pem_password_cb" || s == "bio_info_cb" || s.starts_with("CRYPTO_EX_")
    });
    cfg.skip_struct(|s| s == "ProbeResult");
    cfg.skip_field(|s, field| s == "pkcs7_st" && field == "d");
    cfg.skip_struct(|s| s == "pkcs7_st__d");
    cfg.skip_fn(move |s| {
        s == "CRYPTO_memcmp" ||                 // uses volatile