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