CMS: add encrypt, from_der

This commit is contained in:
tgbit 2019-03-01 23:47:17 +01:00
parent 7602aed0dc
commit 546eb4d391
4 changed files with 87 additions and 0 deletions

View File

@ -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,

View File

@ -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<X509>,
data: &[u8],
cipher: Cipher,
flags: CMSOptions,
) -> Result<CmsContentInfo, ErrorStack>
{
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);
}
}

BIN
openssl/test/cms.p12 Normal file

Binary file not shown.

BIN
openssl/test/cms_pubkey.der Normal file

Binary file not shown.