Unverified Commit 9e688cb8 authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #1075 from tgbit/cms_extensions

CMS: add encrypt, from_der
parents 7602aed0 546eb4d3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
use libc::*;
use *;

pub enum CMS_ContentInfo {}

@@ -7,6 +8,9 @@ extern "C" {
    pub fn CMS_ContentInfo_free(cms: *mut ::CMS_ContentInfo);
    #[cfg(ossl101)]
    pub fn i2d_CMS_ContentInfo(a: *mut ::CMS_ContentInfo, pp: *mut *mut c_uchar) -> c_int;

    #[cfg(ossl101)]
    pub fn d2i_CMS_ContentInfo(a: *mut *mut ::CMS_ContentInfo, pp: *mut *const c_uchar, length: c_long) -> *mut ::CMS_ContentInfo;
}

#[cfg(ossl101)]
@@ -67,6 +71,14 @@ extern "C" {
        flags: c_uint,
    ) -> *mut ::CMS_ContentInfo;

    #[cfg(ossl101)]
    pub fn CMS_encrypt(
        certs: *mut stack_st_X509,
        data: *mut ::BIO,
        cipher: *const EVP_CIPHER,
        flags: c_uint
    ) -> *mut ::CMS_ContentInfo;

    #[cfg(ossl101)]
    pub fn CMS_decrypt(
        cms: *mut ::CMS_ContentInfo,
+75 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ use libc::c_uint;
use pkey::{HasPrivate, PKeyRef};
use stack::StackRef;
use x509::{X509Ref, X509};
use symm::Cipher;
use {cvt, cvt_p};

bitflags! {
@@ -122,6 +123,17 @@ impl CmsContentInfo {
        }
    }

    from_der! {
        /// Deserializes a DER-encoded ContentInfo structure.
        ///
        /// This corresponds to [`d2i_CMS_ContentInfo`].
        ///
        /// [`d2i_CMS_ContentInfo`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html
        from_der,
        CmsContentInfo,
        ffi::d2i_CMS_ContentInfo
    }

    /// Given a signing cert `signcert`, private key `pkey`, a certificate stack `certs`,
    /// data `data` and flags `flags`, create a CmsContentInfo struct.
    ///
@@ -161,4 +173,67 @@ impl CmsContentInfo {
            Ok(CmsContentInfo::from_ptr(cms))
        }
    }

    /// Given a certificate stack `certs`, data `data`, cipher `cipher` and flags `flags`,
    /// create a CmsContentInfo struct.
    ///
    /// OpenSSL documentation at [`CMS_encrypt`]
    ///
    /// [`CMS_encrypt`]: https://www.openssl.org/docs/manmaster/man3/CMS_encrypt.html
    pub fn encrypt(
        certs: &StackRef<X509>,
        data: &[u8],
        cipher: Cipher,
        flags: CMSOptions,
    ) -> Result<CmsContentInfo, ErrorStack>
    {
        unsafe {
            let data_bio = MemBioSlice::new(data)?;

            let cms = cvt_p(ffi::CMS_encrypt(
                certs.as_ptr(),
                data_bio.as_ptr(),
                cipher.as_ptr(),
                flags.bits(),
            ))?;

            Ok(CmsContentInfo::from_ptr(cms))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use stack::Stack;
    use x509::X509;
    use pkcs12::Pkcs12;

    #[test]
    fn cms_encrypt_decrypt() {
        // load cert with public key only
        let pub_cert_bytes = include_bytes!("../test/cms_pubkey.der");
        let pub_cert = X509::from_der(pub_cert_bytes).expect("failed to load pub cert");

        // load cert with private key
        let priv_cert_bytes = include_bytes!("../test/cms.p12");
        let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert");
        let priv_cert = priv_cert.parse("mypass").expect("failed to parse priv cert");

        // encrypt cms message using public key cert
        let input = String::from("My Message");
        let mut cert_stack = Stack::new().expect("failed to create stack");
        cert_stack.push(pub_cert).expect("failed to add pub cert to stack");

        let encrypt = CmsContentInfo::encrypt(&cert_stack, &input.as_bytes(), Cipher::des_ede3_cbc(), CMSOptions::empty())
            .expect("failed create encrypted cms");
        let encrypt = encrypt.to_der().expect("failed to create der from cms");

        // decrypt cms message using private key cert
        let decrypt = CmsContentInfo::from_der(&encrypt).expect("failed read cms from der");
        let decrypt = decrypt.decrypt(&priv_cert.pkey, &priv_cert.cert).expect("failed to decrypt cms");
        let decrypt = String::from_utf8(decrypt).expect("failed to create string from cms content");

        assert_eq!(input, decrypt);
    }
}

openssl/test/cms.p12

0 → 100644
+1.67 KiB

File added.

No diff preview for this file type.

+688 B

File added.

No diff preview for this file type.