|
| 1 | +use serde::{Deserialize, Serialize}; |
| 2 | +use std::path::PathBuf; |
| 3 | + |
| 4 | +// Wrapped into a sub-module to avoid exposing `TlsClientPolicyConfig` in two places: |
| 5 | +// inside `pavex::tls::config` and `pavex::tls::client`. |
| 6 | +// We only want users to see `pavex::tls::client::TlsClientPolicyConfig`. |
| 7 | +pub(crate) mod _config { |
| 8 | + use super::*; |
| 9 | + |
| 10 | + #[derive(Debug, Default, Clone, Deserialize, Serialize)] |
| 11 | + /// Configure the TLS policy for a client. |
| 12 | + /// |
| 13 | + /// It covers: |
| 14 | + /// - The [cryptographic stack](`Self::crypto_provider`) used to secure the connection. |
| 15 | + /// - Which [TLS versions](`Self::allowed_versions`) are allowed. |
| 16 | + /// - The [certificate verification](`Self::certificate_verification`) mechanism used to verify server certificates. |
| 17 | + /// |
| 18 | + /// For testing/development purposes only, it exposes a few [insecure](`Self::insecure`) configuration options |
| 19 | + /// that lower the security posture of your client. |
| 20 | + /// |
| 21 | + /// # Defaults |
| 22 | + /// |
| 23 | + /// The default configuration should be suitable for most production environments: |
| 24 | + /// |
| 25 | + #[doc = include_str!("../../../tests/fixtures/tls_config/default.yaml")] |
| 26 | + /// |
| 27 | + /// # Overriding the default configuration |
| 28 | + /// |
| 29 | + /// If you want to deviate from the default configuration, it's enough to specify the fields you |
| 30 | + /// want to override. |
| 31 | + /// |
| 32 | + /// ## Example: Disable TLS 1.2 |
| 33 | + /// |
| 34 | + #[doc = include_str!("../../../tests/fixtures/tls_config/disable_tls_1_2.yaml")] |
| 35 | + /// |
| 36 | + /// ## Example: Trust additional root certificates |
| 37 | + /// |
| 38 | + #[doc = include_str!("../../../tests/fixtures/tls_config/additional_roots.yaml")] |
| 39 | + /// |
| 40 | + /// ## Example: Disable certificate verification |
| 41 | + /// |
| 42 | + #[doc = include_str!("../../../tests/fixtures/tls_config/skip_verification.yaml")] |
| 43 | + pub struct TlsClientPolicyConfig { |
| 44 | + /// The cryptographic stack used to secure the connection. |
| 45 | + /// |
| 46 | + /// Refer to the documentation for [`CryptoProviderConfig`](CryptoProviderConfig) |
| 47 | + /// for more details. |
| 48 | + #[serde(default)] |
| 49 | + #[serde(with = "serde_yaml::with::singleton_map_recursive")] |
| 50 | + pub crypto_provider: CryptoProviderConfig, |
| 51 | + /// Which TLS versions are allowed. |
| 52 | + /// |
| 53 | + /// Refer to the documentation for [`TlsVersionsConfig`](TlsVersionsConfig) |
| 54 | + /// for more details. |
| 55 | + #[serde(default)] |
| 56 | + pub allowed_versions: AllowedTlsVersionsConfig, |
| 57 | + /// The mechanism used to verify server certificates. |
| 58 | + /// |
| 59 | + /// Refer to the documentation for [`CertificateVerificationConfig`](CertificateVerificationConfig) |
| 60 | + /// for more details. |
| 61 | + #[serde(default)] |
| 62 | + pub certificate_verification: CertificateVerificationConfig, |
| 63 | + /// Dangerous configuration options that lower the security |
| 64 | + /// posture of your client. |
| 65 | + /// |
| 66 | + /// These options should never be used in production scenarios. |
| 67 | + /// They are available for testing/development purposes only. |
| 68 | + #[serde(default)] |
| 69 | + pub insecure: InsecureTlsClientConfig, |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] |
| 74 | +#[non_exhaustive] |
| 75 | +/// Which TLS versions are allowed. |
| 76 | +/// |
| 77 | +/// By default, TLS 1.2 and TLS 1.3 are enabled. |
| 78 | +/// |
| 79 | +/// # Security |
| 80 | +/// |
| 81 | +/// The lack of support for TLS 1.0 and TLS 1.1 is intentional. |
| 82 | +pub struct AllowedTlsVersionsConfig { |
| 83 | + /// Enables TLS 1.2 if `true`. |
| 84 | + /// |
| 85 | + /// It requires the server to support TLS 1.2. |
| 86 | + #[serde(default = "default_v1_2")] |
| 87 | + pub v1_2: bool, |
| 88 | + /// Enables TLS 1.3 if `true`. |
| 89 | + /// |
| 90 | + /// It requires the server to support TLS 1.3. |
| 91 | + #[serde(default = "default_v1_3")] |
| 92 | + pub v1_3: bool, |
| 93 | +} |
| 94 | + |
| 95 | +fn default_v1_2() -> bool { |
| 96 | + true |
| 97 | +} |
| 98 | + |
| 99 | +fn default_v1_3() -> bool { |
| 100 | + true |
| 101 | +} |
| 102 | + |
| 103 | +impl Default for AllowedTlsVersionsConfig { |
| 104 | + fn default() -> Self { |
| 105 | + Self { |
| 106 | + v1_2: default_v1_2(), |
| 107 | + v1_3: default_v1_3(), |
| 108 | + } |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 113 | +/// Configure how server certificates are verified. |
| 114 | +/// |
| 115 | +/// # Default |
| 116 | +/// |
| 117 | +/// By default, we rely on verification machinery of the underlying operating system. |
| 118 | +/// Refer to the documentation for [`rustls-platform-verifier`](https://docs.rs/rustls-platform-verifier/latest/rustls_platform_verifier/) |
| 119 | +/// for more information on how each platform handles certificate verification. |
| 120 | +/// |
| 121 | +/// # Customization |
| 122 | +/// |
| 123 | +/// Set [`additional_roots`][`CertificateVerificationConfig::additional_roots`] to trust |
| 124 | +/// additional root certificates in addition to the ones already trusted |
| 125 | +/// by the operating system. |
| 126 | +/// |
| 127 | +/// # Skipping Verification |
| 128 | +/// |
| 129 | +/// If you want to skip certificate verification altogether, check out the [`insecure`][`TlsClientConfig::insecure`] |
| 130 | +/// options in [`TlsClientConfig`]. |
| 131 | +/// |
| 132 | +/// ## Incorrect Usage |
| 133 | +/// |
| 134 | +/// Setting [`use_os_verifier`][`CertificateVerificationConfig::use_os_verifier`] to `false`, with |
| 135 | +/// no [`additional_roots`][`CertificateVerificationConfig::additional_roots`] specified, does **not** |
| 136 | +/// disable certificate verification. It does instead cause all certificate verification attempts to fail. |
| 137 | +/// |
| 138 | +/// We treat this scenario as a misconfiguration and return an error at runtime, when |
| 139 | +/// trying to initialize the client. |
| 140 | +pub struct CertificateVerificationConfig { |
| 141 | + /// Whether to use the certificate verification machinery provided by |
| 142 | + /// the underlying operating system. |
| 143 | + /// |
| 144 | + /// Defaults to `true`. |
| 145 | + #[serde(default = "default_use_os_verifier")] |
| 146 | + pub use_os_verifier: bool, |
| 147 | + /// Trust one or more additional root certificates. |
| 148 | + /// |
| 149 | + /// If [`use_os_verifier`][`CertificateVerificationConfig::use_os_verifier`] is `false`, |
| 150 | + /// these will be the only trusted root certificates. |
| 151 | + /// If [`use_os_verifier`][`CertificateVerificationConfig::use_os_verifier`] is `true`, these will be |
| 152 | + /// trusted **in addition** to the ones already trusted by the underlying operating system. |
| 153 | + /// |
| 154 | + /// They can either be loaded from files or inlined in configuration. |
| 155 | + #[serde(default)] |
| 156 | + #[serde(with = "serde_yaml::with::singleton_map_recursive")] |
| 157 | + pub additional_roots: Vec<RootCertificate>, |
| 158 | +} |
| 159 | + |
| 160 | +fn default_use_os_verifier() -> bool { |
| 161 | + true |
| 162 | +} |
| 163 | + |
| 164 | +impl Default for CertificateVerificationConfig { |
| 165 | + fn default() -> Self { |
| 166 | + CertificateVerificationConfig { |
| 167 | + use_os_verifier: default_use_os_verifier(), |
| 168 | + additional_roots: Default::default(), |
| 169 | + } |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 174 | +#[serde(rename_all = "snake_case")] |
| 175 | +#[non_exhaustive] |
| 176 | +pub enum RootCertificate { |
| 177 | + File { |
| 178 | + encoding: RootCertificateFileEncoding, |
| 179 | + path: PathBuf, |
| 180 | + }, |
| 181 | + Inline { |
| 182 | + encoding: RootCertificateInlineEncoding, |
| 183 | + data: String, |
| 184 | + }, |
| 185 | +} |
| 186 | + |
| 187 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 188 | +#[serde(rename_all = "snake_case")] |
| 189 | +#[non_exhaustive] |
| 190 | +/// Supported encodings for the root certificate in [`RootCertificate::File`]. |
| 191 | +pub enum RootCertificateFileEncoding { |
| 192 | + /// A DER-encoded X.509 certificate; as specified in [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1). |
| 193 | + Der, |
| 194 | + /// A PEM-encoded X.509 certificate; as specified in [RFC 7468](https://datatracker.ietf.org/doc/html/rfc7468#section-5). |
| 195 | + Pem, |
| 196 | +} |
| 197 | + |
| 198 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 199 | +#[serde(rename_all = "snake_case")] |
| 200 | +#[non_exhaustive] |
| 201 | +/// Supported encodings for the root certificate in [`RootCertificate::Inline`]. |
| 202 | +pub enum RootCertificateInlineEncoding { |
| 203 | + /// A DER-encoded X.509 certificate; as specified in [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1). |
| 204 | + /// |
| 205 | + /// Since DER is a binary format, we expect the data to be [base64-encoded](https://datatracker.ietf.org/doc/html/rfc4648#section-4). |
| 206 | + Base64Der, |
| 207 | + /// A PEM-encoded X.509 certificate; as specified in [RFC 7468](https://datatracker.ietf.org/doc/html/rfc7468#section-5). |
| 208 | + /// |
| 209 | + /// Since PEM is a text format, we don't expect the data to be base64-encoded. |
| 210 | + Pem, |
| 211 | +} |
| 212 | + |
| 213 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 214 | +#[non_exhaustive] |
| 215 | +pub struct InsecureTlsClientConfig { |
| 216 | + /// Don't verify server certificates. |
| 217 | + /// |
| 218 | + /// Extremely dangerous option, limit its usage to local development environments. |
| 219 | + #[serde(default = "default_skip_verification")] |
| 220 | + pub skip_verification: bool, |
| 221 | +} |
| 222 | + |
| 223 | +impl Default for InsecureTlsClientConfig { |
| 224 | + fn default() -> Self { |
| 225 | + InsecureTlsClientConfig { |
| 226 | + skip_verification: default_skip_verification(), |
| 227 | + } |
| 228 | + } |
| 229 | +} |
| 230 | + |
| 231 | +fn default_skip_verification() -> bool { |
| 232 | + false |
| 233 | +} |
| 234 | + |
| 235 | +#[derive(Debug, Clone, Deserialize, Serialize)] |
| 236 | +#[serde(rename_all = "kebab-case", tag = "name")] |
| 237 | +#[non_exhaustive] |
| 238 | +pub enum CryptoProviderConfig { |
| 239 | + AwsLcRs { |
| 240 | + #[serde(default)] |
| 241 | + require_fips: bool, |
| 242 | + }, |
| 243 | + Ring, |
| 244 | +} |
| 245 | + |
| 246 | +impl Default for CryptoProviderConfig { |
| 247 | + fn default() -> Self { |
| 248 | + CryptoProviderConfig::AwsLcRs { |
| 249 | + require_fips: false, |
| 250 | + } |
| 251 | + } |
| 252 | +} |
0 commit comments