diff --git a/openssl-sys/src/ssl.rs b/openssl-sys/src/ssl.rs index a951e90bbf24703a3ccf1d1489bb1411bac95781..df9f571897bcdf7f99a3ece53be5ca918189ad30 100644 --- a/openssl-sys/src/ssl.rs +++ b/openssl-sys/src/ssl.rs @@ -876,6 +876,10 @@ extern "C" { #[cfg(ossl111)] pub fn SSL_CIPHER_get_handshake_digest(cipher: *const ::SSL_CIPHER) -> *const ::EVP_MD; pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn SSL_CIPHER_standard_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn OPENSSL_cipher_name(rfc_name: *const c_char) -> *const c_char; pub fn SSL_pending(ssl: *const SSL) -> c_int; pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cc98be14f66039afdb9dd6fe70b1d4cefc3d06f1..c78b7f668e7c63391242be15243258fb10f26202 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -113,6 +113,28 @@ mod error; #[cfg(test)] mod test; +/// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name. +/// +/// Requires OpenSSL 1.1.1 or newer. +/// +/// This corresponds to [`OPENSSL_cipher_name`] +/// +/// [`OPENSSL_cipher_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html +#[cfg(ossl111)] +pub fn cipher_name(std_name: &str) -> Option<&'static str> { + unsafe { + ffi::init(); + + let s = CString::new(std_name).unwrap(); + let ptr = ffi::OPENSSL_cipher_name(s.as_ptr()); + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } +} + bitflags! { /// Options controlling the behavior of an `SslContext`. pub struct SslOptions: c_ulong { @@ -1880,12 +1902,29 @@ impl SslCipherRef { /// /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn name(&self) -> &'static str { - let name = unsafe { + unsafe { let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); - CStr::from_ptr(ptr as *const _) - }; + CStr::from_ptr(ptr).to_str().unwrap() + } + } - str::from_utf8(name.to_bytes()).unwrap() + /// Returns the RFC-standard name of the cipher, if one exists. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CIPHER_standard_name`]. + /// + /// [`SSL_CIPHER_standard_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[cfg(ossl111)] + pub fn standard_name(&self) -> Option<&'static str> { + unsafe { + let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } } /// Returns the SSL/TLS protocol version that first defined the cipher. diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index 0e9969f1b2976cfc85ca30292b707d47ac048ae5..09ea04e989f7fcdd524e648f345d8b9a0a012e41 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -1838,3 +1838,12 @@ fn client_hello() { guard.join().unwrap(); } + +#[test] +#[cfg(ossl111)] +fn openssl_cipher_name() { + assert_eq!( + super::cipher_name("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), + Some("ECDHE-RSA-AES256-SHA384") + ); +}