ferron/setup/
tls_single.rs

1use ferron_common::{get_value, get_values};
2use rustls::crypto::aws_lc_rs::cipher_suite::*;
3use rustls::crypto::aws_lc_rs::default_provider;
4use rustls::crypto::aws_lc_rs::kx_group::*;
5use rustls::crypto::CryptoProvider;
6use rustls::version::{TLS12, TLS13};
7use rustls::{ConfigBuilder, ServerConfig, WantsVerifier, WantsVersions};
8
9/// Initializes the cryptography provider for Rustls.
10pub fn init_crypto_provider(
11  global_configuration: Option<&ferron_common::config::ServerConfiguration>,
12) -> Result<CryptoProvider, anyhow::Error> {
13  let mut crypto_provider = default_provider();
14  set_cipher_suites(&mut crypto_provider, global_configuration)?;
15  set_ecdh_curves(&mut crypto_provider, global_configuration)?;
16  Ok(crypto_provider)
17}
18
19/// Sets cipher suites based on the global configuration
20fn set_cipher_suites(
21  crypto_provider: &mut CryptoProvider,
22  global_configuration: Option<&ferron_common::config::ServerConfiguration>,
23) -> Result<(), anyhow::Error> {
24  let cipher_suite: Vec<&ferron_common::config::ServerConfigurationValue> =
25    global_configuration.map_or(vec![], |c| get_values!("tls_cipher_suite", c));
26  if !cipher_suite.is_empty() {
27    let mut cipher_suites = Vec::new();
28    let cipher_suite_iter = cipher_suite.iter();
29    for cipher_suite_config in cipher_suite_iter {
30      if let Some(cipher_suite) = cipher_suite_config.as_str() {
31        let cipher_suite_to_add = match cipher_suite {
32          "TLS_AES_128_GCM_SHA256" => TLS13_AES_128_GCM_SHA256,
33          "TLS_AES_256_GCM_SHA384" => TLS13_AES_256_GCM_SHA384,
34          "TLS_CHACHA20_POLY1305_SHA256" => TLS13_CHACHA20_POLY1305_SHA256,
35          "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" => TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
36          "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" => TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
37          "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" => TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
38          "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" => TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
39          "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" => TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
40          "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" => TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
41          _ => Err(anyhow::anyhow!(
42            "The \"{}\" cipher suite is not supported",
43            cipher_suite
44          ))?,
45        };
46        cipher_suites.push(cipher_suite_to_add);
47      }
48    }
49    crypto_provider.cipher_suites = cipher_suites;
50  }
51  Ok(())
52}
53
54/// Sets ECDH curves based on the global configuration.
55fn set_ecdh_curves(
56  crypto_provider: &mut CryptoProvider,
57  global_configuration: Option<&ferron_common::config::ServerConfiguration>,
58) -> Result<(), anyhow::Error> {
59  let ecdh_curves = global_configuration.map_or(vec![], |c| get_values!("tls_ecdh_curve", c));
60  if !ecdh_curves.is_empty() {
61    let mut kx_groups = Vec::new();
62    let ecdh_curves_iter = ecdh_curves.iter();
63    for ecdh_curve_config in ecdh_curves_iter {
64      if let Some(ecdh_curve) = ecdh_curve_config.as_str() {
65        let kx_group_to_add = match ecdh_curve {
66          "secp256r1" => SECP256R1,
67          "secp384r1" => SECP384R1,
68          "x25519" => X25519,
69          "x25519mklem768" => X25519MLKEM768,
70          "mklem768" => MLKEM768,
71          _ => Err(anyhow::anyhow!("The \"{}\" ECDH curve is not supported", ecdh_curve))?,
72        };
73        kx_groups.push(kx_group_to_add);
74      }
75    }
76    crypto_provider.kx_groups = kx_groups;
77  }
78  Ok(())
79}
80
81/// Sets the TLS version based on the global configuration.
82pub fn set_tls_version(
83  tls_config_builder_wants_versions: ConfigBuilder<ServerConfig, WantsVersions>,
84  global_configuration: Option<&ferron_common::config::ServerConfiguration>,
85) -> Result<ConfigBuilder<ServerConfig, WantsVerifier>, anyhow::Error> {
86  let min_tls_version_option = global_configuration
87    .and_then(|c| get_value!("tls_min_version", c))
88    .and_then(|v| v.as_str());
89  let max_tls_version_option = global_configuration
90    .and_then(|c| get_value!("tls_max_version", c))
91    .and_then(|v| v.as_str());
92
93  let tls_config_builder_wants_verifier = if min_tls_version_option.is_none() && max_tls_version_option.is_none() {
94    tls_config_builder_wants_versions.with_safe_default_protocol_versions()?
95  } else {
96    let tls_versions = [("TLSv1.2", &TLS12), ("TLSv1.3", &TLS13)];
97    let min_tls_version_index = min_tls_version_option
98      .map_or(Some(0), |v| tls_versions.iter().position(|p| p.0 == v))
99      .ok_or(anyhow::anyhow!("Invalid minimum TLS version"))?;
100    let max_tls_version_index = max_tls_version_option
101      .map_or(Some(tls_versions.len() - 1), |v| {
102        tls_versions.iter().position(|p| p.0 == v)
103      })
104      .ok_or(anyhow::anyhow!("Invalid maximum TLS version"))?;
105    if max_tls_version_index < min_tls_version_index {
106      Err(anyhow::anyhow!("Maximum TLS version is older than minimum TLS version"))?
107    }
108    tls_config_builder_wants_versions.with_protocol_versions(
109      &tls_versions[min_tls_version_index..=max_tls_version_index]
110        .iter()
111        .map(|p| p.1)
112        .collect::<Vec<_>>(),
113    )?
114  };
115
116  Ok(tls_config_builder_wants_verifier)
117}