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