1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::net::IpAddr;
15 use std::path::Path;
16 use std::sync::Arc;
17 
18 use crate::error::{ErrorKind, HttpClientError};
19 use crate::util::c_openssl::error::ErrorStack;
20 use crate::util::c_openssl::ssl::{
21     Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslVersion,
22 };
23 use crate::util::c_openssl::verify::PubKeyPins;
24 use crate::util::c_openssl::x509::{X509Store, X509};
25 use crate::util::config::tls::DefaultCertVerifier;
26 use crate::util::AlpnProtocolList;
27 
28 /// `TlsContextBuilder` implementation based on `SSL_CTX`.
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// use ylong_http_client::{TlsConfigBuilder, TlsVersion};
34 ///
35 /// let context = TlsConfigBuilder::new()
36 ///     .ca_file("ca.crt")
37 ///     .max_proto_version(TlsVersion::TLS_1_2)
38 ///     .min_proto_version(TlsVersion::TLS_1_2)
39 ///     .cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK")
40 ///     .build();
41 /// ```
42 pub struct TlsConfigBuilder {
43     inner: Result<SslContextBuilder, ErrorStack>,
44     cert_verifier: Option<Arc<DefaultCertVerifier>>,
45     use_sni: bool,
46     verify_hostname: bool,
47     certs_list: Vec<Cert>,
48     pins: Option<PubKeyPins>,
49     paths_list: Vec<String>,
50 }
51 
52 impl TlsConfigBuilder {
53     /// Creates a new, default `SslContextBuilder`.
54     ///
55     /// # Examples
56     ///
57     /// ```
58     /// use ylong_http_client::TlsConfigBuilder;
59     ///
60     /// let builder = TlsConfigBuilder::new();
61     /// ```
newnull62     pub fn new() -> Self {
63         Self {
64             inner: SslContext::builder(SslMethod::tls_client()),
65             cert_verifier: None,
66             use_sni: true,
67             verify_hostname: true,
68             certs_list: vec![],
69             pins: None,
70             paths_list: vec![],
71         }
72     }
73 
74     /// Loads trusted root certificates from a file. The file should contain a
75     /// sequence of PEM-formatted CA certificates.
76     ///
77     /// # Examples
78     ///
79     /// ```
80     /// use ylong_http_client::TlsConfigBuilder;
81     ///
82     /// let builder = TlsConfigBuilder::new().ca_file("ca.crt");
83     /// ```
ca_filenull84     pub fn ca_file<T: AsRef<Path>>(mut self, path: T) -> Self {
85         self.inner = self
86             .inner
87             .and_then(|mut builder| builder.set_ca_file(path).map(|_| builder));
88         self
89     }
90 
91     /// Sets the maximum supported protocol version. A value of `None` will
92     /// enable protocol versions down the highest version supported by
93     /// `OpenSSL`.
94     ///
95     /// Requires `OpenSSL 1.1.0` or `LibreSSL 2.6.1` or newer.
96     ///
97     /// # Examples
98     ///
99     /// ```
100     /// use ylong_http_client::{TlsConfigBuilder, TlsVersion};
101     ///
102     /// let builder = TlsConfigBuilder::new().max_proto_version(TlsVersion::TLS_1_2);
103     /// ```
max_proto_versionnull104     pub fn max_proto_version(mut self, version: TlsVersion) -> Self {
105         self.inner = self.inner.and_then(|mut builder| {
106             builder
107                 .set_max_proto_version(version.into_inner())
108                 .map(|_| builder)
109         });
110         self
111     }
112 
113     /// Sets the minimum supported protocol version. A value of `None` will
114     /// enable protocol versions down the the lowest version supported by
115     /// `OpenSSL`.
116     ///
117     /// Requires `OpenSSL 1.1.0` or `LibreSSL 2.6.1` or newer.
118     ///
119     /// # Examples
120     ///
121     /// ```
122     /// use ylong_http_client::{TlsConfigBuilder, TlsVersion};
123     ///
124     /// let builder = TlsConfigBuilder::new().min_proto_version(TlsVersion::TLS_1_2);
125     /// ```
min_proto_versionnull126     pub fn min_proto_version(mut self, version: TlsVersion) -> Self {
127         self.inner = self.inner.and_then(|mut builder| {
128             builder
129                 .set_min_proto_version(version.into_inner())
130                 .map(|_| builder)
131         });
132         self
133     }
134 
135     /// Sets the list of supported ciphers for protocols before `TLSv1.3`.
136     ///
137     /// See [`ciphers`] for details on the format.
138     ///
139     /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
140     ///
141     /// # Examples
142     ///
143     /// ```
144     /// use ylong_http_client::TlsConfigBuilder;
145     ///
146     /// let builder = TlsConfigBuilder::new()
147     ///     .cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK");
148     /// ```
cipher_listnull149     pub fn cipher_list(mut self, list: &str) -> Self {
150         self.inner = self
151             .inner
152             .and_then(|mut builder| builder.set_cipher_list(list).map(|_| builder));
153         self
154     }
155 
156     /// Loads a leaf certificate from a file.
157     ///
158     /// Only a single certificate will be loaded - use `add_extra_chain_cert` to
159     /// add the remainder of the certificate chain, or
160     /// `set_certificate_chain_file` to load the entire chain from a single
161     /// file.
162     ///
163     /// # Examples
164     ///
165     /// ```
166     /// use ylong_http_client::{TlsConfigBuilder, TlsFileType};
167     ///
168     /// let builder = TlsConfigBuilder::new().certificate_file("cert.pem", TlsFileType::PEM);
169     /// ```
certificate_filenull170     pub fn certificate_file<T: AsRef<Path>>(mut self, path: T, file_type: TlsFileType) -> Self {
171         self.inner = self.inner.and_then(|mut builder| {
172             builder
173                 .set_certificate_file(path, file_type.into_inner())
174                 .map(|_| builder)
175         });
176         self
177     }
178 
179     /// Loads a certificate chain from a file.
180     ///
181     /// The file should contain a sequence of PEM-formatted certificates,
182     /// the first being the leaf certificate, and the remainder forming the
183     /// chain of certificates up to and including the trusted root certificate.
184     ///
185     /// # Examples
186     ///
187     /// ```
188     /// use ylong_http_client::TlsConfigBuilder;
189     ///
190     /// let builder = TlsConfigBuilder::new().certificate_chain_file("cert.pem");
191     /// ```
certificate_chain_filenull192     pub fn certificate_chain_file<T: AsRef<Path>>(mut self, path: T) -> Self {
193         self.inner = self
194             .inner
195             .and_then(|mut builder| builder.set_certificate_chain_file(path).map(|_| builder));
196         self
197     }
198 
199     /// Adds custom root certificate.
200     ///
201     /// # Examples
202     ///
203     /// ```
204     /// use ylong_http_client::{Cert, TlsConfigBuilder};
205     /// # fn example(certs: Vec<Cert>) {
206     /// let builder = TlsConfigBuilder::new().add_root_certificates(certs);
207     /// # }
208     /// ```
add_root_certificatesnull209     pub fn add_root_certificates(mut self, mut certs: Vec<Cert>) -> Self {
210         self.certs_list.append(&mut certs);
211         self
212     }
213 
214     /// Adds custom root certificate.
215     ///
216     /// # Examples
217     ///
218     /// ```
219     /// use ylong_http_client::TlsConfigBuilder;
220     /// # fn example(path: String) {
221     /// let builder = TlsConfigBuilder::new().add_path_certificates(path);
222     /// # }
223     /// ```
add_path_certificatesnull224     pub fn add_path_certificates(mut self, path: String) -> Self {
225         self.paths_list.push(path);
226         self
227     }
228 
229     // Sets the protocols to sent to the server for Application Layer Protocol
230     // Negotiation (ALPN).
231     //
232     // Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
233     #[cfg(any(feature = "http2", feature = "http3"))]
234     pub(crate) fn alpn_protos(mut self, protocols: &[u8]) -> Self {
235         self.inner = self
236             .inner
237             .and_then(|mut builder| builder.set_alpn_protos(protocols).map(|_| builder));
238         self
239     }
240 
241     // Sets the protocols to sent to the server for Application Layer Protocol
242     // Negotiation (ALPN).
243     //
244     // This method is based on `openssl::SslContextBuilder::set_alpn_protos`.
245     // Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
246     pub(crate) fn alpn_proto_list(mut self, list: AlpnProtocolList) -> Self {
247         self.inner = self
248             .inner
249             .and_then(|mut builder| builder.set_alpn_protos(list.as_slice()).map(|_| builder));
250         self
251     }
252 
253     /// Controls the use of built-in system certificates during certificate
254     /// validation. Default to `true` -- uses built-in system certs.
build_in_root_certsnull255     pub fn build_in_root_certs(mut self, is_use: bool) -> Self {
256         if !is_use {
257             self.inner = X509Store::new().and_then(|store| {
258                 self.inner.and_then(|mut builder| {
259                     {
260                         builder.set_cert_store(store);
261                         Ok(())
262                     }
263                     .map(|_| builder)
264                 })
265             });
266         }
267         self
268     }
269 
270     /// Controls the use of certificates verification.
271     ///
272     /// Defaults to `false` -- verify certificates.
273     ///
274     /// # Warning
275     ///
276     /// When sets `true`, any certificate for any site will be trusted for use.
277     ///
278     /// # Examples
279     ///
280     /// ```
281     /// use ylong_http_client::TlsConfigBuilder;
282     ///
283     /// let builder = TlsConfigBuilder::new().danger_accept_invalid_certs(true);
284     /// ```
danger_accept_invalid_certsnull285     pub fn danger_accept_invalid_certs(mut self, is_invalid: bool) -> Self {
286         if is_invalid {
287             self.inner = self.inner.and_then(|mut builder| {
288                 {
289                     builder.set_verify(crate::util::c_openssl::ssl::SSL_VERIFY_NONE);
290                     Ok(())
291                 }
292                 .map(|_| builder)
293             });
294         }
295         self
296     }
297 
298     /// Controls the use of hostname verification.
299     ///
300     /// Defaults to `false` -- verify hostname.
301     ///
302     /// # Warning
303     ///
304     /// When sets `true`, any valid certificate for any site will be trusted for
305     /// use from any other.
306     ///
307     /// # Examples
308     ///
309     /// ```
310     /// use ylong_http_client::TlsConfigBuilder;
311     ///
312     /// let builder = TlsConfigBuilder::new().danger_accept_invalid_hostnames(true);
313     /// ```
danger_accept_invalid_hostnamesnull314     pub fn danger_accept_invalid_hostnames(mut self, invalid_hostname: bool) -> Self {
315         self.verify_hostname = !invalid_hostname;
316         self
317     }
318 
319     pub(crate) fn cert_verifier(mut self, verifier: Arc<DefaultCertVerifier>) -> Self {
320         let inner = Arc::as_ptr(&verifier);
321         self.cert_verifier = Some(verifier);
322         self.inner = self.inner.map(|mut builder| {
323             builder.set_cert_verify_callback(inner);
324             builder
325         });
326         self
327     }
328 
329     pub(crate) fn pinning_public_key(mut self, pin: PubKeyPins) -> Self {
330         self.pins = Some(pin);
331         self
332     }
333 
334     /// Controls the use of TLS server name indication.
335     ///
336     /// Defaults to `true` -- sets sni.
337     ///
338     /// # Examples
339     ///
340     /// ```
341     /// use ylong_http_client::TlsConfigBuilder;
342     ///
343     /// let builder = TlsConfigBuilder::new().sni(true);
344     /// ```
sninull345     pub fn sni(mut self, use_sni: bool) -> Self {
346         self.use_sni = use_sni;
347         self
348     }
349 
350     /// Builds a `TlsContext`. Returns `Err` if an error occurred during
351     /// configuration.
352     ///
353     /// # Examples
354     ///
355     /// ```
356     /// use ylong_http_client::{TlsConfigBuilder, TlsVersion};
357     ///
358     /// let context = TlsConfigBuilder::new()
359     ///     .ca_file("ca.crt")
360     ///     .max_proto_version(TlsVersion::TLS_1_2)
361     ///     .min_proto_version(TlsVersion::TLS_1_2)
362     ///     .cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK")
363     ///     .build();
364     /// ```
buildnull365     pub fn build(mut self) -> Result<TlsConfig, HttpClientError> {
366         for cert in self.certs_list {
367             self.inner = self.inner.and_then(|mut builder| {
368                 Ok(builder.cert_store_mut())
369                     .and_then(|store| store.add_cert(cert.0))
370                     .map(|_| builder)
371             });
372         }
373 
374         for path in self.paths_list {
375             self.inner = self.inner.and_then(|mut builder| {
376                 Ok(builder.cert_store_mut())
377                     .and_then(|store| store.add_path(path))
378                     .map(|_| builder)
379             });
380         }
381 
382         let ctx = self
383             .inner
384             .map(|builder| builder.build())
385             .map_err(|e| HttpClientError::from_error(ErrorKind::Build, e))?;
386 
387         Ok(TlsConfig {
388             ctx,
389             cert_verifier: self.cert_verifier,
390             use_sni: self.use_sni,
391             verify_hostname: self.verify_hostname,
392             pins: self.pins,
393         })
394     }
395 }
396 
397 impl Default for TlsConfigBuilder {
defaultnull398     fn default() -> Self {
399         Self::new()
400     }
401 }
402 
403 /// `TlsContext` is based on `SSL_CTX`, which provides context
404 /// object of `TLS` streams.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// use ylong_http_client::TlsConfig;
410 ///
411 /// let builder = TlsConfig::builder();
412 /// ```
413 #[derive(Clone)]
414 pub struct TlsConfig {
415     ctx: SslContext,
416     #[allow(dead_code)]
417     cert_verifier: Option<Arc<DefaultCertVerifier>>,
418     use_sni: bool,
419     verify_hostname: bool,
420     pins: Option<PubKeyPins>,
421 }
422 
423 impl TlsConfig {
424     /// Creates a new, default `TlsContextBuilder`.
425     ///
426     /// # Examples
427     ///
428     /// ```
429     /// use ylong_http_client::TlsConfig;
430     ///
431     /// let builder = TlsConfig::builder();
432     /// ```
buildernull433     pub fn builder() -> TlsConfigBuilder {
434         TlsConfigBuilder::new()
435     }
436 
437     /// Creates a new, default `TlsSsl`.
438     pub(crate) fn ssl_new(&self, domain: &str) -> Result<TlsSsl, ErrorStack> {
439         let ctx = &self.ctx;
440         let mut ssl = Ssl::new(ctx)?;
441 
442         // SNI extension in `ClientHello` stage.
443         if self.use_sni && domain.parse::<IpAddr>().is_err() {
444             ssl.set_host_name_in_sni(domain)?;
445         }
446 
447         // Hostname verification in certificate verification.
448         if self.verify_hostname {
449             ssl.set_verify_hostname(domain)?;
450         }
451         Ok(TlsSsl(ssl))
452     }
453 
454     pub(crate) fn pinning_host_match(&self, domain: &str) -> Option<String> {
455         match &self.pins {
456             None => None,
457             Some(pins) => pins.get_pin(domain),
458         }
459     }
460 }
461 
462 impl Default for TlsConfig {
defaultnull463     fn default() -> Self {
464         // It certainly can be successful.
465         TlsConfig::builder()
466             .build()
467             .expect("TlsConfig build error!")
468     }
469 }
470 
471 /// /// `TlsSsl` is based on `Ssl`
472 pub(crate) struct TlsSsl(Ssl);
473 
474 impl TlsSsl {
475     pub(crate) fn into_inner(self) -> Ssl {
476         self.0
477     }
478 }
479 
480 /// `TlsVersion` is based on `openssl::SslVersion`, which provides `SSL/TLS`
481 /// protocol version.
482 ///
483 /// # Examples
484 ///
485 /// ```
486 /// use ylong_http_client::TlsVersion;
487 ///
488 /// let version = TlsVersion::TLS_1_2;
489 /// ```
490 pub struct TlsVersion(SslVersion);
491 
492 impl TlsVersion {
493     /// Constant for TLS version 1.
494     pub const TLS_1_0: Self = Self(SslVersion::TLS_1_0);
495     /// Constant for TLS version 1.1.
496     pub const TLS_1_1: Self = Self(SslVersion::TLS_1_1);
497     /// Constant for TLS version 1.2.
498     pub const TLS_1_2: Self = Self(SslVersion::TLS_1_2);
499     /// Constant for TLS version 1.3.
500     pub const TLS_1_3: Self = Self(SslVersion::TLS_1_3);
501 
502     /// Consumes `TlsVersion` and then takes `SslVersion`.
503     pub(crate) fn into_inner(self) -> SslVersion {
504         self.0
505     }
506 }
507 
508 /// `TlsFileType` is based on `openssl::SslFileType`, which provides an
509 /// identifier of the format of a certificate or key file.
510 ///
511 /// ```
512 /// use ylong_http_client::TlsFileType;
513 ///
514 /// let file_type = TlsFileType::PEM;
515 /// ```
516 pub struct TlsFileType(SslFiletype);
517 
518 impl TlsFileType {
519     /// Constant for PEM file type.
520     pub const PEM: Self = Self(SslFiletype::PEM);
521     /// Constant for ASN1 file type.
522     pub const ASN1: Self = Self(SslFiletype::ASN1);
523 
524     /// Consumes `TlsFileType` and then takes `SslFiletype`.
525     pub(crate) fn into_inner(self) -> SslFiletype {
526         self.0
527     }
528 }
529 
530 /// `Cert` is based on `X509`, which indicates `X509` public
531 /// key certificate.
532 ///
533 /// ```
534 /// # use ylong_http_client::Cert;
535 ///
536 /// # fn read_from_pem(pem: &[u8]) {
537 /// let cert = Cert::from_pem(pem);
538 /// # }
539 ///
540 /// # fn read_from_der(der: &[u8]) {
541 /// let cert = Cert::from_der(der);
542 /// # }
543 /// ```
544 #[derive(Clone)]
545 pub struct Cert(X509);
546 
547 impl Cert {
548     /// Deserializes a PEM-encoded `Cert` structure.
549     ///
550     /// The input should have a header like below:
551     ///
552     /// ```text
553     /// -----BEGIN CERTIFICATE-----
554     /// ```
555     ///
556     /// # Examples
557     ///
558     /// ```
559     /// # use ylong_http_client::Cert;
560     ///
561     /// # fn read_from_pem(pem: &[u8]) {
562     /// let cert = Cert::from_pem(pem);
563     /// # }
564     /// ```
from_pemnull565     pub fn from_pem(pem: &[u8]) -> Result<Self, HttpClientError> {
566         Ok(Self(X509::from_pem(pem).map_err(|e| {
567             HttpClientError::from_error(ErrorKind::Build, e)
568         })?))
569     }
570 
571     /// Deserializes a DER-encoded `Cert` structure.
572     ///
573     /// # Examples
574     ///
575     /// ```
576     /// use ylong_http_client::Cert;
577     ///
578     /// # fn read_from_der(der: &[u8]) {
579     /// let cert = Cert::from_der(der);
580     /// # }
581     /// ```
from_dernull582     pub fn from_der(der: &[u8]) -> Result<Self, HttpClientError> {
583         Ok(Self(X509::from_der(der).map_err(|e| {
584             HttpClientError::from_error(ErrorKind::Build, e)
585         })?))
586     }
587 
588     /// Deserializes a list of PEM-formatted certificates.
stack_from_pemnull589     pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<Self>, HttpClientError> {
590         Ok(X509::stack_from_pem(pem)
591             .map_err(|e| HttpClientError::from_error(ErrorKind::Build, e))?
592             .into_iter()
593             .map(Self)
594             .collect())
595     }
596 }
597 
598 /// Represents a server X509 certificates.
599 ///
600 /// You can use `from_pem` to parse a `&[u8]` into a list of certificates.
601 ///
602 /// # Examples
603 ///
604 /// ```
605 /// use ylong_http_client::Certificate;
606 ///
607 /// fn from_pem(pem: &[u8]) {
608 ///     let certs = Certificate::from_pem(pem);
609 /// }
610 /// ```
611 #[derive(Clone)]
612 pub struct Certificate {
613     inner: CertificateList,
614 }
615 
616 #[derive(Clone)]
617 pub(crate) enum CertificateList {
618     CertList(Vec<Cert>),
619     PathList(String),
620 }
621 
622 impl Certificate {
623     /// Deserializes a list of PEM-formatted certificates.
from_pemnull624     pub fn from_pem(pem: &[u8]) -> Result<Self, HttpClientError> {
625         let cert_list = X509::stack_from_pem(pem)
626             .map_err(|e| HttpClientError::from_error(ErrorKind::Build, e))?
627             .into_iter()
628             .map(Cert)
629             .collect();
630         Ok(Certificate {
631             inner: CertificateList::CertList(cert_list),
632         })
633     }
634 
635     /// Deserializes a list of PEM-formatted certificates.
from_pathnull636     pub fn from_path(path: &str) -> Result<Self, HttpClientError> {
637         Ok(Certificate {
638             inner: CertificateList::PathList(path.to_string()),
639         })
640     }
641 
642     pub(crate) fn into_inner(self) -> CertificateList {
643         self.inner
644     }
645 }
646 
647 #[cfg(test)]
648 mod ut_openssl_adapter {
649     use crate::util::c_openssl::adapter::CertificateList;
650     use crate::util::{Cert, TlsConfigBuilder, TlsFileType, TlsVersion};
651     use crate::{AlpnProtocol, AlpnProtocolList, Certificate};
652 
653     /// UT test cases for `TlsConfigBuilder::new`.
654     ///
655     /// # Brief
656     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`
657     /// 2. Checks if the result is as expected.
658     #[test]
ut_tls_config_builder_newnull659     fn ut_tls_config_builder_new() {
660         let _ = TlsConfigBuilder::default();
661         let builder = TlsConfigBuilder::new();
662         assert!(builder.ca_file("folder/ca.crt").build().is_err());
663     }
664 
665     /// UT test cases for `TlsConfigBuilder::set_max_proto_version`.
666     ///
667     /// # Brief
668     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
669     /// 2. Calls `set_max_proto_version`.
670     /// 3. Checks if the result is as expected.
671     #[test]
ut_set_max_proto_versionnull672     fn ut_set_max_proto_version() {
673         let builder = TlsConfigBuilder::new()
674             .max_proto_version(TlsVersion::TLS_1_2)
675             .build();
676         assert!(builder.is_ok());
677     }
678 
679     /// UT test cases for `TlsConfigBuilder::set_min_proto_version`.
680     ///
681     /// # Brief
682     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
683     /// 2. Calls `set_min_proto_version`.
684     /// 3. Checks if the result is as expected.
685     #[test]
ut_set_min_proto_versionnull686     fn ut_set_min_proto_version() {
687         let builder = TlsConfigBuilder::new()
688             .min_proto_version(TlsVersion::TLS_1_2)
689             .build();
690         assert!(builder.is_ok());
691     }
692 
693     /// UT test cases for `TlsConfigBuilder::set_cipher_list`.
694     ///
695     /// # Brief
696     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
697     /// 2. Calls `set_cipher_list`.
698     /// 3. Checks if the result is as expected.
699     #[test]
ut_set_cipher_listnull700     fn ut_set_cipher_list() {
701         let builder = TlsConfigBuilder::new()
702             .cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK")
703             .build();
704         assert!(builder.is_ok());
705     }
706 
707     /// UT test cases for `TlsConfigBuilder::set_certificate_file`.
708     ///
709     /// # Brief
710     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
711     /// 2. Calls `set_certificate_file`.
712     /// 3. Provides an invalid path as argument.
713     /// 4. Checks if the result is as expected.
714     #[test]
ut_set_certificate_filenull715     fn ut_set_certificate_file() {
716         let builder = TlsConfigBuilder::new()
717             .certificate_file("cert.pem", TlsFileType::PEM)
718             .build();
719         assert!(builder.is_err());
720     }
721 
722     /// UT test cases for `TlsConfigBuilder::set_certificate_chain_file`.
723     ///
724     /// # Brief
725     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
726     /// 2. Calls `set_certificate_chain_file`.
727     /// 3. Provides an invalid path as argument.
728     /// 4. Checks if the result is as expected.
729     #[test]
ut_set_certificate_chain_filenull730     fn ut_set_certificate_chain_file() {
731         let builder = TlsConfigBuilder::new()
732             .certificate_chain_file("cert.pem")
733             .build();
734         assert!(builder.is_err());
735     }
736 
737     /// UT test cases for `TlsConfigBuilder::add_root_certificates`.
738     ///
739     /// # Brief
740     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
741     /// 2. Calls `add_root_certificates`.
742     /// 3. Provides PEM-formatted certificates.
743     /// 4. Checks if the result is as expected.
744     #[test]
ut_add_root_certificatesnull745     fn ut_add_root_certificates() {
746         let certificate = Certificate::from_pem(include_bytes!("../../../tests/file/root-ca.pem"))
747             .expect("Sets certs error.");
748         let certs = match certificate.inner {
749             CertificateList::CertList(c) => c,
750             CertificateList::PathList(_) => vec![],
751         };
752 
753         let builder = TlsConfigBuilder::new().add_root_certificates(certs).build();
754         assert!(builder.is_ok());
755     }
756 
757     /// UT test cases for `Certificate::clone`.
758     ///
759     /// # Brief
760     /// 1. Creates a `Certificate` by calling `Certificate::from_pem`.
761     /// 2. Creates another `Certificate` by calling `Certificate::clone`.
762     /// 3. Checks if the result is as expected.
763     #[test]
764     #[allow(clippy::redundant_clone)]
ut_certificate_clonenull765     fn ut_certificate_clone() {
766         let pem = include_bytes!("../../../tests/file/root-ca.pem");
767         let certificate = Certificate::from_pem(pem).unwrap();
768         drop(certificate.clone());
769     }
770 
771     /// UT test cases for `Cert::clone`.
772     ///
773     /// # Brief
774     /// 1. Creates a `Cert` by calling `Cert::from_pem`.
775     /// 2. Creates another `Cert` by calling `Cert::clone`.
776     /// 3. Checks if the result is as expected.
777     #[test]
778     #[allow(clippy::redundant_clone)]
ut_cert_clonenull779     fn ut_cert_clone() {
780         let pem = include_bytes!("../../../tests/file/root-ca.pem");
781         let cert = Cert::from_pem(pem).unwrap();
782         drop(cert.clone());
783     }
784 
785     /// UT test cases for `TlsConfigBuilder::build_in_root_certs`.
786     ///
787     /// # Brief
788     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
789     /// 2. Calls `build_in_root_certs`.
790     /// 3. Checks if the result is as expected.
791     #[test]
ut_build_in_root_certsnull792     fn ut_build_in_root_certs() {
793         let builder = TlsConfigBuilder::new().build_in_root_certs(true).build();
794         assert!(builder.is_ok());
795     }
796 
797     /// UT test cases for `TlsConfigBuilder::set_alpn_proto_list`.
798     ///
799     /// # Brief
800     /// 1. Creates a `TlsConfigBuilder` by calling `TlsConfigBuilder::new`.
801     /// 2. Calls `set_alpn_proto_list`.
802     /// 3. Provides `AlpnProtocol`s.
803     /// 4. Checks if the result is as expected.
804     #[test]
ut_set_alpn_proto_listnull805     fn ut_set_alpn_proto_list() {
806         let builder = TlsConfigBuilder::new()
807             .alpn_proto_list(
808                 AlpnProtocolList::new()
809                     .extend(AlpnProtocol::HTTP11)
810                     .extend(AlpnProtocol::H2),
811             )
812             .build();
813         assert!(builder.is_ok());
814     }
815 
816     /// UT test cases for `TlsConfig::ssl`.
817     ///
818     /// # Brief
819     /// 1. Creates a `TlsConfig` by calling `TlsConfigBuilder::new` and
820     ///    `TlsConfigBuilder::build`.
821     /// 2. Creates a `TlsSsl` by calling `TlsConfig::ssl_new`.
822     /// 3. Calls `TlsSsl::into_inner`.
823     /// 4. Checks if the result is as expected.
824     #[test]
ut_tls_sslnull825     fn ut_tls_ssl() {
826         let config = TlsConfigBuilder::new()
827             .build()
828             .expect("TlsConfig build error.");
829         let _ssl = config
830             .ssl_new("host name")
831             .expect("Ssl build error.")
832             .into_inner();
833     }
834 
835     /// UT test cases for `TlsConfig::ssl` and `SslRef::set_verify_hostname`.
836     ///
837     /// # Brief
838     /// 1. Creates a `TlsConfig` by calling `TlsConfigBuilder::new` and
839     ///    `TlsConfigBuilder::build`.
840     /// 2. Sets hostname "" and verify_hostname.
841     /// 3. Creates a `Ssl` by calling `TlsConfig::ssl_new` then creates a
842     ///    `SslStream`.
843     /// 4. Calls `write` and `read` by `SslStream`.
844     /// 5. Checks if retures the segmentation fault `invalid memory reference`.
845     #[cfg(feature = "sync")]
846     #[test]
ut_tls_ssl_verify_hostnamenull847     fn ut_tls_ssl_verify_hostname() {
848         use std::io::{Read, Write};
849         use std::net::TcpStream;
850 
851         let config = TlsConfigBuilder::new()
852             .sni(false)
853             .danger_accept_invalid_hostnames(false)
854             .build()
855             .expect("TlsConfig build error.");
856 
857         let domain = String::from("");
858         let ssl = config
859             .ssl_new(domain.as_str())
860             .expect("Ssl build error.")
861             .into_inner();
862         let stream = TcpStream::connect("huawei.com:443").expect("Tcp stream error.");
863         let mut tls_stream = ssl.connect(stream).expect("Tls stream error.");
864 
865         tls_stream
866             .write_all(b"GET / HTTP/1.0\r\n\r\n")
867             .expect("Stream write error.");
868         let mut res = vec![];
869         tls_stream
870             .read_to_end(&mut res)
871             .expect("Stream read error.");
872         println!("{}", String::from_utf8_lossy(&res));
873     }
874 
875     /// UT test cases for `Cert::from_pem`.
876     ///
877     /// # Brief
878     /// 1. Creates a `Cert` by calling `Cert::from_pem`.
879     /// 2. Provides an invalid pem as argument.
880     /// 3. Checks if the result is as expected.
881     #[test]
ut_x509_from_pemnull882     fn ut_x509_from_pem() {
883         let pem = "(pem-content)";
884         let x509 = Cert::from_pem(pem.as_bytes());
885         assert!(x509.is_err());
886 
887         let cert = include_bytes!("../../../tests/file/root-ca.pem");
888         println!("{:?}", std::str::from_utf8(cert).unwrap());
889         let x509 = Cert::from_pem(cert);
890         assert!(x509.is_ok());
891     }
892 
893     /// UT test cases for `Cert::from_der`.
894     ///
895     /// # Brief
896     /// 1. Creates a `Cert` by calling `Cert::from_der`.
897     /// 2. Provides an invalid der as argument.
898     /// 3. Checks if the result is as expected.
899     #[test]
ut_x509_from_dernull900     fn ut_x509_from_der() {
901         let der = "(dar-content)";
902         let x509 = Cert::from_der(der.as_bytes());
903         assert!(x509.is_err());
904     }
905 
906     /// UT test cases for `Cert::stack_from_pem`.
907     ///
908     /// # Brief
909     /// 1. Creates a `Cert` by calling `Cert::stack_from_pem`.
910     /// 2. Provides pem bytes as argument.
911     /// 3. Checks if the result is as expected.
912     #[test]
ut_cert_stack_from_dernull913     fn ut_cert_stack_from_der() {
914         let v = include_bytes!("../../../tests/file/root-ca.pem");
915         let x509 = Cert::stack_from_pem(v);
916         assert!(x509.is_ok());
917     }
918 
919     /// UT test cases for `Certificate::from_pem`.
920     ///
921     /// # Brief
922     /// 1. Creates a `Certificate` by calling `Certificate::from_pem`.
923     /// 2. Provides pem bytes as argument.
924     /// 3. Checks if the result is as expected.
925     #[test]
ut_certificate_from_pemnull926     fn ut_certificate_from_pem() {
927         let v = include_bytes!("../../../tests/file/root-ca.pem");
928         let certs = Certificate::from_pem(v);
929         assert!(certs.is_ok());
930     }
931 }
932