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