summaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorFlakebi <flakebi@t-online.de>2018-01-14 23:41:11 +0100
committerFlakebi <flakebi@t-online.de>2018-03-19 21:02:46 +0100
commit0860115156bdcb88c2da932114a43fafb71d47fb (patch)
treead39036116e33224232f1a64f93b25146ed1c904 /openssl/src
parent66a2ad76b757606eed85ef6f8a6504aaa96c1af8 (diff)
downloadrust-openssl-0860115156bdcb88c2da932114a43fafb71d47fb.zip
Make it possible to use cmac
This adds Signer::new_without_digest to create Signers which don't have a digest (like cmac, which is based on aes). As openssl supports cmac since version 1.1.0, the functions are behind the ossl110 feature. This allows building CMAC/OMAC1 and the EAX AEAD on top of this library.
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/pkey.rs62
-rw-r--r--openssl/src/sign.rs37
2 files changed, 98 insertions, 1 deletions
diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs
index 66ff33d6..322e6416 100644
--- a/openssl/src/pkey.rs
+++ b/openssl/src/pkey.rs
@@ -365,6 +365,68 @@ impl PKey<Private> {
}
}
+ /// Creates a new `PKey` containing a CMAC key.
+ ///
+ /// CMAC is only supported since the version 1.1.0 of OpenSSL.
+ ///
+ /// # Note
+ ///
+ /// To compute CMAC values, use the `sign` module.
+ #[cfg(any(all(ossl110, feature = "v110"), all(ossl111, feature = "v111")))]
+ pub fn cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
+ unsafe {
+ assert!(key.len() <= c_int::max_value() as usize);
+ let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(
+ ffi::EVP_PKEY_CMAC,
+ ptr::null_mut(),
+ ))?;
+
+ let ret = (|| {
+ cvt(ffi::EVP_PKEY_keygen_init(kctx))?;
+
+ // Set cipher for cmac
+ cvt(ffi::EVP_PKEY_CTX_ctrl(
+ kctx,
+ -1,
+ ffi::EVP_PKEY_OP_KEYGEN,
+ ffi::EVP_PKEY_CTRL_CIPHER,
+ 0,
+ cipher.as_ptr() as *mut _,
+ ))?;
+
+ // Set the key data
+ cvt(ffi::EVP_PKEY_CTX_ctrl(
+ kctx,
+ -1,
+ ffi::EVP_PKEY_OP_KEYGEN,
+ ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
+ key.len() as c_int,
+ key.as_ptr() as *mut _,
+ ))?;
+ Ok(())
+ })();
+
+ if let Err(e) = ret {
+ // Free memory
+ ffi::EVP_PKEY_CTX_free(kctx);
+ return Err(e);
+ }
+
+ // Generate key
+ let mut key = ptr::null_mut();
+ let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
+
+ // Free memory
+ ffi::EVP_PKEY_CTX_free(kctx);
+
+ if let Err(e) = ret {
+ return Err(e);
+ }
+
+ Ok(PKey::from_ptr(key))
+ }
+ }
+
private_key_from_pem! {
/// Deserializes a private key from a PEM-encoded key type specific format.
///
diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs
index 6a49cb49..9270d222 100644
--- a/openssl/src/sign.rs
+++ b/openssl/src/sign.rs
@@ -130,6 +130,26 @@ impl<'a> Signer<'a> {
where
T: HasPrivate,
{
+ Self::new_intern(Some(type_), pkey)
+ }
+
+ /// Creates a new `Signer` without a digest.
+ ///
+ /// This can be used to create a CMAC.
+ /// OpenSSL documentation at [`EVP_DigestSignInit`].
+ ///
+ /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
+ pub fn new_without_digest<T>(pkey: &'a PKeyRef<T>) -> Result<Signer<'a>, ErrorStack>
+ where
+ T: HasPrivate,
+ {
+ Self::new_intern(None, pkey)
+ }
+
+ pub fn new_intern<T>(type_: Option<MessageDigest>, pkey: &'a PKeyRef<T>) -> Result<Signer<'a>, ErrorStack>
+ where
+ T: HasPrivate,
+ {
unsafe {
ffi::init();
@@ -138,7 +158,7 @@ impl<'a> Signer<'a> {
let r = ffi::EVP_DigestSignInit(
ctx,
&mut pctx,
- type_.as_ptr(),
+ type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()),
ptr::null_mut(),
pkey.as_ptr(),
);
@@ -638,6 +658,21 @@ mod test {
test_hmac(MessageDigest::sha1(), &tests);
}
+ #[cfg(ossl110)]
+ #[test]
+ fn test_cmac() {
+ let cipher = ::symm::Cipher::aes_128_cbc();
+ let key = Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap();
+ let pkey = PKey::cmac(&cipher, &key).unwrap();
+ let mut signer = Signer::new_without_digest(&pkey).unwrap();
+
+ let data = b"Hi There";
+ signer.update(data as &[u8]).unwrap();
+
+ let expected = vec![136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19];
+ assert_eq!(signer.sign_to_vec().unwrap(), expected);
+ }
+
#[test]
fn ec() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();