From 546eb4d39185882cacafae356c237fcad8bc88f6 Mon Sep 17 00:00:00 2001 From: tgbit Date: Fri, 1 Mar 2019 23:47:17 +0100 Subject: [PATCH] CMS: add encrypt, from_der --- openssl-sys/src/cms.rs | 12 ++++++ openssl/src/cms.rs | 75 ++++++++++++++++++++++++++++++++++++ openssl/test/cms.p12 | Bin 0 -> 1709 bytes openssl/test/cms_pubkey.der | Bin 0 -> 688 bytes 4 files changed, 87 insertions(+) create mode 100644 openssl/test/cms.p12 create mode 100644 openssl/test/cms_pubkey.der 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 0000000000000000000000000000000000000000..c4f96b6996e41e31fb19f982c59a8a0fad90462b GIT binary patch literal 1709 zcmY+DdpHvcAIEpIHn+LVn7c`1ZjY9B3L8 zjw|#n{HOuk1r&0iF%S;)#10O_bHLQUBB+o9_T5255D>7l2!AC&yfIYuKOfYAP`oAt z=CNcSqgcI!0fAtEd=6NvkuSk#s^qLM4fYzT)`$021R*6ukUX`nrU1JEH}>)EcXsPU zg-pBTda9))RCK2vRGlO@C4X=}LG)fw)ak9vetvfTIiVe5fs44L(O_&^APyl<8H2um z()M+}wK5_tWSivIzB1+y{08i}oay!IU`&+gG~RO}#Y-U1Om0q}hW={fW^6h#v{~xx z8S5N`?hw^s`;}VGNFyH&Ugsls9JM($cUxB6`iY3xFnW-fXN%$rCE*tOXX*8mD@R7- zcgH-zWng89$T`JdgjDip{Gy zpX^#5_(y<8O4lQ&nNiSzxI1mJC1b93beM~-0;!)K43}<3}rqxg-&UbyI3c!nC!e%y2r)*oJKjT9i>8QHCsB0kjp(^Fd{UX%*W9lcE>ljVg@lT`mjduj) z*)8@MFr9zVW;5%?=IMUsi}gTWf+p=5t!`I8D51Hg?Vhu8;=8wTKMMrcbgI3KS~5=Z z#YF^~eM78DG>KZ1Mpa*29`^2g;|)YdM@;Trg(Y5uS13P5!}-2a&5^;b!>tR`iScVQ z-5+}jLH(8aXe+(#{f1S@qJ`z%*dyg+?e{paXhnR4Hh>0azO7O9FTkm&+p7ERPDbysRBVeVdD-I{mnA)7t1=+ z^B=lGy?9?N+d0oaU_0b)ax1tmaZ2e|nTyw{yclv)YX9A`y16cePjcf=)i)yUoME(% zGLgM%MVXVdm{7ydL1GpkeB6)M3iB|tKDyMhIFgZG$IY6?jXG+?Rc2UaxhLInU#r0( z`AKvD%1qQJ&Pz7nYX_A{*G>K0jKWqJgPfLvaXJn&r}hH8EFdxx1|)I2uWB@|Ell>O zdJaBu!JG;>RLkA6HJiB5G<=XW+}0Cv=<`h+fwZMNeu$-QuuA{n@0PA5dOw1=Q8rjj zQ9qwYW}%}ZW|AR1^SR4Bl7Cb&ys7EO>eGyy^VpYC0O}*LfnF)&e!z;U^GQI}Dwc!K z3#b*jYdfs!L?;K}LhWA8QGeBcqaB?`mA+-n%#J zl~ZoBX$$H+!}IhG8w!9;H96`CvrrqW)rt<$?Rgi=HHTkdI@V=u z>1Yq|sZ~AR*Uk16r)P(G62i=6>5VMYZvE~a4EG!KD%im{VY)2pbMm6ya}y82?Ua3p zhv$X{mvT=8zF%oa6cofy2*T#Dwfpn+Sdzj8Zt3+bvYS*~IAJ^n5-x_R0LMRo0 z*RJi%s2aTo%o-wA4;W4_x0Z;fbmW`+!GK1S1>L6m)4Q{(F>n55&vpxtNi7g*_sSz% z>RuhWweS)?H)7~#ATZgSWP1ep$hX(>7A<5s$3U~Cj)!5a;n+ijz$zd(576gUcP4Q3 z9QMrEL}XoK>)X4QWhHyrP1Ox9Ni0b<6g3bA33Bo95k8Ii+zvawsseGB7vx zG8i;=GBq|b91ixXOq=@5P_p*Z{*#&#i#~3ZJixg5*=_$P7iAJ;+nD`Uu_yjsdvVS6 zO}84OSf1#Ko%?t(ZPTQ4euL*)v6 z{2w!J@V~k2me-m_xvs!&(Fm?xT(i7({F*E3xc@@cq3p9KYfmdxGBGnUFfI-@2sDrd zhPf;six`WDZQI)&OWtkB6}P{#&E7M4+S3PZiU#r^X=N4(1F;6|3iv?^gc%wCv#=U4 z11V%b17n^U=vh`@iLz7ean;Xlr)T>0)rr*|(A&(qcs+CQvaBLCf%Yq+OH^_~nm+2N zzURr`6Y=@W+j-lRPJa+zHR+az%5>*XtSgpU`RXn6wf->mf0yT?-O+#E`UbVG@VG2+ tW?ACCKBeQVC4U&%Q=dw1?Y^TnvwffI2CFTpMrSMo9ruMg_=E&x0|0_v@QnZf literal 0 HcmV?d00001