diff --git a/ylong_http_client/Cargo.toml b/ylong_http_client/Cargo.toml index 3d668388a87e379e94bc753fde118c0ddabf4447..9cbf26abd1f38519e05cf088f83af64fd1087960 100644 --- a/ylong_http_client/Cargo.toml +++ b/ylong_http_client/Cargo.toml @@ -43,6 +43,11 @@ __c_openssl = ["__tls", "libc"] # Not open to user, only mark to use tls c_openssl_1_1 = ["__c_openssl"] # Uses TLS by FFI of C-openssl 1.1. c_openssl_3_0 = ["__c_openssl"] # Uses TLS by FFI of C-openssl 3.0. +[[example]] +name = "async_certs_adapter" +path = "examples/async_certs_adapter.rs" +required-features = ["async", "http1_1", "ylong_base", "__c_openssl"] + [[example]] name = "async_http" path = "examples/async_http.rs" diff --git a/ylong_http_client/examples/async_certs_adapter.rs b/ylong_http_client/examples/async_certs_adapter.rs new file mode 100644 index 0000000000000000000000000000000000000000..d8125dee3fd9185a0c14962a214a9755a4da6e08 --- /dev/null +++ b/ylong_http_client/examples/async_certs_adapter.rs @@ -0,0 +1,59 @@ +// Copyright (c) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This is a simple asynchronous HTTPS client example. + +use std::sync::Arc; + +use ylong_http_client::async_impl::{Client, ClientBuilder, Downloader}; +use ylong_http_client::{CertVerifier, HttpClientError, Request, ServerCerts}; + +struct Verifier; + +impl CertVerifier for Verifier { + fn verify(&self, _certs: &ServerCerts) -> bool { + println!("Custom verified"); + false + } +} + +fn main() -> Result<(), HttpClientError> { + let mut handles = Vec::new(); + + let client = Arc::new( + ClientBuilder::new() + .cert_verifier(Verifier) + .build() + .unwrap(), + ); + + for _ in 0..4 { + let temp = client.clone(); + handles.push(ylong_runtime::spawn(request(temp))); + } + for handle in handles { + let _ = ylong_runtime::block_on(handle); + } + Ok(()) +} + +async fn request(client: Arc) -> Result<(), HttpClientError> { + let request = Request::get("https://www.example.com") + .body("".as_bytes()) + .map_err(|e| HttpClientError::other(Some(e))) + .unwrap(); + // Sends request and receives a `Response`. + let response = client.request(request).await?; + // Reads the body of `Response` by using `BodyReader`. + Downloader::console(response).download().await +} diff --git a/ylong_http_client/src/async_impl/client.rs b/ylong_http_client/src/async_impl/client.rs index 9863dba486ef5e270d2365103e3ecf46f9b3ccfb..ec61c7235634ebb5edd5e3ca358df11494d9e7a7 100644 --- a/ylong_http_client/src/async_impl/client.rs +++ b/ylong_http_client/src/async_impl/client.rs @@ -11,6 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::sync::Arc; + use ylong_http::body::{ChunkBody, TextBody}; use ylong_http::request::method::Method; use ylong_http::response::Response; @@ -18,10 +20,13 @@ use ylong_http::version::Version; use super::{conn, Body, ConnPool, Connector, HttpBody, HttpConnector}; use crate::async_impl::timeout::TimeoutFuture; +use crate::util::config::tls::DefaultCertVerifier; use crate::util::normalizer::{format_host_value, RequestFormatter, UriFormatter}; use crate::util::proxy::Proxies; use crate::util::redirect::TriggerKind; use crate::util::{ClientConfig, ConnectorConfig, HttpConfig, HttpVersion, Redirect}; +#[cfg(feature = "__tls")] +use crate::CertVerifier; #[cfg(feature = "http2")] use crate::H2Config; use crate::{sleep, timeout, ErrorKind, HttpClientError, Proxy, Request, Timeout, Uri}; @@ -685,6 +690,44 @@ impl ClientBuilder { self.tls = self.tls.sni(is_set_sni); self } + + /// Controls the use of TLS certs verifier. + /// + /// Defaults to `None` -- sets cert_verifier. + /// + /// # Example + /// + /// ``` + /// use ylong_http_client::async_impl::ClientBuilder; + /// use ylong_http_client::{CertVerifier, ServerCerts}; + /// + /// pub struct CallbackTest { + /// inner: String, + /// } + /// + /// impl CallbackTest { + /// pub(crate) fn new() -> Self { + /// Self { + /// inner: "Test".to_string(), + /// } + /// } + /// } + /// + /// impl CertVerifier for CallbackTest { + /// fn verify(&self, certs: &ServerCerts) -> bool { + /// true + /// } + /// } + /// + /// let verifier = CallbackTest::new(); + /// let builder = ClientBuilder::new().cert_verifier(verifier); + /// ``` + pub fn cert_verifier(mut self, verifier: T) -> Self { + self.tls = self + .tls + .cert_verifier(Arc::new(DefaultCertVerifier::new(verifier))); + self + } } impl Default for ClientBuilder { diff --git a/ylong_http_client/src/util/c_openssl/adapter.rs b/ylong_http_client/src/util/c_openssl/adapter.rs index bad3828ee4eb2ae62f0d18fde27300f781c53c54..c3e0afee52985d7f141d6c910dcb66375da1f210 100644 --- a/ylong_http_client/src/util/c_openssl/adapter.rs +++ b/ylong_http_client/src/util/c_openssl/adapter.rs @@ -13,6 +13,7 @@ use std::net::IpAddr; use std::path::Path; +use std::sync::Arc; use crate::error::HttpClientError; use crate::util::c_openssl::error::ErrorStack; @@ -20,8 +21,9 @@ use crate::util::c_openssl::ssl::{ Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslVersion, }; use crate::util::c_openssl::x509::{X509Ref, X509Store, X509}; +use crate::util::config::tls::DefaultCertVerifier; use crate::util::AlpnProtocolList; -use crate::ErrorKind; +use crate::{CertVerifier, ErrorKind, ServerCerts}; /// `TlsContextBuilder` implementation based on `SSL_CTX`. /// @@ -39,6 +41,7 @@ use crate::ErrorKind; /// ``` pub struct TlsConfigBuilder { inner: Result, + cert_verifier: Option>, use_sni: bool, verify_hostname: bool, certs_list: Vec, @@ -59,6 +62,7 @@ impl TlsConfigBuilder { pub fn new() -> Self { Self { inner: SslContext::builder(SslMethod::tls_client()), + cert_verifier: None, use_sni: true, verify_hostname: true, certs_list: vec![], @@ -224,46 +228,47 @@ impl TlsConfigBuilder { /// # Examples /// /// ``` - /// use ylong_http_client::async_impl::Client; - /// use ylong_http_client::{Certificate, TlsVersion}; + /// use ylong_http_client::async_impl::Client; + /// use ylong_http_client::{Certificate, TlsVersion}; /// - /// let cert1 = Certificate::from_pem(include_bytes!("../../../tests/file/root-ca.pem")).unwrap(); - /// let cert2 = Certificate::from_pem(include_bytes!("../../../tests/file/cert.pem")).unwrap(); + /// let cert1 = Certificate::from_pem(include_bytes!("../../../tests/file/root-ca.pem")).unwrap(); + /// let cert2 = Certificate::from_pem(include_bytes!("../../../tests/file/cert.pem")).unwrap(); /// - /// // Creates a `Client` - /// let client = Client::builder() - /// .tls_built_in_root_certs(false) - /// .danger_accept_invalid_certs(false) - /// .max_tls_version(TlsVersion::TLS_1_2) - /// .min_tls_version(TlsVersion::TLS_1_2) - /// .add_root_certificate(cert1) - /// .add_root_certificate(cert2) - /// .build().unwrap(); + /// // Creates a `Client` + /// let client = Client::builder() + /// .tls_built_in_root_certs(false) + /// .danger_accept_invalid_certs(false) + /// .max_tls_version(TlsVersion::TLS_1_2) + /// .min_tls_version(TlsVersion::TLS_1_2) + /// .add_root_certificate(cert1) + /// .add_root_certificate(cert2) + /// .build() + /// .unwrap(); /// ``` pub fn add_root_certificates(mut self, mut certs: Vec) -> Self { self.certs_list.append(&mut certs); self } - /// Adds custom root certificate. /// /// # Examples /// /// ``` - /// use ylong_http_client::async_impl::Client; - /// use ylong_http_client::{Certificate, TlsVersion}; + /// use ylong_http_client::async_impl::Client; + /// use ylong_http_client::{Certificate, TlsVersion}; /// - /// let path_cert = Certificate::from_path("../../../cert/file").unwrap(); + /// let path_cert = Certificate::from_path("../../../cert/file").unwrap(); /// - /// // Creates a `Client` - /// let client = Client::builder() - /// .tls_built_in_root_certs(false) - /// .danger_accept_invalid_certs(false) - /// .max_tls_version(TlsVersion::TLS_1_2) - /// .min_tls_version(TlsVersion::TLS_1_2) - /// .add_root_certificate(path_cert) - /// .build().unwrap(); + /// // Creates a `Client` + /// let client = Client::builder() + /// .tls_built_in_root_certs(false) + /// .danger_accept_invalid_certs(false) + /// .max_tls_version(TlsVersion::TLS_1_2) + /// .min_tls_version(TlsVersion::TLS_1_2) + /// .add_root_certificate(path_cert) + /// .build() + /// .unwrap(); /// ``` #[cfg(feature = "c_openssl_3_0")] pub fn add_path_certificates(mut self, path: String) -> Self { @@ -271,7 +276,6 @@ impl TlsConfigBuilder { self } - /// Sets the protocols to sent to the server for Application Layer Protocol /// Negotiation (ALPN). /// @@ -380,6 +384,16 @@ impl TlsConfigBuilder { self } + pub(crate) fn cert_verifier(mut self, verifier: Arc) -> Self { + let inner = Arc::as_ptr(&verifier); + self.cert_verifier = Some(verifier); + self.inner = self.inner.map(|mut builder| { + builder.set_cert_verify_callback(inner); + builder + }); + self + } + /// Controls the use of TLS server name indication. /// /// Defaults to `true` -- sets sni. @@ -422,8 +436,7 @@ impl TlsConfigBuilder { #[cfg(feature = "c_openssl_3_0")] for path in self.paths_list { self.inner = self.inner.and_then(|mut builder| { - { Ok(builder.cert_store_mut()).map(|store| store.add_path(path)) } - .map(|_| builder) + { Ok(builder.cert_store_mut()).map(|store| store.add_path(path)) }.map(|_| builder) }); } @@ -434,6 +447,7 @@ impl TlsConfigBuilder { Ok(TlsConfig { ctx, + cert_verifier: self.cert_verifier, use_sni: self.use_sni, verify_hostname: self.verify_hostname, }) @@ -459,6 +473,7 @@ impl Default for TlsConfigBuilder { #[derive(Clone)] pub struct TlsConfig { ctx: SslContext, + cert_verifier: Option>, use_sni: bool, verify_hostname: bool, } @@ -653,11 +668,11 @@ impl Cert { /// let certs = Certificate::from_pem(pem); /// } /// ``` -pub struct Certificate { +pub struct Certificate { inner: CertificateList, } -pub(crate) enum CertificateList { +pub(crate) enum CertificateList { CertList(Vec), #[cfg(feature = "c_openssl_3_0")] PathList(String), @@ -671,13 +686,17 @@ impl Certificate { .into_iter() .map(Cert) .collect(); - Ok(Certificate { inner: CertificateList::CertList(cert_list) }) + Ok(Certificate { + inner: CertificateList::CertList(cert_list), + }) } /// Deserializes a list of PEM-formatted certificates. #[cfg(feature = "c_openssl_3_0")] pub fn from_path(path: &str) -> Result { - Ok(Certificate { inner: CertificateList::PathList(path.to_string()) }) + Ok(Certificate { + inner: CertificateList::PathList(path.to_string()), + }) } pub(crate) fn into_inner(self) -> CertificateList { @@ -690,9 +709,9 @@ mod ut_openssl_adapter { use std::io::{Read, Write}; use std::net::TcpStream; + use crate::util::c_openssl::adapter::CertificateList; use crate::util::{Cert, TlsConfigBuilder, TlsFileType, TlsVersion}; use crate::{AlpnProtocol, AlpnProtocolList, Certificate}; - use crate::util::c_openssl::adapter::CertificateList; /// UT test cases for `TlsConfigBuilder::new`. /// @@ -808,9 +827,7 @@ mod ut_openssl_adapter { CertificateList::PathList(_) => vec![], }; - let builder = TlsConfigBuilder::new() - .add_root_certificates(certs) - .build(); + let builder = TlsConfigBuilder::new().add_root_certificates(certs).build(); assert!(builder.is_ok()); } diff --git a/ylong_http_client/src/util/c_openssl/ffi/callback.rs b/ylong_http_client/src/util/c_openssl/ffi/callback.rs new file mode 100644 index 0000000000000000000000000000000000000000..2f3627c995ac2009d985cdc82135524a3120443a --- /dev/null +++ b/ylong_http_client/src/util/c_openssl/ffi/callback.rs @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::ffi::{c_int, c_void}; + +use crate::util::c_openssl::ffi::ssl::SSL_CTX; +use crate::util::c_openssl::ffi::x509::X509_STORE_CTX; +use crate::util::c_openssl::foreign::ForeignRef; +use crate::util::c_openssl::x509::X509StoreContextRef; +use crate::util::config::tls::DefaultCertVerifier; +use crate::{CertVerifier, ServerCerts}; + +pub(crate) extern "C" fn cert_verify(ctx: *mut X509_STORE_CTX, arg: *mut c_void) -> c_int { + unsafe { + let verifier = &*(arg as *const DefaultCertVerifier); + let ctx = X509StoreContextRef::from_ptr(ctx); + verifier.verify(&ServerCerts::new(ctx)) as c_int + } +} diff --git a/ylong_http_client/src/util/c_openssl/ffi/mod.rs b/ylong_http_client/src/util/c_openssl/ffi/mod.rs index e24ca1318c9080e39048bbff173aec9a6947b319..830257ef5aed13b43e29ba742de3e8988fac83ff 100644 --- a/ylong_http_client/src/util/c_openssl/ffi/mod.rs +++ b/ylong_http_client/src/util/c_openssl/ffi/mod.rs @@ -15,6 +15,7 @@ #![allow(non_camel_case_types)] pub(crate) mod bio; +pub(crate) mod callback; pub(crate) mod err; pub(crate) mod pem; pub(crate) mod ssl; diff --git a/ylong_http_client/src/util/c_openssl/ffi/ssl.rs b/ylong_http_client/src/util/c_openssl/ffi/ssl.rs index 5fa2d8e9fdca2fcaf7523feb00cac5fbfc856b56..d34432ddd4d424a0ab3f0c7c3d10cccc642681b9 100644 --- a/ylong_http_client/src/util/c_openssl/ffi/ssl.rs +++ b/ylong_http_client/src/util/c_openssl/ffi/ssl.rs @@ -113,6 +113,11 @@ extern "C" { verify_callback: Option c_int>, ); + pub(crate) fn SSL_CTX_set_cert_verify_callback( + ctx: *mut SSL_CTX, + callback: extern "C" fn(*mut X509_STORE_CTX, *mut c_void) -> c_int, + arg: *mut c_void, + ); } /// This is the main SSL/TLS structure which is created by a server or client diff --git a/ylong_http_client/src/util/c_openssl/ffi/x509.rs b/ylong_http_client/src/util/c_openssl/ffi/x509.rs index 2d8ea6352bfc2c488a52b7fa1db3509e4e534764..035a0c6f56b0848d22d147991d0740271b84f53b 100644 --- a/ylong_http_client/src/util/c_openssl/ffi/x509.rs +++ b/ylong_http_client/src/util/c_openssl/ffi/x509.rs @@ -45,14 +45,18 @@ extern "C" { /// Adds the respective object to the X509_STORE's local storage. pub(crate) fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut C_X509) -> c_int; - - /// Adds the respective object of file paths to the X509_STORE's local storage. + /// Adds the respective object of file paths to the X509_STORE's local + /// storage. #[cfg(feature = "c_openssl_3_0")] pub(crate) fn X509_STORE_load_path(store: *mut X509_STORE, x: *const c_char) -> c_int; } pub(crate) enum X509_STORE_CTX {} +extern "C" { + pub(crate) fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); +} + pub(crate) enum X509_VERIFY_PARAM {} // for `X509_VERIFY_PARAM` diff --git a/ylong_http_client/src/util/c_openssl/mod.rs b/ylong_http_client/src/util/c_openssl/mod.rs index 785a981a22ad339f6a854ee623c0e3d42e4629b6..6167c7b65f80394a75f70443db6d16616b5d875f 100644 --- a/ylong_http_client/src/util/c_openssl/mod.rs +++ b/ylong_http_client/src/util/c_openssl/mod.rs @@ -26,6 +26,7 @@ pub(crate) mod stack; pub(crate) mod x509; pub mod adapter; + use core::ptr; use std::sync::Once; @@ -33,6 +34,7 @@ pub use adapter::{Cert, Certificate, TlsConfig, TlsConfigBuilder, TlsFileType, T use error::ErrorStack; use libc::c_int; +pub(crate) use crate::util::c_openssl::ffi::callback::*; use crate::util::c_openssl::ffi::OPENSSL_init_ssl; /// Automatic loading of the libssl error strings. This option is a default diff --git a/ylong_http_client/src/util/c_openssl/ssl/ctx.rs b/ylong_http_client/src/util/c_openssl/ssl/ctx.rs index ae88e56b4cc670f68505496ec20030741a894429..8011401c18f2a208b4cd1e71451d1643f7dae5e3 100644 --- a/ylong_http_client/src/util/c_openssl/ssl/ctx.rs +++ b/ylong_http_client/src/util/c_openssl/ssl/ctx.rs @@ -14,6 +14,8 @@ use core::{fmt, mem, ptr}; use std::ffi::CString; use std::path::Path; +use std::ptr::{null, null_mut}; +use std::sync::Weak; use libc::{c_int, c_long, c_uint, c_void}; @@ -27,12 +29,15 @@ use crate::c_openssl::x509::{X509Store, X509StoreRef}; use crate::util::c_openssl::error::ErrorStack; use crate::util::c_openssl::ffi::ssl::{ SSL_CTX_ctrl, SSL_CTX_load_verify_locations, SSL_CTX_new, SSL_CTX_set_alpn_protos, - SSL_CTX_set_cert_store, SSL_CTX_set_cipher_list, SSL_CTX_set_ciphersuites, SSL_CTX_up_ref, - SSL_CTX_use_certificate_chain_file, SSL_CTX_use_certificate_file, SSL_CTX, + SSL_CTX_set_cert_store, SSL_CTX_set_cert_verify_callback, SSL_CTX_set_cipher_list, + SSL_CTX_set_ciphersuites, SSL_CTX_up_ref, SSL_CTX_use_certificate_chain_file, + SSL_CTX_use_certificate_file, SSL_CTX, }; use crate::util::c_openssl::foreign::{Foreign, ForeignRef}; use crate::util::c_openssl::x509::{X509Ref, X509}; -use crate::util::c_openssl::{check_ptr, check_ret, ssl_init}; +use crate::util::c_openssl::{cert_verify, check_ptr, check_ret, ssl_init}; +use crate::util::config::tls::DefaultCertVerifier; +use crate::{CertVerifier, ServerCerts}; const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; @@ -258,6 +263,13 @@ impl SslContextBuilder { unsafe { SSL_CTX_set_verify(ptr, mode, None) }; } + pub(crate) fn set_cert_verify_callback(&mut self, verifier: *const DefaultCertVerifier) { + let ptr = self.as_ptr_mut(); + unsafe { + SSL_CTX_set_cert_verify_callback(ptr, cert_verify, verifier as *mut c_void); + } + } + pub(crate) fn set_cert_store(&mut self, cert_store: X509Store) { let ptr = self.as_ptr_mut(); unsafe { diff --git a/ylong_http_client/src/util/c_openssl/x509.rs b/ylong_http_client/src/util/c_openssl/x509.rs index 21b16b7c9838e0b4d2c304217b385f8fdd439815..13e129289f17d90be02d250174fc1cc89cfb7cea 100644 --- a/ylong_http_client/src/util/c_openssl/x509.rs +++ b/ylong_http_client/src/util/c_openssl/x509.rs @@ -12,6 +12,8 @@ // limitations under the License. use core::{ffi, fmt, ptr, str}; +#[cfg(feature = "c_openssl_3_0")] +use std::ffi::CString; use std::net::IpAddr; use libc::{c_int, c_long, c_uint}; @@ -20,19 +22,18 @@ use super::bio::BioSlice; use super::error::{error_get_lib, error_get_reason, ErrorStack}; use super::ffi::err::{ERR_clear_error, ERR_peek_last_error}; use super::ffi::pem::PEM_read_bio_X509; +#[cfg(feature = "c_openssl_3_0")] +use super::ffi::x509::X509_STORE_load_path; use super::ffi::x509::{ - d2i_X509, X509_STORE_add_cert, X509_STORE_free, X509_STORE_new, X509_VERIFY_PARAM_free, - X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_set_hostflags, - X509_verify_cert_error_string, STACK_X509, X509_STORE, X509_VERIFY_PARAM, + d2i_X509, X509_STORE_CTX_free, X509_STORE_add_cert, X509_STORE_free, X509_STORE_new, + X509_VERIFY_PARAM_free, X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_set1_ip, + X509_VERIFY_PARAM_set_hostflags, X509_verify_cert_error_string, STACK_X509, X509_STORE, + X509_STORE_CTX, X509_VERIFY_PARAM, }; use super::foreign::{Foreign, ForeignRef}; use super::stack::Stackof; use super::{check_ptr, check_ret, ssl_init}; use crate::util::c_openssl::ffi::x509::{X509_free, C_X509}; -#[cfg(feature = "c_openssl_3_0")] -use super::ffi::x509::X509_STORE_load_path; -#[cfg(feature = "c_openssl_3_0")] -use std::ffi::CString; foreign_type!( type CStruct = C_X509; @@ -153,7 +154,8 @@ impl X509StoreRef { Ok(cstr) => cstr, Err(_) => return Err(ErrorStack::get()), }; - check_ret(unsafe { X509_STORE_load_path(self.as_ptr(), path.as_ptr() as *const _) }).map(|_| ()) + check_ret(unsafe { X509_STORE_load_path(self.as_ptr(), path.as_ptr() as *const _) }) + .map(|_| ()) } } @@ -198,3 +200,10 @@ impl X509VerifyParamRef { .map(|_| ()) } } + +foreign_type! { + type CStruct = X509_STORE_CTX; + fn drop = X509_STORE_CTX_free; + pub(crate) struct X509StoreContext; + pub(crate) struct X509StoreContextRef; +} diff --git a/ylong_http_client/src/util/config/mod.rs b/ylong_http_client/src/util/config/mod.rs index 6cd5be3170bad0d67e50c37217edda5dbbb7d1f2..f638f11c46b98ae4dc4c6dc2b9686881fed34cab 100644 --- a/ylong_http_client/src/util/config/mod.rs +++ b/ylong_http_client/src/util/config/mod.rs @@ -22,10 +22,10 @@ pub(crate) use http::{HttpConfig, HttpVersion}; pub use settings::{Proxy, ProxyBuilder, Redirect, Retry, SpeedLimit, Timeout}; #[cfg(feature = "__tls")] -mod tls; +pub(crate) mod tls; #[cfg(feature = "http2")] pub use http::http2::H2Config; #[cfg(feature = "__tls")] -pub use tls::{AlpnProtocol, AlpnProtocolList}; +pub use tls::{AlpnProtocol, AlpnProtocolList, CertVerifier, ServerCerts}; #[cfg(feature = "tls_rust_ssl")] pub use tls::{Certificate, PrivateKey, TlsConfig, TlsConfigBuilder, TlsFileType, TlsVersion}; diff --git a/ylong_http_client/src/util/config/tls/mod.rs b/ylong_http_client/src/util/config/tls/mod.rs index dd0a9c41930e9ea94c6b2635644ec7dc04cb2997..6a0353da98662a67b1db13b44dd9507707ece524 100644 --- a/ylong_http_client/src/util/config/tls/mod.rs +++ b/ylong_http_client/src/util/config/tls/mod.rs @@ -13,3 +13,7 @@ mod alpn; pub use alpn::{AlpnProtocol, AlpnProtocolList}; + +mod verifier; +pub(crate) use verifier::DefaultCertVerifier; +pub use verifier::{CertVerifier, ServerCerts}; diff --git a/ylong_http_client/src/util/config/tls/verifier/mod.rs b/ylong_http_client/src/util/config/tls/verifier/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..6cf9996ed5c4ee17354e3d0e32fe020844be88ab --- /dev/null +++ b/ylong_http_client/src/util/config/tls/verifier/mod.rs @@ -0,0 +1,42 @@ +// Copyright (c) 2023 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(feature = "__c_openssl")] +mod openssl; +#[cfg(feature = "__c_openssl")] +pub use openssl::ServerCerts; + +/// used to custom verify certs +pub trait CertVerifier { + /// provided to users custom certs adapter + fn verify(&self, certs: &ServerCerts) -> bool; +} + +/// default cert verifier +pub struct DefaultCertVerifier { + inner: Box, +} + +impl DefaultCertVerifier { + pub(crate) fn new(verifier: T) -> Self { + Self { + inner: Box::new(verifier), + } + } +} + +impl CertVerifier for DefaultCertVerifier { + fn verify(&self, certs: &ServerCerts) -> bool { + self.inner.verify(certs) + } +} diff --git a/ylong_http_client/src/util/config/tls/verifier/openssl.rs b/ylong_http_client/src/util/config/tls/verifier/openssl.rs new file mode 100644 index 0000000000000000000000000000000000000000..f32d49cc121530bcf721a900cd1ab47e0ac46477 --- /dev/null +++ b/ylong_http_client/src/util/config/tls/verifier/openssl.rs @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::util::c_openssl::x509::X509StoreContextRef; + +/// ServerCerts is provided to fetch info from X509 +pub struct ServerCerts<'a> { + inner: &'a X509StoreContextRef, +} + +impl<'a> ServerCerts<'a> { + pub(crate) fn new(inner: &'a X509StoreContextRef) -> Self { + Self { inner } + } +} + +impl AsRef for ServerCerts<'_> { + fn as_ref(&self) -> &X509StoreContextRef { + self.inner + } +} diff --git a/ylong_http_client/src/util/mod.rs b/ylong_http_client/src/util/mod.rs index 0dd45fe422eab48827a9415eb66112437db3d58f..49d3fbd8c11f95a29263f687f9ca3cb1dad7f90c 100644 --- a/ylong_http_client/src/util/mod.rs +++ b/ylong_http_client/src/util/mod.rs @@ -22,9 +22,9 @@ #![allow(dead_code)] #![allow(unused_imports)] -mod config; +pub(crate) mod config; #[cfg(feature = "__tls")] -pub use config::{AlpnProtocol, AlpnProtocolList}; +pub use config::{AlpnProtocol, AlpnProtocolList, CertVerifier, ServerCerts}; pub(crate) use config::{ClientConfig, ConnectorConfig, HttpConfig, HttpVersion}; pub use config::{Proxy, ProxyBuilder, Redirect, Retry, SpeedLimit, Timeout};