Unverified Commit dd34c7d4 authored by Jack Rickard's avatar Jack Rickard Committed by GitHub
Browse files

Merge pull request #1770 from iamwwc/feedback-to-upstream

Add some ssl api
parents 2c0c391f a16ca8d4
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -492,6 +492,8 @@ extern "C" {
    pub fn SSL_CTX_set_ciphersuites(ctx: *mut SSL_CTX, str: *const c_char) -> c_int;
    #[cfg(any(ossl111, libressl340))]
    pub fn SSL_set_ciphersuites(ssl: *mut ::SSL, str: *const c_char) -> c_int;
    pub fn SSL_set_cipher_list(ssl: *mut SSL, s: *const c_char) -> c_int;
    pub fn SSL_set_ssl_method(s: *mut SSL, method: *const SSL_METHOD) -> c_int;
    pub fn SSL_set_verify(
        ssl: *mut SSL,
        mode: c_int,
@@ -515,6 +517,13 @@ extern "C" {
        ctx: *mut SSL_CTX,
        cert_chain_file: *const c_char,
    ) -> c_int;
    pub fn SSL_use_PrivateKey_file(ssl: *mut SSL, file: *const c_char, type_: c_int) -> c_int;
    pub fn SSL_use_PrivateKey(ssl: *mut SSL, pkey: *mut EVP_PKEY) -> c_int;
    pub fn SSL_use_certificate(ssl: *mut SSL, x: *mut X509) -> c_int;
    #[cfg(any(ossl110, libressl332))]
    pub fn SSL_use_certificate_chain_file(ssl: *mut SSL, file: *const c_char) -> c_int;
    pub fn SSL_set_client_CA_list(s: *mut SSL, name_list: *mut stack_st_X509_NAME);
    pub fn SSL_add_client_CA(ssl: *mut SSL, x: *mut X509) -> c_int;
    pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME;

    #[cfg(not(ossl110))]
+5 −0
Original line number Diff line number Diff line
@@ -392,6 +392,11 @@ pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_ST
    SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void)
}

#[cfg(ossl102)]
pub unsafe fn SSL_set0_verify_cert_store(ssl: *mut SSL, st: *mut X509_STORE) -> c_long {
    SSL_ctrl(ssl, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void)
}

cfg_if! {
    if #[cfg(ossl111)] {
        pub unsafe fn SSL_CTX_set1_groups_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_long {
+172 −3
Original line number Diff line number Diff line
@@ -2507,10 +2507,8 @@ impl SslRef {

    /// Like [`SslContext::private_key`].
    ///
    /// This corresponds to `SSL_get_privatekey`.
    ///
    /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key
    #[corresponds(SSL_get_certificate)]
    #[corresponds(SSL_get_privatekey)]
    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
        unsafe {
            let ptr = ffi::SSL_get_privatekey(self.as_ptr());
@@ -3114,6 +3112,177 @@ impl SslRef {
        }
        Ok(())
    }

    /// Sets a new default TLS/SSL method for SSL objects
    #[cfg(not(boringssl))]
    pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?;
        };
        Ok(())
    }

    /// Loads the private key from a file.
    #[corresponds(SSL_use_Private_Key_file)]
    pub fn set_private_key_file<P: AsRef<Path>>(
        &mut self,
        path: P,
        ssl_file_type: SslFiletype,
    ) -> Result<(), ErrorStack> {
        let p = path.as_ref().as_os_str().to_str().unwrap();
        let key_file = CString::new(p).unwrap();
        unsafe {
            cvt(ffi::SSL_use_PrivateKey_file(
                self.as_ptr(),
                key_file.as_ptr(),
                ssl_file_type.as_raw(),
            ))?;
        };
        Ok(())
    }

    /// Sets the private key.
    #[corresponds(SSL_use_PrivateKey)]
    pub fn set_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?;
        };
        Ok(())
    }

    /// Sets the certificate
    #[corresponds(SSL_use_certificate)]
    pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?;
        };
        Ok(())
    }

    /// Loads a certificate chain from a file.
    ///
    /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
    /// certificate, and the remainder forming the chain of certificates up to and including the
    /// trusted root certificate.
    #[corresponds(SSL_use_certificate_chain_file)]
    #[cfg(any(ossl110, libressl332))]
    pub fn set_certificate_chain_file<P: AsRef<Path>>(
        &mut self,
        path: P,
    ) -> Result<(), ErrorStack> {
        let p = path.as_ref().as_os_str().to_str().unwrap();
        let cert_file = CString::new(p).unwrap();
        unsafe {
            cvt(ffi::SSL_use_certificate_chain_file(
                self.as_ptr(),
                cert_file.as_ptr(),
            ))?;
        };
        Ok(())
    }

    /// Sets ca certificate that client trusted
    #[corresponds(SSL_add_client_CA)]
    pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?;
        };
        Ok(())
    }

    // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl
    #[corresponds(SSL_set_client_CA_list)]
    pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
        unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) }
        mem::forget(list);
    }

    /// Sets the minimum supported protocol version.
    ///
    /// A value of `None` will enable protocol versions down the the lowest version supported by
    /// OpenSSL.
    ///
    /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
    #[corresponds(SSL_set_min_proto_version)]
    #[cfg(any(ossl110, libressl261))]
    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_set_min_proto_version(
                self.as_ptr(),
                version.map_or(0, |v| v.0 as _),
            ))
            .map(|_| ())
        }
    }

    /// Sets the maximum supported protocol version.
    ///
    /// A value of `None` will enable protocol versions down the the highest version supported by
    /// OpenSSL.
    ///
    /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
    #[corresponds(SSL_set_max_proto_version)]
    #[cfg(any(ossl110, libressl261))]
    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_set_max_proto_version(
                self.as_ptr(),
                version.map_or(0, |v| v.0 as _),
            ))
            .map(|_| ())
        }
    }

    /// Sets the list of supported ciphers for the TLSv1.3 protocol.
    ///
    /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3.
    ///
    /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
    /// preference.
    ///
    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
    #[corresponds(SSL_set_ciphersuites)]
    #[cfg(any(ossl111, libressl340))]
    pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
        let cipher_list = CString::new(cipher_list).unwrap();
        unsafe {
            cvt(ffi::SSL_set_ciphersuites(
                self.as_ptr(),
                cipher_list.as_ptr() as *const _,
            ))
            .map(|_| ())
        }
    }

    /// Sets the list of supported ciphers for protocols before TLSv1.3.
    ///
    /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
    ///
    /// See [`ciphers`] for details on the format.
    ///
    /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html
    #[corresponds(SSL_set_cipher_list)]
    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
        let cipher_list = CString::new(cipher_list).unwrap();
        unsafe {
            cvt(ffi::SSL_set_cipher_list(
                self.as_ptr(),
                cipher_list.as_ptr() as *const _,
            ))
            .map(|_| ())
        }
    }

    /// Set the certificate store used for certificate verification
    #[corresponds(SSL_set_cert_store)]
    #[cfg(ossl102)]
    pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?;
            mem::forget(cert_store);
            Ok(())
        }
    }
}

/// An SSL stream midway through the handshake process.
+55 −0
Original line number Diff line number Diff line
@@ -1422,3 +1422,58 @@ fn add_chain_cert() {
    let mut ssl = Ssl::new(&ctx).unwrap();
    assert!(ssl.add_chain_cert(cert).is_ok());
}
#[test]
#[cfg(ossl111)]
fn set_ssl_certificate_key_related_api() {
    let cert_str: &str = include_str!("../../../test/cert.pem");
    let key_str: &str = include_str!("../../../test/key.pem");
    let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
    let cert_x509 = X509::from_pem(CERT).unwrap();
    let mut ssl = Ssl::new(&ctx).unwrap();
    assert!(ssl.set_method(SslMethod::tls()).is_ok());
    ssl.set_private_key_file("test/key.pem", SslFiletype::PEM)
        .unwrap();
    {
        let pkey = String::from_utf8(
            ssl.private_key()
                .unwrap()
                .private_key_to_pem_pkcs8()
                .unwrap(),
        )
        .unwrap();
        assert!(pkey.lines().eq(key_str.lines()));
    }
    let pkey = PKey::private_key_from_pem(KEY).unwrap();
    ssl.set_private_key(pkey.as_ref()).unwrap();
    {
        let pkey = String::from_utf8(
            ssl.private_key()
                .unwrap()
                .private_key_to_pem_pkcs8()
                .unwrap(),
        )
        .unwrap();
        assert!(pkey.lines().eq(key_str.lines()));
    }
    ssl.set_certificate(cert_x509.as_ref()).unwrap();
    let cert = String::from_utf8(ssl.certificate().unwrap().to_pem().unwrap()).unwrap();
    assert!(cert.lines().eq(cert_str.lines()));
    ssl.add_client_ca(cert_x509.as_ref()).unwrap();
    ssl.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap();
    ssl.set_max_proto_version(Some(SslVersion::TLS1_3)).unwrap();
    ssl.set_cipher_list("HIGH:!aNULL:!MD5").unwrap();
    ssl.set_ciphersuites("TLS_AES_128_GCM_SHA256").unwrap();
    let x509 = X509::from_pem(ROOT_CERT).unwrap();
    let mut builder = X509StoreBuilder::new().unwrap();
    builder.add_cert(x509).unwrap();
    let store = builder.build();
    ssl.set_verify_cert_store(store).unwrap();
}

#[test]
#[cfg(ossl110)]
fn test_ssl_set_cert_chain_file() {
    let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
    let mut ssl = Ssl::new(&ctx).unwrap();
    ssl.set_certificate_chain_file("test/cert.pem").unwrap();
}