From d4e66d38b1e39684d4ca826d410f87f7799566ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Sch=C3=B6nberger?= Date: Tue, 27 Feb 2024 15:33:32 +0100 Subject: [PATCH 1/2] Add config for additional SMTP TLS root certs --- .env.template | 4 ++++ src/config.rs | 2 ++ src/mail.rs | 23 ++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 0189cc7a..9bbe0fa3 100644 --- a/.env.template +++ b/.env.template @@ -525,6 +525,10 @@ ## Only use this as a last resort if you are not able to use a valid certificate. # SMTP_ACCEPT_INVALID_HOSTNAMES=false +## Accept additional root certs +## Paths to PEM files, separated by semicolons +# SMTP_ADDITIONAL_ROOT_CERTS= + ########################## ### Rocket settings ### ########################## diff --git a/src/config.rs b/src/config.rs index 489a229d..49d64bc1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -674,6 +674,8 @@ make_config! { smtp_accept_invalid_certs: bool, true, def, false; /// Accept Invalid Hostnames (Know the risks!) |> DANGEROUS: Allow invalid hostnames. This option introduces significant vulnerabilities to man-in-the-middle attacks! smtp_accept_invalid_hostnames: bool, true, def, false; + /// Accept additional root certs |> Paths to PEM files, separated by semicolons + smtp_additional_root_certs: String, true, option; }, /// Email 2FA Settings diff --git a/src/mail.rs b/src/mail.rs index 151554a1..1fa92e1e 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -1,12 +1,13 @@ use std::str::FromStr; use chrono::NaiveDateTime; +use once_cell::sync::Lazy; use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; use lettre::{ message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, - transport::smtp::client::{Tls, TlsParameters}, + transport::smtp::client::{Certificate, Tls, TlsParameters}, transport::smtp::extension::ClientId, Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, }; @@ -29,6 +30,21 @@ fn sendmail_transport() -> AsyncSendmailTransport { } } +static SMTP_ADDITIONAL_ROOT_CERTS: Lazy>> = Lazy::new(|| { + Some( + CONFIG + .smtp_additional_root_certs()? + .split(';') + .filter(|path| !path.is_empty()) + .map(|path| { + let cert = std::fs::read(path) + .unwrap_or_else(|e| panic!("Error loading additional SMTP root certificate file {path}.\n{e}")); + Certificate::from_pem(&cert).unwrap_or_else(|e| panic!("Error decoding certificate file {path}.\n{e}")) + }) + .collect(), + ) +}); + fn smtp_transport() -> AsyncSmtpTransport { use std::time::Duration; let host = CONFIG.smtp_host().unwrap(); @@ -46,6 +62,11 @@ fn smtp_transport() -> AsyncSmtpTransport { if CONFIG.smtp_accept_invalid_certs() { tls_parameters = tls_parameters.dangerous_accept_invalid_certs(true); } + if let Some(ref certs) = *SMTP_ADDITIONAL_ROOT_CERTS { + for cert in certs { + tls_parameters = tls_parameters.add_root_certificate(cert.clone()); + } + } let tls_parameters = tls_parameters.build().unwrap(); if CONFIG.smtp_security() == *"force_tls" { From f0366d054f89d79222ac4d65aaf3deafe2dcaee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Sch=C3=B6nberger?= Date: Tue, 27 Feb 2024 15:42:13 +0100 Subject: [PATCH 2/2] Add config to disable system root cert store --- .env.template | 3 +++ src/config.rs | 2 ++ src/mail.rs | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 9bbe0fa3..7417d0ba 100644 --- a/.env.template +++ b/.env.template @@ -529,6 +529,9 @@ ## Paths to PEM files, separated by semicolons # SMTP_ADDITIONAL_ROOT_CERTS= +## Use system root certificate store for TLS host verification +# SMTP_USE_SYSTEM_ROOT_CERTS=true + ########################## ### Rocket settings ### ########################## diff --git a/src/config.rs b/src/config.rs index 49d64bc1..a4470aea 100644 --- a/src/config.rs +++ b/src/config.rs @@ -676,6 +676,8 @@ make_config! { smtp_accept_invalid_hostnames: bool, true, def, false; /// Accept additional root certs |> Paths to PEM files, separated by semicolons smtp_additional_root_certs: String, true, option; + /// Use system root certificate store for TLS host verification + smtp_use_system_root_certs: bool, true, def, true; }, /// Email 2FA Settings diff --git a/src/mail.rs b/src/mail.rs index 1fa92e1e..a481df08 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -7,7 +7,7 @@ use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; use lettre::{ message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, - transport::smtp::client::{Certificate, Tls, TlsParameters}, + transport::smtp::client::{Certificate, CertificateStore, Tls, TlsParameters}, transport::smtp::extension::ClientId, Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, }; @@ -67,6 +67,9 @@ fn smtp_transport() -> AsyncSmtpTransport { tls_parameters = tls_parameters.add_root_certificate(cert.clone()); } } + if !CONFIG.smtp_use_system_root_certs() { + tls_parameters = tls_parameters.certificate_store(CertificateStore::None); + } let tls_parameters = tls_parameters.build().unwrap(); if CONFIG.smtp_security() == *"force_tls" {