diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 887359ae..9b49e21b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1465,6 +1465,51 @@ 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; +#[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(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; + // 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) @@ -2856,6 +2901,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: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut 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..6ee62fd0 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -9,11 +9,42 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use std::ptr; -use {cvt, cvt_p}; 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 : 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; + #[cfg(all(not(libressl), not(ossl101)))] + const KEY_PARAM = ffi::CMS_KEY_PARAM; + #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] + const ASCIICRLF = ffi::CMS_ASCIICRLF; + } +} foreign_type_and_impl_send_sync! { type CType = ffi::CMS_ContentInfo; @@ -63,6 +94,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 { @@ -80,4 +121,49 @@ impl CmsContentInfo { Ok(CmsContentInfo::from_ptr(cms)) } } + + /// 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: Option<&X509>, + pkey: Option<&PKeyRef>, + certs: Option<&Stack>, + data: Option<&[u8]>, + flags: CMSOptions, + ) -> Result { + unsafe { + 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.bits(), + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } }