diff --git a/openssl-sys/src/cms.rs b/openssl-sys/src/cms.rs index 26bc9497..b310ceab 100644 --- a/openssl-sys/src/cms.rs +++ b/openssl-sys/src/cms.rs @@ -1,4 +1,5 @@ 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, diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 9ddd9309..45f4dd65 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -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, + data: &[u8], + cipher: Cipher, + flags: CMSOptions, + ) -> Result + { + 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); + } } diff --git a/openssl/test/cms.p12 b/openssl/test/cms.p12 new file mode 100644 index 00000000..c4f96b69 Binary files /dev/null and b/openssl/test/cms.p12 differ diff --git a/openssl/test/cms_pubkey.der b/openssl/test/cms_pubkey.der new file mode 100644 index 00000000..7efd440f Binary files /dev/null and b/openssl/test/cms_pubkey.der differ