From 8ce5dee00d1f7658e0790b60dfcb86d4b2f81621 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Fri, 20 Apr 2018 17:15:04 +0530 Subject: [PATCH 1/7] Add the CMS_sign and i2d_CMS_ContentInfo function bindings This adds the CMS_sign and i2d_CMS_ContentInfo bindings in the openssl-sys crate and Rusty wrappers in the openssl crate. --- openssl-sys/src/lib.rs | 12 +++++++++- openssl/src/cms.rs | 50 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 85527f8f..42bd8268 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -5,8 +5,8 @@ extern crate libc; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t, FILE}; -use std::ptr; use std::mem; +use std::ptr; #[cfg(any(ossl101, ossl102))] mod ossl10x; @@ -2846,6 +2846,16 @@ extern "C" { pub fn SMIME_read_CMS(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut CMS_ContentInfo; #[cfg(not(libressl))] pub fn CMS_ContentInfo_free(cms: *mut CMS_ContentInfo); + #[cfg(not(libressl))] + pub fn CMS_sign( + signcert: *const X509, + pkey: *const EVP_PKEY, + certs: *const stack_st_X509, + data: *mut BIO, + flags: c_uint, + ) -> *mut CMS_ContentInfo; + #[cfg(not(libressl))] + pub fn i2d_CMS_ContentInfo(a: *mut CMS_ContentInfo, pp: *mut *mut c_uchar) -> c_int; #[cfg(not(libressl))] pub fn FIPS_mode_set(onoff: c_int) -> c_int; diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 8c60455c..b549e066 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -9,11 +9,12 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use std::ptr; -use {cvt, cvt_p}; use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use pkey::{HasPrivate, PKeyRef}; +use stack::Stack; use x509::X509; +use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::CMS_ContentInfo; @@ -80,4 +81,51 @@ impl CmsContentInfo { Ok(CmsContentInfo::from_ptr(cms)) } } + + /// Given a signing cert `signcert`, private key `pkey`, an optional certificate stack `certs`, + /// data `data` and flags `flags`, create a CmsContentInfo struct. + /// + /// OpenSSL documentation at [`CMS_sign`] + /// + /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html + pub fn sign( + signcert: &X509, + pkey: &PKeyRef, + certs: Option<&Stack>, + data: &[u8], + flags: u32, + ) -> Result { + unsafe { + let signcert = signcert.as_ptr(); + let pkey = pkey.as_ptr(); + let data_bio = MemBioSlice::new(data)?; + let cms = cvt_p(ffi::CMS_sign( + signcert, + pkey, + certs.unwrap_or(&Stack::::new()?).as_ptr(), + data_bio.as_ptr(), + flags, + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } + + /// Serializes this CmsContentInfo using DER. + /// + /// OpenSSL documentation at [`i2d_CMS_ContentInfo`] + /// + /// [`i2d_CMS_ContentInfo`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_CMS_ContentInfo.html + pub fn to_der(&mut self) -> Result, ErrorStack> { + unsafe { + let size = ffi::i2d_CMS_ContentInfo(self.as_ptr(), ptr::null_mut()); + let mut der = vec![0u8; size as usize]; + + let raw_ptr = Box::into_raw(Box::new(der.as_mut_ptr())); + ffi::i2d_CMS_ContentInfo(self.as_ptr(), raw_ptr); + + Box::from_raw(raw_ptr); + Ok(der) + } + } } From 5360f5ad04ff879cce1c4bbd32b076841324dcd3 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Fri, 20 Apr 2018 17:30:20 +0530 Subject: [PATCH 2/7] Fix mutability issues with CMS_sign --- openssl-sys/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 42bd8268..e5330b93 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2848,9 +2848,9 @@ extern "C" { pub fn CMS_ContentInfo_free(cms: *mut CMS_ContentInfo); #[cfg(not(libressl))] pub fn CMS_sign( - signcert: *const X509, - pkey: *const EVP_PKEY, - certs: *const stack_st_X509, + signcert: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut stack_st_X509, data: *mut BIO, flags: c_uint, ) -> *mut CMS_ContentInfo; From 13caf731a2e1a911ceba03b791554bf6884a0577 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Sun, 22 Apr 2018 10:57:09 +0530 Subject: [PATCH 3/7] Implement CR suggestions * Don't do un-necessary heap pointer gymnastics * Use the to_der! macro instead of a manually written impl * Allow optional arguments for CMS_sign --- openssl/src/cms.rs | 66 ++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index b549e066..ca43078d 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -64,6 +64,16 @@ impl CmsContentInfoRef { Ok(out.get_buf().to_owned()) } } + + to_der! { + /// Serializes this CmsContentInfo using DER. + /// + /// OpenSSL documentation at [`i2d_CMS_ContentInfo`] + /// + /// [`i2d_CMS_ContentInfo`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_CMS_ContentInfo.html + to_der, + ffi::i2d_CMS_ContentInfo + } } impl CmsContentInfo { @@ -82,50 +92,42 @@ impl CmsContentInfo { } } - /// Given a signing cert `signcert`, private key `pkey`, an optional certificate stack `certs`, + /// Given a signing cert `signcert`, private key `pkey`, a certificate stack `certs`, /// data `data` and flags `flags`, create a CmsContentInfo struct. /// + /// All arguments are optional. + /// /// OpenSSL documentation at [`CMS_sign`] /// /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html pub fn sign( - signcert: &X509, - pkey: &PKeyRef, + signcert: Option<&X509>, + pkey: Option<&PKeyRef>, certs: Option<&Stack>, - data: &[u8], + data: Option<&[u8]>, flags: u32, ) -> Result { unsafe { - let signcert = signcert.as_ptr(); - let pkey = pkey.as_ptr(); - let data_bio = MemBioSlice::new(data)?; - let cms = cvt_p(ffi::CMS_sign( - signcert, - pkey, - certs.unwrap_or(&Stack::::new()?).as_ptr(), - data_bio.as_ptr(), - flags, - ))?; + let signcert = match signcert { + Some(cert) => cert.as_ptr(), + None => ptr::null_mut(), + }; + let pkey = match pkey { + Some(pkey) => pkey.as_ptr(), + None => ptr::null_mut(), + }; + let data_bio_ptr = match data { + Some(data) => MemBioSlice::new(data)?.as_ptr(), + None => ptr::null_mut(), + }; + let certs = match certs { + Some(certs) => certs.as_ptr(), + None => ptr::null_mut(), + }; + + let cms = cvt_p(ffi::CMS_sign(signcert, pkey, certs, data_bio_ptr, flags))?; Ok(CmsContentInfo::from_ptr(cms)) } } - - /// Serializes this CmsContentInfo using DER. - /// - /// OpenSSL documentation at [`i2d_CMS_ContentInfo`] - /// - /// [`i2d_CMS_ContentInfo`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_CMS_ContentInfo.html - pub fn to_der(&mut self) -> Result, ErrorStack> { - unsafe { - let size = ffi::i2d_CMS_ContentInfo(self.as_ptr(), ptr::null_mut()); - let mut der = vec![0u8; size as usize]; - - let raw_ptr = Box::into_raw(Box::new(der.as_mut_ptr())); - ffi::i2d_CMS_ContentInfo(self.as_ptr(), raw_ptr); - - Box::from_raw(raw_ptr); - Ok(der) - } - } } From 043ad63a5233d4400e741cd013985115b9f489ab Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Thu, 26 Apr 2018 09:15:29 +0530 Subject: [PATCH 4/7] Use bitflags for CMS options --- openssl/src/cms.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index ca43078d..66d52955 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -16,6 +16,33 @@ use stack::Stack; use x509::X509; use {cvt, cvt_p}; +bitflags! { + pub struct CMSOptions : u32 { + const CMS_TEXT = 0x1; + const CMS_NOCERTS = 0x2; + const CMS_NO_CONTENT_VERIFY = 0x4; + const CMS_NO_ATTR_VERIFY = 0x8; + const CMS_NOSIGS = 0x4 | 0x8; + const CMS_NOINTERN = 0x10; + const CMS_NO_SIGNER_CERT_VERIFY = 0x20; + const CMS_NOVERIFY = 0x20; + const CMS_DETACHED = 0x40; + const CMS_BINARY = 0x80; + const CMS_NOATTR = 0x100; + const CMS_NOSMIMECAP = 0x200; + const CMS_NOOLDMIMETYPE = 0x400; + const CMS_CRLFEOL = 0x800; + const CMS_STREAM = 0x1000; + const CMS_NOCRL = 0x2000; + const CMS_PARTIAL = 0x4000; + const CMS_REUSE_DIGEST = 0x8000; + const CMS_USE_KEYID = 0x10000; + const CMS_DEBUG_DECRYPT = 0x20000; + const CMS_KEY_PARAM = 0x40000; + const CMS_ASCIICRLF = 0x80000; + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::CMS_ContentInfo; fn drop = ffi::CMS_ContentInfo_free; @@ -105,7 +132,7 @@ impl CmsContentInfo { pkey: Option<&PKeyRef>, certs: Option<&Stack>, data: Option<&[u8]>, - flags: u32, + flags: CMSOptions, ) -> Result { unsafe { let signcert = match signcert { @@ -125,7 +152,7 @@ impl CmsContentInfo { None => ptr::null_mut(), }; - let cms = cvt_p(ffi::CMS_sign(signcert, pkey, certs, data_bio_ptr, flags))?; + let cms = cvt_p(ffi::CMS_sign(signcert, pkey, certs, data_bio_ptr, flags.bits()))?; Ok(CmsContentInfo::from_ptr(cms)) } From 90898e99c996bc661daa16d8640479101906cc73 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Thu, 10 May 2018 20:26:57 +0530 Subject: [PATCH 5/7] Move CMS_* flags to the openssl-sys package Also renames attributes in the bitflags struct. --- openssl-sys/src/lib.rs | 24 ++++++++++++++++++ openssl/src/cms.rs | 55 ++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e5330b93..4b9c4cb8 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1465,6 +1465,30 @@ pub const GEN_RID: c_int = 8; pub const DTLS1_COOKIE_LENGTH: c_uint = 256; +#[cfg(not(libressl))] +pub const CMS_TEXT: c_uint = 0x1; +pub const CMS_NOCERTS: c_uint = 0x2; +pub const CMS_NO_CONTENT_VERIFY: c_uint = 0x4; +pub const CMS_NO_ATTR_VERIFY: c_uint = 0x8; +pub const CMS_NOSIGS: c_uint = 0x4 | 0x8; +pub const CMS_NOINTERN: c_uint = 0x10; +pub const CMS_NO_SIGNER_CERT_VERIFY: c_uint = 0x20; +pub const CMS_NOVERIFY: c_uint = 0x20; +pub const CMS_DETACHED: c_uint = 0x40; +pub const CMS_BINARY: c_uint = 0x80; +pub const CMS_NOATTR: c_uint = 0x100; +pub const CMS_NOSMIMECAP: c_uint = 0x200; +pub const CMS_NOOLDMIMETYPE: c_uint = 0x400; +pub const CMS_CRLFEOL: c_uint = 0x800; +pub const CMS_STREAM: c_uint = 0x1000; +pub const CMS_NOCRL: c_uint = 0x2000; +pub const CMS_PARTIAL: c_uint = 0x4000; +pub const CMS_REUSE_DIGEST: c_uint = 0x8000; +pub const CMS_USE_KEYID: c_uint = 0x10000; +pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; +pub const CMS_KEY_PARAM: c_uint = 0x40000; +pub const CMS_ASCIICRLF: c_uint = 0x80000; + // macros pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 66d52955..1884c568 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -11,35 +11,36 @@ use std::ptr; use bio::{MemBio, MemBioSlice}; use error::ErrorStack; +use libc::c_uint; use pkey::{HasPrivate, PKeyRef}; use stack::Stack; use x509::X509; use {cvt, cvt_p}; bitflags! { - pub struct CMSOptions : u32 { - const CMS_TEXT = 0x1; - const CMS_NOCERTS = 0x2; - const CMS_NO_CONTENT_VERIFY = 0x4; - const CMS_NO_ATTR_VERIFY = 0x8; - const CMS_NOSIGS = 0x4 | 0x8; - const CMS_NOINTERN = 0x10; - const CMS_NO_SIGNER_CERT_VERIFY = 0x20; - const CMS_NOVERIFY = 0x20; - const CMS_DETACHED = 0x40; - const CMS_BINARY = 0x80; - const CMS_NOATTR = 0x100; - const CMS_NOSMIMECAP = 0x200; - const CMS_NOOLDMIMETYPE = 0x400; - const CMS_CRLFEOL = 0x800; - const CMS_STREAM = 0x1000; - const CMS_NOCRL = 0x2000; - const CMS_PARTIAL = 0x4000; - const CMS_REUSE_DIGEST = 0x8000; - const CMS_USE_KEYID = 0x10000; - const CMS_DEBUG_DECRYPT = 0x20000; - const CMS_KEY_PARAM = 0x40000; - const CMS_ASCIICRLF = 0x80000; + pub struct CMSOptions : c_uint { + const TEXT = ffi::CMS_TEXT; + const CMS_NOCERTS = ffi::CMS_NOCERTS; + const NO_CONTENT_VERIFY = ffi::CMS_NO_CONTENT_VERIFY; + const NO_ATTR_VERIFY = ffi::CMS_NO_ATTR_VERIFY; + const NOSIGS = ffi::CMS_NOSIGS; + const NOINTERN = ffi::CMS_NOINTERN; + const NO_SIGNER_CERT_VERIFY = ffi::CMS_NO_SIGNER_CERT_VERIFY; + const NOVERIFY = ffi::CMS_NOVERIFY; + const DETACHED = ffi::CMS_DETACHED; + const BINARY = ffi::CMS_BINARY; + const NOATTR = ffi::CMS_NOATTR; + const NOSMIMECAP = ffi::CMS_NOSMIMECAP; + const NOOLDMIMETYPE = ffi::CMS_NOOLDMIMETYPE; + const CRLFEOL = ffi::CMS_CRLFEOL; + const STREAM = ffi::CMS_STREAM; + const NOCRL = ffi::CMS_NOCRL; + const PARTIAL = ffi::CMS_PARTIAL; + const REUSE_DIGEST = ffi::CMS_REUSE_DIGEST; + const USE_KEYID = ffi::CMS_USE_KEYID; + const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; + const KEY_PARAM = ffi::CMS_KEY_PARAM; + const ASCIICRLF = ffi::CMS_ASCIICRLF; } } @@ -152,7 +153,13 @@ impl CmsContentInfo { None => ptr::null_mut(), }; - let cms = cvt_p(ffi::CMS_sign(signcert, pkey, certs, data_bio_ptr, flags.bits()))?; + let cms = cvt_p(ffi::CMS_sign( + signcert, + pkey, + certs, + data_bio_ptr, + flags.bits(), + ))?; Ok(CmsContentInfo::from_ptr(cms)) } From 541458c1c165ef1bbc6f9b949f9956fcf3c37ae6 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Thu, 10 May 2018 20:48:38 +0530 Subject: [PATCH 6/7] Properly version-gate CMS constants --- openssl-sys/src/lib.rs | 21 +++++++++++++++++++++ openssl/src/cms.rs | 1 + 2 files changed, 22 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 4b9c4cb8..b07d5ab6 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1467,26 +1467,47 @@ pub const DTLS1_COOKIE_LENGTH: c_uint = 256; #[cfg(not(libressl))] pub const CMS_TEXT: c_uint = 0x1; +#[cfg(not(libressl))] pub const CMS_NOCERTS: c_uint = 0x2; +#[cfg(not(libressl))] pub const CMS_NO_CONTENT_VERIFY: c_uint = 0x4; +#[cfg(not(libressl))] pub const CMS_NO_ATTR_VERIFY: c_uint = 0x8; +#[cfg(not(libressl))] pub const CMS_NOSIGS: c_uint = 0x4 | 0x8; +#[cfg(not(libressl))] pub const CMS_NOINTERN: c_uint = 0x10; +#[cfg(not(libressl))] pub const CMS_NO_SIGNER_CERT_VERIFY: c_uint = 0x20; +#[cfg(not(libressl))] pub const CMS_NOVERIFY: c_uint = 0x20; +#[cfg(not(libressl))] pub const CMS_DETACHED: c_uint = 0x40; +#[cfg(not(libressl))] pub const CMS_BINARY: c_uint = 0x80; +#[cfg(not(libressl))] pub const CMS_NOATTR: c_uint = 0x100; +#[cfg(not(libressl))] pub const CMS_NOSMIMECAP: c_uint = 0x200; +#[cfg(not(libressl))] pub const CMS_NOOLDMIMETYPE: c_uint = 0x400; +#[cfg(not(libressl))] pub const CMS_CRLFEOL: c_uint = 0x800; +#[cfg(not(libressl))] pub const CMS_STREAM: c_uint = 0x1000; +#[cfg(not(libressl))] pub const CMS_NOCRL: c_uint = 0x2000; +#[cfg(not(libressl))] pub const CMS_PARTIAL: c_uint = 0x4000; +#[cfg(not(libressl))] pub const CMS_REUSE_DIGEST: c_uint = 0x8000; +#[cfg(not(libressl))] pub const CMS_USE_KEYID: c_uint = 0x10000; +#[cfg(not(libressl))] pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; +#[cfg(not(libressl))] pub const CMS_KEY_PARAM: c_uint = 0x40000; +#[cfg(all(not(libressl), not(ossl101), not(ossl102)))] pub const CMS_ASCIICRLF: c_uint = 0x80000; // macros diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 1884c568..0583d086 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -40,6 +40,7 @@ bitflags! { const USE_KEYID = ffi::CMS_USE_KEYID; const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; const KEY_PARAM = ffi::CMS_KEY_PARAM; + #[cfg(all(not(libressl), any(ossl101, ossl102)))] const ASCIICRLF = ffi::CMS_ASCIICRLF; } } From afaa2387c89a6e7d2d8c2ee05d4ecb605b5188e1 Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Thu, 10 May 2018 21:33:51 +0530 Subject: [PATCH 7/7] Gate away CMS_KEY_PARAM from OpenSSL 1.0.1 --- openssl-sys/src/lib.rs | 2 +- openssl/src/cms.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index b07d5ab6..de24d94e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1505,7 +1505,7 @@ pub const CMS_REUSE_DIGEST: c_uint = 0x8000; pub const CMS_USE_KEYID: c_uint = 0x10000; #[cfg(not(libressl))] pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; -#[cfg(not(libressl))] +#[cfg(all(not(libressl), not(ossl101)))] pub const CMS_KEY_PARAM: c_uint = 0x40000; #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] pub const CMS_ASCIICRLF: c_uint = 0x80000; diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 0583d086..6ee62fd0 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -39,8 +39,9 @@ bitflags! { const REUSE_DIGEST = ffi::CMS_REUSE_DIGEST; const USE_KEYID = ffi::CMS_USE_KEYID; const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; + #[cfg(all(not(libressl), not(ossl101)))] const KEY_PARAM = ffi::CMS_KEY_PARAM; - #[cfg(all(not(libressl), any(ossl101, ossl102)))] + #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] const ASCIICRLF = ffi::CMS_ASCIICRLF; } }