diff options
-rw-r--r-- | openssl-sys/src/lib.rs | 9 | ||||
-rw-r--r-- | openssl/src/pkey.rs | 62 | ||||
-rw-r--r-- | openssl/src/sign.rs | 37 |
3 files changed, 107 insertions, 1 deletions
diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 331479ed..d5406e1f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -221,6 +221,7 @@ pub const PEM_R_NO_START_LINE: c_int = 108; pub const EVP_MAX_MD_SIZE: c_uint = 64; pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; +pub const EVP_PKEY_CMAC: c_int = NID_cmac; pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; @@ -233,6 +234,10 @@ pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2; pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; +pub const EVP_PKEY_CTRL_SET_MAC_KEY: c_int = 6; +pub const EVP_PKEY_CTRL_CIPHER: c_int = 12; + +pub const EVP_PKEY_OP_KEYGEN: c_int = 1 << 2; pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3; pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4; pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5; @@ -2093,6 +2098,7 @@ extern "C" { ) -> *mut EVP_PKEY; pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; + pub fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX); pub fn EVP_PKEY_CTX_ctrl( ctx: *mut EVP_PKEY_CTX, @@ -2103,6 +2109,9 @@ extern "C" { p2: *mut c_void, ) -> c_int; + pub fn EVP_PKEY_keygen_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int; + pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int; 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(); |