diff options
author | Sebastian Sturm <25849945+sturmsebastian@users.noreply.github.com> | 2019-08-16 11:10:29 +0200 |
---|---|---|
committer | Sebastian Sturm <25849945+sturmsebastian@users.noreply.github.com> | 2019-08-16 11:15:04 +0200 |
commit | bdede43afe5485aeeeb01737ff9c2800df11759c (patch) | |
tree | a2961d84f340e1e22490ba5745f93845722757b1 | |
parent | 8b2c370b866807ecdba4f3ae53daf4625b828e0b (diff) | |
download | rust-openssl-bdede43afe5485aeeeb01737ff9c2800df11759c.zip |
Added support for Ed25519 and Ed448 signatures
-rw-r--r-- | openssl-sys/src/evp.rs | 25 | ||||
-rw-r--r-- | openssl-sys/src/obj_mac.rs | 4 | ||||
-rw-r--r-- | openssl/src/pkey.rs | 39 | ||||
-rw-r--r-- | openssl/src/sign.rs | 133 |
4 files changed, 199 insertions, 2 deletions
diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs index 4ab210bb..140e6a36 100644 --- a/openssl-sys/src/evp.rs +++ b/openssl-sys/src/evp.rs @@ -10,6 +10,10 @@ pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; 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; +#[cfg(ossl111)] +pub const EVP_PKEY_ED25519: c_int = NID_ED25519; +#[cfg(ossl111)] +pub const EVP_PKEY_ED448: c_int = NID_ED448; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_CMAC: c_int = NID_cmac; @@ -154,6 +158,27 @@ cfg_if! { } } cfg_if! { + if #[cfg(ossl111)] { + extern "C" { + pub fn EVP_DigestSign( + ctx: *mut EVP_MD_CTX, + sigret: *mut c_uchar, + siglen: *mut size_t, + tbs: *const c_uchar, + tbslen: size_t + ) -> c_int; + + pub fn EVP_DigestVerify( + ctx: *mut EVP_MD_CTX, + sigret: *const c_uchar, + siglen: size_t, + tbs: *const c_uchar, + tbslen: size_t + ) -> c_int; + } + } +} +cfg_if! { if #[cfg(any(ossl102, libressl280))] { extern "C" { pub fn EVP_DigestVerifyFinal( diff --git a/openssl-sys/src/obj_mac.rs b/openssl-sys/src/obj_mac.rs index 60c5767d..e348f341 100644 --- a/openssl-sys/src/obj_mac.rs +++ b/openssl-sys/src/obj_mac.rs @@ -912,3 +912,7 @@ pub const NID_rc4_hmac_md5: c_int = 915; pub const NID_aes_128_cbc_hmac_sha1: c_int = 916; pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; +#[cfg(ossl111)] +pub const NID_ED25519: c_int = 1087; +#[cfg(ossl111)] +pub const NID_ED448: c_int = 1088; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 0b562d74..f05f5f15 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -90,6 +90,11 @@ impl Id { pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); pub const EC: Id = Id(ffi::EVP_PKEY_EC); + + #[cfg(ossl111)] + pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); + #[cfg(ossl111)] + pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); } /// A trait indicating that a key has parameters. @@ -426,6 +431,40 @@ impl PKey<Private> { } } + #[cfg(ossl110)] + fn generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack> { + unsafe { + let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?; + let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx)); + if let Err(e) = ret { + ffi::EVP_PKEY_CTX_free(kctx); + return Err(e); + } + let mut key = ptr::null_mut(); + let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key)); + + ffi::EVP_PKEY_CTX_free(kctx); + + if let Err(e) = ret { + return Err(e); + } + + Ok(PKey::from_ptr(key)) + } + } + + /// Generates a new private Ed25519 key + #[cfg(ossl111)] + pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> { + PKey::generate_eddsa(ffi::EVP_PKEY_ED25519) + } + + /// Generates a new private Ed448 key + #[cfg(ossl111)] + pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> { + PKey::generate_eddsa(ffi::EVP_PKEY_ED448) + } + 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 a3a58bfe..633d77ac 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -126,6 +126,9 @@ impl<'a> Drop for Signer<'a> { impl<'a> Signer<'a> { /// Creates a new `Signer`. /// + /// This cannot be used with Ed25519 or Ed448 keys. Please refer to + /// `new_without_digest`. + /// /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html @@ -138,7 +141,9 @@ impl<'a> Signer<'a> { /// Creates a new `Signer` without a digest. /// - /// This can be used to create a CMAC. + /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. + /// It can also be used to create a CMAC. + /// /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html @@ -249,6 +254,9 @@ impl<'a> Signer<'a> { /// Feeds more data into the `Signer`. /// + /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. + /// Use `sign_oneshot` instead. + /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html @@ -271,6 +279,7 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + #[cfg(not(ossl111))] pub fn len(&self) -> Result<usize, ErrorStack> { unsafe { let mut len = 0; @@ -283,6 +292,21 @@ impl<'a> Signer<'a> { } } + #[cfg(ossl111)] + pub fn len(&self) -> Result<usize, ErrorStack> { + unsafe { + let mut len = 0; + cvt(ffi::EVP_DigestSign( + self.md_ctx, + ptr::null_mut(), + &mut len, + ptr::null(), + 0 + ))?; + Ok(len) + } + } + /// Writes the signature into the provided buffer, returning the number of bytes written. /// /// This method will fail if the buffer is not large enough for the signature. Use the `len` @@ -313,6 +337,44 @@ impl<'a> Signer<'a> { buf.truncate(len); Ok(buf) } + + /// Signs the data in data_buf and writes the siganture into the buffer sig_buf, returning the + /// number of bytes written. + /// + /// For PureEdDSA (Ed25519 and Ed448 keys) this is the only way to sign data. + /// + /// This method will fail if the buffer is not large enough for the signature. Use the `len` + /// method to get an upper bound on the required size. + /// + /// OpenSSL documentation at [`EVP_DigestSign`]. + /// + /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html + #[cfg(ossl111)] + pub fn sign_oneshot(&self, sig_buf: &mut [u8], data_buf: &[u8]) -> Result<usize, ErrorStack> { + unsafe { + let mut sig_len = sig_buf.len(); + cvt(ffi::EVP_DigestSign( + self.md_ctx, + sig_buf.as_mut_ptr() as *mut _, + &mut sig_len, + data_buf.as_ptr() as *const _, + data_buf.len() + ))?; + Ok(sig_len) + } + } + + /// Returns the signature. + /// + /// This is a simple convenience wrapper over `len` and `sign_oneshot`. + #[cfg(ossl111)] + pub fn sign_oneshot_to_vec(&self, data_buf: &[u8]) -> Result<Vec<u8>, ErrorStack> { + let mut sig_buf = vec![0; self.len()?]; + let len = self.sign_oneshot(&mut sig_buf, data_buf)?; + // The advertised length is not always equal to the real length for things like DSA + sig_buf.truncate(len); + Ok(sig_buf) + } } impl<'a> Write for Signer<'a> { @@ -348,6 +410,9 @@ impl<'a> Drop for Verifier<'a> { impl<'a> Verifier<'a> { /// Creates a new `Verifier`. /// + /// This cannot be used with Ed25519 or Ed448 keys. Please refer to + /// `new_without_digest`. + /// /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. /// /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html @@ -355,6 +420,28 @@ impl<'a> Verifier<'a> { where T: HasPublic, { + Verifier::new_intern(Some(type_), pkey) + } + + /// Creates a new `Verifier` without a digest. + /// + /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. + /// + /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. + /// + /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html + pub fn new_without_digest<T>(pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack> + where + T: HasPublic + { + Verifier::new_intern(None, pkey) + } + + + fn new_intern<T>(type_: Option<MessageDigest>, pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack> + where + T: HasPublic, + { unsafe { ffi::init(); @@ -363,7 +450,7 @@ impl<'a> Verifier<'a> { let r = ffi::EVP_DigestVerifyInit( ctx, &mut pctx, - type_.as_ptr(), + type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()), ptr::null_mut(), pkey.as_ptr(), ); @@ -448,6 +535,9 @@ impl<'a> Verifier<'a> { /// Feeds more data into the `Verifier`. /// + /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. + /// Use `verify_oneshot` instead. + /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html @@ -481,6 +571,32 @@ impl<'a> Verifier<'a> { } } } + + /// Determines if the data given in buf matches the provided signature. + /// + /// OpenSSL documentation at [`EVP_DigestVerify`]. + /// + /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html + #[cfg(ossl111)] + pub fn verify_oneshot(&self, signature: &[u8], buf: &[u8]) -> Result<bool, ErrorStack> { + unsafe { + let r = ffi::EVP_DigestVerify( + self.md_ctx, + signature.as_ptr() as *const _, + signature.len(), + buf.as_ptr() as *const _, + buf.len(), + ); + match r { + 1 => Ok(true), + 0 => { + ErrorStack::get(); + Ok(false) + }, + _ => Err(ErrorStack::get()), + } + } + } } impl<'a> Write for Verifier<'a> { @@ -705,6 +821,19 @@ mod test { } #[test] + #[cfg(ossl111)] + fn eddsa() { + let key = PKey::generate_ed25519().unwrap(); + + let signer = Signer::new_without_digest(&key).unwrap(); + let signature = signer.sign_oneshot_to_vec(b"hello world").unwrap(); + + let verifier = Verifier::new_without_digest(&key).unwrap(); + assert!(verifier.verify_oneshot(&signature, b"hello world").unwrap()); + } + + #[test] + #[cfg(ossl111)] fn rsa_sign_verify() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); |