192f3ab15Sopenharmony_ciuse bitflags::bitflags;
292f3ab15Sopenharmony_ciuse foreign_types::{ForeignType, ForeignTypeRef};
392f3ab15Sopenharmony_ciuse libc::c_int;
492f3ab15Sopenharmony_ciuse std::mem;
592f3ab15Sopenharmony_ciuse std::ptr;
692f3ab15Sopenharmony_ci
792f3ab15Sopenharmony_ciuse crate::bio::{MemBio, MemBioSlice};
892f3ab15Sopenharmony_ciuse crate::error::ErrorStack;
992f3ab15Sopenharmony_ciuse crate::pkey::{HasPrivate, PKeyRef};
1092f3ab15Sopenharmony_ciuse crate::stack::{Stack, StackRef};
1192f3ab15Sopenharmony_ciuse crate::symm::Cipher;
1292f3ab15Sopenharmony_ciuse crate::x509::store::X509StoreRef;
1392f3ab15Sopenharmony_ciuse crate::x509::{X509Ref, X509};
1492f3ab15Sopenharmony_ciuse crate::{cvt, cvt_p};
1592f3ab15Sopenharmony_ciuse openssl_macros::corresponds;
1692f3ab15Sopenharmony_ci
1792f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! {
1892f3ab15Sopenharmony_ci    type CType = ffi::PKCS7;
1992f3ab15Sopenharmony_ci    fn drop = ffi::PKCS7_free;
2092f3ab15Sopenharmony_ci
2192f3ab15Sopenharmony_ci    /// A PKCS#7 structure.
2292f3ab15Sopenharmony_ci    ///
2392f3ab15Sopenharmony_ci    /// Contains signed and/or encrypted data.
2492f3ab15Sopenharmony_ci    pub struct Pkcs7;
2592f3ab15Sopenharmony_ci
2692f3ab15Sopenharmony_ci    /// Reference to `Pkcs7`
2792f3ab15Sopenharmony_ci    pub struct Pkcs7Ref;
2892f3ab15Sopenharmony_ci}
2992f3ab15Sopenharmony_ci
3092f3ab15Sopenharmony_cibitflags! {
3192f3ab15Sopenharmony_ci    pub struct Pkcs7Flags: c_int {
3292f3ab15Sopenharmony_ci        const TEXT = ffi::PKCS7_TEXT;
3392f3ab15Sopenharmony_ci        const NOCERTS = ffi::PKCS7_NOCERTS;
3492f3ab15Sopenharmony_ci        const NOSIGS = ffi::PKCS7_NOSIGS;
3592f3ab15Sopenharmony_ci        const NOCHAIN = ffi::PKCS7_NOCHAIN;
3692f3ab15Sopenharmony_ci        const NOINTERN = ffi::PKCS7_NOINTERN;
3792f3ab15Sopenharmony_ci        const NOVERIFY = ffi::PKCS7_NOVERIFY;
3892f3ab15Sopenharmony_ci        const DETACHED = ffi::PKCS7_DETACHED;
3992f3ab15Sopenharmony_ci        const BINARY = ffi::PKCS7_BINARY;
4092f3ab15Sopenharmony_ci        const NOATTR = ffi::PKCS7_NOATTR;
4192f3ab15Sopenharmony_ci        const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP;
4292f3ab15Sopenharmony_ci        const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE;
4392f3ab15Sopenharmony_ci        const CRLFEOL = ffi::PKCS7_CRLFEOL;
4492f3ab15Sopenharmony_ci        const STREAM = ffi::PKCS7_STREAM;
4592f3ab15Sopenharmony_ci        const NOCRL = ffi::PKCS7_NOCRL;
4692f3ab15Sopenharmony_ci        const PARTIAL = ffi::PKCS7_PARTIAL;
4792f3ab15Sopenharmony_ci        const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST;
4892f3ab15Sopenharmony_ci        #[cfg(not(any(ossl101, ossl102, libressl)))]
4992f3ab15Sopenharmony_ci        const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT;
5092f3ab15Sopenharmony_ci    }
5192f3ab15Sopenharmony_ci}
5292f3ab15Sopenharmony_ci
5392f3ab15Sopenharmony_ciimpl Pkcs7 {
5492f3ab15Sopenharmony_ci    from_pem! {
5592f3ab15Sopenharmony_ci        /// Deserializes a PEM-encoded PKCS#7 signature
5692f3ab15Sopenharmony_ci        ///
5792f3ab15Sopenharmony_ci        /// The input should have a header of `-----BEGIN PKCS7-----`.
5892f3ab15Sopenharmony_ci        #[corresponds(PEM_read_bio_PKCS7)]
5992f3ab15Sopenharmony_ci        from_pem,
6092f3ab15Sopenharmony_ci        Pkcs7,
6192f3ab15Sopenharmony_ci        ffi::PEM_read_bio_PKCS7
6292f3ab15Sopenharmony_ci    }
6392f3ab15Sopenharmony_ci
6492f3ab15Sopenharmony_ci    from_der! {
6592f3ab15Sopenharmony_ci        /// Deserializes a DER-encoded PKCS#7 signature
6692f3ab15Sopenharmony_ci        #[corresponds(d2i_PKCS7)]
6792f3ab15Sopenharmony_ci        from_der,
6892f3ab15Sopenharmony_ci        Pkcs7,
6992f3ab15Sopenharmony_ci        ffi::d2i_PKCS7
7092f3ab15Sopenharmony_ci    }
7192f3ab15Sopenharmony_ci
7292f3ab15Sopenharmony_ci    /// Parses a message in S/MIME format.
7392f3ab15Sopenharmony_ci    ///
7492f3ab15Sopenharmony_ci    /// Returns the loaded signature, along with the cleartext message (if
7592f3ab15Sopenharmony_ci    /// available).
7692f3ab15Sopenharmony_ci    #[corresponds(SMIME_read_PKCS7)]
7792f3ab15Sopenharmony_ci    pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option<Vec<u8>>), ErrorStack> {
7892f3ab15Sopenharmony_ci        ffi::init();
7992f3ab15Sopenharmony_ci
8092f3ab15Sopenharmony_ci        let input_bio = MemBioSlice::new(input)?;
8192f3ab15Sopenharmony_ci        let mut bcont_bio = ptr::null_mut();
8292f3ab15Sopenharmony_ci        unsafe {
8392f3ab15Sopenharmony_ci            let pkcs7 =
8492f3ab15Sopenharmony_ci                cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio)).map(Pkcs7)?;
8592f3ab15Sopenharmony_ci            let out = if !bcont_bio.is_null() {
8692f3ab15Sopenharmony_ci                let bcont_bio = MemBio::from_ptr(bcont_bio);
8792f3ab15Sopenharmony_ci                Some(bcont_bio.get_buf().to_vec())
8892f3ab15Sopenharmony_ci            } else {
8992f3ab15Sopenharmony_ci                None
9092f3ab15Sopenharmony_ci            };
9192f3ab15Sopenharmony_ci            Ok((pkcs7, out))
9292f3ab15Sopenharmony_ci        }
9392f3ab15Sopenharmony_ci    }
9492f3ab15Sopenharmony_ci
9592f3ab15Sopenharmony_ci    /// Creates and returns a PKCS#7 `envelopedData` structure.
9692f3ab15Sopenharmony_ci    ///
9792f3ab15Sopenharmony_ci    /// `certs` is a list of recipient certificates. `input` is the content to be
9892f3ab15Sopenharmony_ci    /// encrypted. `cipher` is the symmetric cipher to use. `flags` is an optional
9992f3ab15Sopenharmony_ci    /// set of flags.
10092f3ab15Sopenharmony_ci    #[corresponds(PKCS7_encrypt)]
10192f3ab15Sopenharmony_ci    pub fn encrypt(
10292f3ab15Sopenharmony_ci        certs: &StackRef<X509>,
10392f3ab15Sopenharmony_ci        input: &[u8],
10492f3ab15Sopenharmony_ci        cipher: Cipher,
10592f3ab15Sopenharmony_ci        flags: Pkcs7Flags,
10692f3ab15Sopenharmony_ci    ) -> Result<Pkcs7, ErrorStack> {
10792f3ab15Sopenharmony_ci        let input_bio = MemBioSlice::new(input)?;
10892f3ab15Sopenharmony_ci
10992f3ab15Sopenharmony_ci        unsafe {
11092f3ab15Sopenharmony_ci            cvt_p(ffi::PKCS7_encrypt(
11192f3ab15Sopenharmony_ci                certs.as_ptr(),
11292f3ab15Sopenharmony_ci                input_bio.as_ptr(),
11392f3ab15Sopenharmony_ci                cipher.as_ptr(),
11492f3ab15Sopenharmony_ci                flags.bits,
11592f3ab15Sopenharmony_ci            ))
11692f3ab15Sopenharmony_ci            .map(Pkcs7)
11792f3ab15Sopenharmony_ci        }
11892f3ab15Sopenharmony_ci    }
11992f3ab15Sopenharmony_ci
12092f3ab15Sopenharmony_ci    /// Creates and returns a PKCS#7 `signedData` structure.
12192f3ab15Sopenharmony_ci    ///
12292f3ab15Sopenharmony_ci    /// `signcert` is the certificate to sign with, `pkey` is the corresponding
12392f3ab15Sopenharmony_ci    /// private key. `certs` is an optional additional set of certificates to
12492f3ab15Sopenharmony_ci    /// include in the PKCS#7 structure (for example any intermediate CAs in the
12592f3ab15Sopenharmony_ci    /// chain).
12692f3ab15Sopenharmony_ci    #[corresponds(PKCS7_sign)]
12792f3ab15Sopenharmony_ci    pub fn sign<PT>(
12892f3ab15Sopenharmony_ci        signcert: &X509Ref,
12992f3ab15Sopenharmony_ci        pkey: &PKeyRef<PT>,
13092f3ab15Sopenharmony_ci        certs: &StackRef<X509>,
13192f3ab15Sopenharmony_ci        input: &[u8],
13292f3ab15Sopenharmony_ci        flags: Pkcs7Flags,
13392f3ab15Sopenharmony_ci    ) -> Result<Pkcs7, ErrorStack>
13492f3ab15Sopenharmony_ci    where
13592f3ab15Sopenharmony_ci        PT: HasPrivate,
13692f3ab15Sopenharmony_ci    {
13792f3ab15Sopenharmony_ci        let input_bio = MemBioSlice::new(input)?;
13892f3ab15Sopenharmony_ci        unsafe {
13992f3ab15Sopenharmony_ci            cvt_p(ffi::PKCS7_sign(
14092f3ab15Sopenharmony_ci                signcert.as_ptr(),
14192f3ab15Sopenharmony_ci                pkey.as_ptr(),
14292f3ab15Sopenharmony_ci                certs.as_ptr(),
14392f3ab15Sopenharmony_ci                input_bio.as_ptr(),
14492f3ab15Sopenharmony_ci                flags.bits,
14592f3ab15Sopenharmony_ci            ))
14692f3ab15Sopenharmony_ci            .map(Pkcs7)
14792f3ab15Sopenharmony_ci        }
14892f3ab15Sopenharmony_ci    }
14992f3ab15Sopenharmony_ci}
15092f3ab15Sopenharmony_ci
15192f3ab15Sopenharmony_ciimpl Pkcs7Ref {
15292f3ab15Sopenharmony_ci    /// Converts PKCS#7 structure to S/MIME format
15392f3ab15Sopenharmony_ci    #[corresponds(SMIME_write_PKCS7)]
15492f3ab15Sopenharmony_ci    pub fn to_smime(&self, input: &[u8], flags: Pkcs7Flags) -> Result<Vec<u8>, ErrorStack> {
15592f3ab15Sopenharmony_ci        let input_bio = MemBioSlice::new(input)?;
15692f3ab15Sopenharmony_ci        let output = MemBio::new()?;
15792f3ab15Sopenharmony_ci        unsafe {
15892f3ab15Sopenharmony_ci            cvt(ffi::SMIME_write_PKCS7(
15992f3ab15Sopenharmony_ci                output.as_ptr(),
16092f3ab15Sopenharmony_ci                self.as_ptr(),
16192f3ab15Sopenharmony_ci                input_bio.as_ptr(),
16292f3ab15Sopenharmony_ci                flags.bits,
16392f3ab15Sopenharmony_ci            ))
16492f3ab15Sopenharmony_ci            .map(|_| output.get_buf().to_owned())
16592f3ab15Sopenharmony_ci        }
16692f3ab15Sopenharmony_ci    }
16792f3ab15Sopenharmony_ci
16892f3ab15Sopenharmony_ci    to_pem! {
16992f3ab15Sopenharmony_ci        /// Serializes the data into a PEM-encoded PKCS#7 structure.
17092f3ab15Sopenharmony_ci        ///
17192f3ab15Sopenharmony_ci        /// The output will have a header of `-----BEGIN PKCS7-----`.
17292f3ab15Sopenharmony_ci        #[corresponds(PEM_write_bio_PKCS7)]
17392f3ab15Sopenharmony_ci        to_pem,
17492f3ab15Sopenharmony_ci        ffi::PEM_write_bio_PKCS7
17592f3ab15Sopenharmony_ci    }
17692f3ab15Sopenharmony_ci
17792f3ab15Sopenharmony_ci    to_der! {
17892f3ab15Sopenharmony_ci        /// Serializes the data into a DER-encoded PKCS#7 structure.
17992f3ab15Sopenharmony_ci        #[corresponds(i2d_PKCS7)]
18092f3ab15Sopenharmony_ci        to_der,
18192f3ab15Sopenharmony_ci        ffi::i2d_PKCS7
18292f3ab15Sopenharmony_ci    }
18392f3ab15Sopenharmony_ci
18492f3ab15Sopenharmony_ci    /// Decrypts data using the provided private key.
18592f3ab15Sopenharmony_ci    ///
18692f3ab15Sopenharmony_ci    /// `pkey` is the recipient's private key, and `cert` is the recipient's
18792f3ab15Sopenharmony_ci    /// certificate.
18892f3ab15Sopenharmony_ci    ///
18992f3ab15Sopenharmony_ci    /// Returns the decrypted message.
19092f3ab15Sopenharmony_ci    #[corresponds(PKCS7_decrypt)]
19192f3ab15Sopenharmony_ci    pub fn decrypt<PT>(
19292f3ab15Sopenharmony_ci        &self,
19392f3ab15Sopenharmony_ci        pkey: &PKeyRef<PT>,
19492f3ab15Sopenharmony_ci        cert: &X509Ref,
19592f3ab15Sopenharmony_ci        flags: Pkcs7Flags,
19692f3ab15Sopenharmony_ci    ) -> Result<Vec<u8>, ErrorStack>
19792f3ab15Sopenharmony_ci    where
19892f3ab15Sopenharmony_ci        PT: HasPrivate,
19992f3ab15Sopenharmony_ci    {
20092f3ab15Sopenharmony_ci        let output = MemBio::new()?;
20192f3ab15Sopenharmony_ci
20292f3ab15Sopenharmony_ci        unsafe {
20392f3ab15Sopenharmony_ci            cvt(ffi::PKCS7_decrypt(
20492f3ab15Sopenharmony_ci                self.as_ptr(),
20592f3ab15Sopenharmony_ci                pkey.as_ptr(),
20692f3ab15Sopenharmony_ci                cert.as_ptr(),
20792f3ab15Sopenharmony_ci                output.as_ptr(),
20892f3ab15Sopenharmony_ci                flags.bits,
20992f3ab15Sopenharmony_ci            ))
21092f3ab15Sopenharmony_ci            .map(|_| output.get_buf().to_owned())
21192f3ab15Sopenharmony_ci        }
21292f3ab15Sopenharmony_ci    }
21392f3ab15Sopenharmony_ci
21492f3ab15Sopenharmony_ci    /// Verifies the PKCS#7 `signedData` structure contained by `&self`.
21592f3ab15Sopenharmony_ci    ///
21692f3ab15Sopenharmony_ci    /// `certs` is a set of certificates in which to search for the signer's
21792f3ab15Sopenharmony_ci    /// certificate. `store` is a trusted certificate store (used for chain
21892f3ab15Sopenharmony_ci    /// verification). `indata` is the signed data if the content is not present
21992f3ab15Sopenharmony_ci    /// in `&self`. The content is written to `out` if it is not `None`.
22092f3ab15Sopenharmony_ci    #[corresponds(PKCS7_verify)]
22192f3ab15Sopenharmony_ci    pub fn verify(
22292f3ab15Sopenharmony_ci        &self,
22392f3ab15Sopenharmony_ci        certs: &StackRef<X509>,
22492f3ab15Sopenharmony_ci        store: &X509StoreRef,
22592f3ab15Sopenharmony_ci        indata: Option<&[u8]>,
22692f3ab15Sopenharmony_ci        out: Option<&mut Vec<u8>>,
22792f3ab15Sopenharmony_ci        flags: Pkcs7Flags,
22892f3ab15Sopenharmony_ci    ) -> Result<(), ErrorStack> {
22992f3ab15Sopenharmony_ci        let out_bio = MemBio::new()?;
23092f3ab15Sopenharmony_ci
23192f3ab15Sopenharmony_ci        let indata_bio = match indata {
23292f3ab15Sopenharmony_ci            Some(data) => Some(MemBioSlice::new(data)?),
23392f3ab15Sopenharmony_ci            None => None,
23492f3ab15Sopenharmony_ci        };
23592f3ab15Sopenharmony_ci        let indata_bio_ptr = indata_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr());
23692f3ab15Sopenharmony_ci
23792f3ab15Sopenharmony_ci        unsafe {
23892f3ab15Sopenharmony_ci            cvt(ffi::PKCS7_verify(
23992f3ab15Sopenharmony_ci                self.as_ptr(),
24092f3ab15Sopenharmony_ci                certs.as_ptr(),
24192f3ab15Sopenharmony_ci                store.as_ptr(),
24292f3ab15Sopenharmony_ci                indata_bio_ptr,
24392f3ab15Sopenharmony_ci                out_bio.as_ptr(),
24492f3ab15Sopenharmony_ci                flags.bits,
24592f3ab15Sopenharmony_ci            ))
24692f3ab15Sopenharmony_ci            .map(|_| ())?
24792f3ab15Sopenharmony_ci        }
24892f3ab15Sopenharmony_ci
24992f3ab15Sopenharmony_ci        if let Some(data) = out {
25092f3ab15Sopenharmony_ci            data.clear();
25192f3ab15Sopenharmony_ci            data.extend_from_slice(out_bio.get_buf());
25292f3ab15Sopenharmony_ci        }
25392f3ab15Sopenharmony_ci
25492f3ab15Sopenharmony_ci        Ok(())
25592f3ab15Sopenharmony_ci    }
25692f3ab15Sopenharmony_ci
25792f3ab15Sopenharmony_ci    /// Retrieve the signer's certificates from the PKCS#7 structure without verifying them.
25892f3ab15Sopenharmony_ci    #[corresponds(PKCS7_get0_signers)]
25992f3ab15Sopenharmony_ci    pub fn signers(
26092f3ab15Sopenharmony_ci        &self,
26192f3ab15Sopenharmony_ci        certs: &StackRef<X509>,
26292f3ab15Sopenharmony_ci        flags: Pkcs7Flags,
26392f3ab15Sopenharmony_ci    ) -> Result<Stack<X509>, ErrorStack> {
26492f3ab15Sopenharmony_ci        unsafe {
26592f3ab15Sopenharmony_ci            let ptr = cvt_p(ffi::PKCS7_get0_signers(
26692f3ab15Sopenharmony_ci                self.as_ptr(),
26792f3ab15Sopenharmony_ci                certs.as_ptr(),
26892f3ab15Sopenharmony_ci                flags.bits,
26992f3ab15Sopenharmony_ci            ))?;
27092f3ab15Sopenharmony_ci
27192f3ab15Sopenharmony_ci            // The returned stack is owned by the caller, but the certs inside are not! Our stack interface can't deal
27292f3ab15Sopenharmony_ci            // with that, so instead we just manually bump the refcount of the certs so that the whole stack is properly
27392f3ab15Sopenharmony_ci            // owned.
27492f3ab15Sopenharmony_ci            let stack = Stack::<X509>::from_ptr(ptr);
27592f3ab15Sopenharmony_ci            for cert in &stack {
27692f3ab15Sopenharmony_ci                mem::forget(cert.to_owned());
27792f3ab15Sopenharmony_ci            }
27892f3ab15Sopenharmony_ci
27992f3ab15Sopenharmony_ci            Ok(stack)
28092f3ab15Sopenharmony_ci        }
28192f3ab15Sopenharmony_ci    }
28292f3ab15Sopenharmony_ci}
28392f3ab15Sopenharmony_ci
28492f3ab15Sopenharmony_ci#[cfg(test)]
28592f3ab15Sopenharmony_cimod tests {
28692f3ab15Sopenharmony_ci    use crate::hash::MessageDigest;
28792f3ab15Sopenharmony_ci    use crate::pkcs7::{Pkcs7, Pkcs7Flags};
28892f3ab15Sopenharmony_ci    use crate::pkey::PKey;
28992f3ab15Sopenharmony_ci    use crate::stack::Stack;
29092f3ab15Sopenharmony_ci    use crate::symm::Cipher;
29192f3ab15Sopenharmony_ci    use crate::x509::store::X509StoreBuilder;
29292f3ab15Sopenharmony_ci    use crate::x509::X509;
29392f3ab15Sopenharmony_ci
29492f3ab15Sopenharmony_ci    #[test]
29592f3ab15Sopenharmony_ci    fn encrypt_decrypt_test() {
29692f3ab15Sopenharmony_ci        let cert = include_bytes!("../test/certs.pem");
29792f3ab15Sopenharmony_ci        let cert = X509::from_pem(cert).unwrap();
29892f3ab15Sopenharmony_ci        let mut certs = Stack::new().unwrap();
29992f3ab15Sopenharmony_ci        certs.push(cert.clone()).unwrap();
30092f3ab15Sopenharmony_ci        let message: String = String::from("foo");
30192f3ab15Sopenharmony_ci        let cipher = Cipher::des_ede3_cbc();
30292f3ab15Sopenharmony_ci        let flags = Pkcs7Flags::STREAM;
30392f3ab15Sopenharmony_ci        let pkey = include_bytes!("../test/key.pem");
30492f3ab15Sopenharmony_ci        let pkey = PKey::private_key_from_pem(pkey).unwrap();
30592f3ab15Sopenharmony_ci
30692f3ab15Sopenharmony_ci        let pkcs7 =
30792f3ab15Sopenharmony_ci            Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
30892f3ab15Sopenharmony_ci
30992f3ab15Sopenharmony_ci        let encrypted = pkcs7
31092f3ab15Sopenharmony_ci            .to_smime(message.as_bytes(), flags)
31192f3ab15Sopenharmony_ci            .expect("should succeed");
31292f3ab15Sopenharmony_ci
31392f3ab15Sopenharmony_ci        let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed");
31492f3ab15Sopenharmony_ci
31592f3ab15Sopenharmony_ci        let decoded = pkcs7_decoded
31692f3ab15Sopenharmony_ci            .decrypt(&pkey, &cert, Pkcs7Flags::empty())
31792f3ab15Sopenharmony_ci            .expect("should succeed");
31892f3ab15Sopenharmony_ci
31992f3ab15Sopenharmony_ci        assert_eq!(decoded, message.into_bytes());
32092f3ab15Sopenharmony_ci    }
32192f3ab15Sopenharmony_ci
32292f3ab15Sopenharmony_ci    #[test]
32392f3ab15Sopenharmony_ci    fn sign_verify_test_detached() {
32492f3ab15Sopenharmony_ci        let cert = include_bytes!("../test/cert.pem");
32592f3ab15Sopenharmony_ci        let cert = X509::from_pem(cert).unwrap();
32692f3ab15Sopenharmony_ci        let certs = Stack::new().unwrap();
32792f3ab15Sopenharmony_ci        let message = "foo";
32892f3ab15Sopenharmony_ci        let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED;
32992f3ab15Sopenharmony_ci        let pkey = include_bytes!("../test/key.pem");
33092f3ab15Sopenharmony_ci        let pkey = PKey::private_key_from_pem(pkey).unwrap();
33192f3ab15Sopenharmony_ci        let mut store_builder = X509StoreBuilder::new().expect("should succeed");
33292f3ab15Sopenharmony_ci
33392f3ab15Sopenharmony_ci        let root_ca = include_bytes!("../test/root-ca.pem");
33492f3ab15Sopenharmony_ci        let root_ca = X509::from_pem(root_ca).unwrap();
33592f3ab15Sopenharmony_ci        store_builder.add_cert(root_ca).expect("should succeed");
33692f3ab15Sopenharmony_ci
33792f3ab15Sopenharmony_ci        let store = store_builder.build();
33892f3ab15Sopenharmony_ci
33992f3ab15Sopenharmony_ci        let pkcs7 =
34092f3ab15Sopenharmony_ci            Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
34192f3ab15Sopenharmony_ci
34292f3ab15Sopenharmony_ci        let signed = pkcs7
34392f3ab15Sopenharmony_ci            .to_smime(message.as_bytes(), flags)
34492f3ab15Sopenharmony_ci            .expect("should succeed");
34592f3ab15Sopenharmony_ci        println!("{:?}", String::from_utf8(signed.clone()).unwrap());
34692f3ab15Sopenharmony_ci        let (pkcs7_decoded, content) =
34792f3ab15Sopenharmony_ci            Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
34892f3ab15Sopenharmony_ci
34992f3ab15Sopenharmony_ci        let mut output = Vec::new();
35092f3ab15Sopenharmony_ci        pkcs7_decoded
35192f3ab15Sopenharmony_ci            .verify(
35292f3ab15Sopenharmony_ci                &certs,
35392f3ab15Sopenharmony_ci                &store,
35492f3ab15Sopenharmony_ci                Some(message.as_bytes()),
35592f3ab15Sopenharmony_ci                Some(&mut output),
35692f3ab15Sopenharmony_ci                flags,
35792f3ab15Sopenharmony_ci            )
35892f3ab15Sopenharmony_ci            .expect("should succeed");
35992f3ab15Sopenharmony_ci
36092f3ab15Sopenharmony_ci        assert_eq!(output, message.as_bytes());
36192f3ab15Sopenharmony_ci        assert_eq!(content.expect("should be non-empty"), message.as_bytes());
36292f3ab15Sopenharmony_ci    }
36392f3ab15Sopenharmony_ci
36492f3ab15Sopenharmony_ci    /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
36592f3ab15Sopenharmony_ci    #[test]
36692f3ab15Sopenharmony_ci    #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
36792f3ab15Sopenharmony_ci    fn sign_verify_test_normal() {
36892f3ab15Sopenharmony_ci        let cert = include_bytes!("../test/cert.pem");
36992f3ab15Sopenharmony_ci        let cert = X509::from_pem(cert).unwrap();
37092f3ab15Sopenharmony_ci        let certs = Stack::new().unwrap();
37192f3ab15Sopenharmony_ci        let message = "foo";
37292f3ab15Sopenharmony_ci        let flags = Pkcs7Flags::STREAM;
37392f3ab15Sopenharmony_ci        let pkey = include_bytes!("../test/key.pem");
37492f3ab15Sopenharmony_ci        let pkey = PKey::private_key_from_pem(pkey).unwrap();
37592f3ab15Sopenharmony_ci        let mut store_builder = X509StoreBuilder::new().expect("should succeed");
37692f3ab15Sopenharmony_ci
37792f3ab15Sopenharmony_ci        let root_ca = include_bytes!("../test/root-ca.pem");
37892f3ab15Sopenharmony_ci        let root_ca = X509::from_pem(root_ca).unwrap();
37992f3ab15Sopenharmony_ci        store_builder.add_cert(root_ca).expect("should succeed");
38092f3ab15Sopenharmony_ci
38192f3ab15Sopenharmony_ci        let store = store_builder.build();
38292f3ab15Sopenharmony_ci
38392f3ab15Sopenharmony_ci        let pkcs7 =
38492f3ab15Sopenharmony_ci            Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
38592f3ab15Sopenharmony_ci
38692f3ab15Sopenharmony_ci        let signed = pkcs7
38792f3ab15Sopenharmony_ci            .to_smime(message.as_bytes(), flags)
38892f3ab15Sopenharmony_ci            .expect("should succeed");
38992f3ab15Sopenharmony_ci
39092f3ab15Sopenharmony_ci        let (pkcs7_decoded, content) =
39192f3ab15Sopenharmony_ci            Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
39292f3ab15Sopenharmony_ci
39392f3ab15Sopenharmony_ci        let mut output = Vec::new();
39492f3ab15Sopenharmony_ci        pkcs7_decoded
39592f3ab15Sopenharmony_ci            .verify(&certs, &store, None, Some(&mut output), flags)
39692f3ab15Sopenharmony_ci            .expect("should succeed");
39792f3ab15Sopenharmony_ci
39892f3ab15Sopenharmony_ci        assert_eq!(output, message.as_bytes());
39992f3ab15Sopenharmony_ci        assert!(content.is_none());
40092f3ab15Sopenharmony_ci    }
40192f3ab15Sopenharmony_ci
40292f3ab15Sopenharmony_ci    /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
40392f3ab15Sopenharmony_ci    #[test]
40492f3ab15Sopenharmony_ci    #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
40592f3ab15Sopenharmony_ci    fn signers() {
40692f3ab15Sopenharmony_ci        let cert = include_bytes!("../test/cert.pem");
40792f3ab15Sopenharmony_ci        let cert = X509::from_pem(cert).unwrap();
40892f3ab15Sopenharmony_ci        let cert_digest = cert.digest(MessageDigest::sha256()).unwrap();
40992f3ab15Sopenharmony_ci        let certs = Stack::new().unwrap();
41092f3ab15Sopenharmony_ci        let message = "foo";
41192f3ab15Sopenharmony_ci        let flags = Pkcs7Flags::STREAM;
41292f3ab15Sopenharmony_ci        let pkey = include_bytes!("../test/key.pem");
41392f3ab15Sopenharmony_ci        let pkey = PKey::private_key_from_pem(pkey).unwrap();
41492f3ab15Sopenharmony_ci        let mut store_builder = X509StoreBuilder::new().expect("should succeed");
41592f3ab15Sopenharmony_ci
41692f3ab15Sopenharmony_ci        let root_ca = include_bytes!("../test/root-ca.pem");
41792f3ab15Sopenharmony_ci        let root_ca = X509::from_pem(root_ca).unwrap();
41892f3ab15Sopenharmony_ci        store_builder.add_cert(root_ca).expect("should succeed");
41992f3ab15Sopenharmony_ci
42092f3ab15Sopenharmony_ci        let pkcs7 =
42192f3ab15Sopenharmony_ci            Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
42292f3ab15Sopenharmony_ci
42392f3ab15Sopenharmony_ci        let signed = pkcs7
42492f3ab15Sopenharmony_ci            .to_smime(message.as_bytes(), flags)
42592f3ab15Sopenharmony_ci            .expect("should succeed");
42692f3ab15Sopenharmony_ci
42792f3ab15Sopenharmony_ci        let (pkcs7_decoded, _) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
42892f3ab15Sopenharmony_ci
42992f3ab15Sopenharmony_ci        let empty_certs = Stack::new().unwrap();
43092f3ab15Sopenharmony_ci        let signer_certs = pkcs7_decoded
43192f3ab15Sopenharmony_ci            .signers(&empty_certs, flags)
43292f3ab15Sopenharmony_ci            .expect("should succeed");
43392f3ab15Sopenharmony_ci        assert_eq!(empty_certs.len(), 0);
43492f3ab15Sopenharmony_ci        assert_eq!(signer_certs.len(), 1);
43592f3ab15Sopenharmony_ci        let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap();
43692f3ab15Sopenharmony_ci        assert_eq!(*cert_digest, *signer_digest);
43792f3ab15Sopenharmony_ci    }
43892f3ab15Sopenharmony_ci
43992f3ab15Sopenharmony_ci    #[test]
44092f3ab15Sopenharmony_ci    fn invalid_from_smime() {
44192f3ab15Sopenharmony_ci        let input = String::from("Invalid SMIME Message");
44292f3ab15Sopenharmony_ci        let result = Pkcs7::from_smime(input.as_bytes());
44392f3ab15Sopenharmony_ci
44492f3ab15Sopenharmony_ci        assert!(result.is_err());
44592f3ab15Sopenharmony_ci    }
44692f3ab15Sopenharmony_ci}
447