summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Sturm <25849945+sturmsebastian@users.noreply.github.com>2019-08-16 11:10:29 +0200
committerSebastian Sturm <25849945+sturmsebastian@users.noreply.github.com>2019-08-16 11:15:04 +0200
commitbdede43afe5485aeeeb01737ff9c2800df11759c (patch)
treea2961d84f340e1e22490ba5745f93845722757b1
parent8b2c370b866807ecdba4f3ae53daf4625b828e0b (diff)
downloadrust-openssl-bdede43afe5485aeeeb01737ff9c2800df11759c.zip
Added support for Ed25519 and Ed448 signatures
-rw-r--r--openssl-sys/src/evp.rs25
-rw-r--r--openssl-sys/src/obj_mac.rs4
-rw-r--r--openssl/src/pkey.rs39
-rw-r--r--openssl/src/sign.rs133
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();