mirror of
https://github.com/chatmail/core.git
synced 2026-05-06 16:36:59 +03:00
Try to lock strict TLS if certificate checks are automatic
This commit is contained in:
@@ -14,8 +14,7 @@ use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
|||||||
|
|
||||||
use crate::dc_tools::EmailAddress;
|
use crate::dc_tools::EmailAddress;
|
||||||
use crate::imap::Imap;
|
use crate::imap::Imap;
|
||||||
use crate::login_param::Socks5Config;
|
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam, Socks5Config};
|
||||||
use crate::login_param::{LoginParam, ServerLoginParam};
|
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::oauth2::dc_get_oauth2_addr;
|
use crate::oauth2::dc_get_oauth2_addr;
|
||||||
use crate::provider::{Protocol, Socket, UsernamePattern};
|
use crate::provider::{Protocol, Socket, UsernamePattern};
|
||||||
@@ -250,6 +249,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
strict_tls: Some(provider.strict_tls),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -290,6 +290,12 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
|||||||
port: param.imap.port,
|
port: param.imap.port,
|
||||||
socket: param.imap.security,
|
socket: param.imap.security,
|
||||||
username: param.imap.user.clone(),
|
username: param.imap.user.clone(),
|
||||||
|
strict_tls: match param.imap.certificate_checks {
|
||||||
|
CertificateChecks::Automatic => None,
|
||||||
|
CertificateChecks::Strict => Some(true),
|
||||||
|
CertificateChecks::AcceptInvalidCertificates2
|
||||||
|
| CertificateChecks::AcceptInvalidCertificates => Some(false),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if !servers
|
if !servers
|
||||||
@@ -302,6 +308,12 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
|||||||
port: param.smtp.port,
|
port: param.smtp.port,
|
||||||
socket: param.smtp.security,
|
socket: param.smtp.security,
|
||||||
username: param.smtp.user.clone(),
|
username: param.smtp.user.clone(),
|
||||||
|
strict_tls: match param.smtp.certificate_checks {
|
||||||
|
CertificateChecks::Automatic => None,
|
||||||
|
CertificateChecks::Strict => Some(true),
|
||||||
|
CertificateChecks::AcceptInvalidCertificates2
|
||||||
|
| CertificateChecks::AcceptInvalidCertificates => Some(false),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let servers = expand_param_vector(servers, ¶m.addr, ¶m_domain);
|
let servers = expand_param_vector(servers, ¶m.addr, ¶m_domain);
|
||||||
@@ -331,6 +343,11 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
|||||||
smtp_param.server = smtp_server.hostname.clone();
|
smtp_param.server = smtp_server.hostname.clone();
|
||||||
smtp_param.port = smtp_server.port;
|
smtp_param.port = smtp_server.port;
|
||||||
smtp_param.security = smtp_server.socket;
|
smtp_param.security = smtp_server.socket;
|
||||||
|
smtp_param.certificate_checks = match smtp_server.strict_tls {
|
||||||
|
Some(true) => CertificateChecks::Strict,
|
||||||
|
Some(false) => CertificateChecks::AcceptInvalidCertificates,
|
||||||
|
None => CertificateChecks::Automatic,
|
||||||
|
};
|
||||||
|
|
||||||
match try_smtp_one_param(
|
match try_smtp_one_param(
|
||||||
&context_smtp,
|
&context_smtp,
|
||||||
@@ -374,6 +391,11 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
|||||||
param.imap.server = imap_server.hostname.clone();
|
param.imap.server = imap_server.hostname.clone();
|
||||||
param.imap.port = imap_server.port;
|
param.imap.port = imap_server.port;
|
||||||
param.imap.security = imap_server.socket;
|
param.imap.security = imap_server.socket;
|
||||||
|
param.imap.certificate_checks = match imap_server.strict_tls {
|
||||||
|
Some(true) => CertificateChecks::Strict,
|
||||||
|
Some(false) => CertificateChecks::AcceptInvalidCertificates,
|
||||||
|
None => CertificateChecks::Automatic,
|
||||||
|
};
|
||||||
|
|
||||||
match try_imap_one_param(
|
match try_imap_one_param(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ fn parse_serverparams(in_emailaddr: &str, xml_raw: &str) -> Result<Vec<ServerPar
|
|||||||
hostname: server.hostname,
|
hostname: server.hostname,
|
||||||
port: server.port,
|
port: server.port,
|
||||||
username: server.username,
|
username: server.username,
|
||||||
|
strict_tls: None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ fn protocols_to_serverparams(protocols: Vec<ProtocolTag>) -> Vec<ServerParams> {
|
|||||||
hostname: protocol.server,
|
hostname: protocol.server,
|
||||||
port: protocol.port,
|
port: protocol.port,
|
||||||
username: String::new(),
|
username: String::new(),
|
||||||
|
strict_tls: None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ pub(crate) struct ServerParams {
|
|||||||
|
|
||||||
/// Username, empty if unknown.
|
/// Username, empty if unknown.
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
|
||||||
|
/// Whether TLS certificates should be strictly checked or not, `None` for automatic.
|
||||||
|
pub strict_tls: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerParams {
|
impl ServerParams {
|
||||||
@@ -128,6 +131,23 @@ impl ServerParams {
|
|||||||
vec![self]
|
vec![self]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expand_strict_tls(self) -> Vec<ServerParams> {
|
||||||
|
if self.strict_tls.is_none() {
|
||||||
|
vec![
|
||||||
|
Self {
|
||||||
|
strict_tls: Some(true), // Strict.
|
||||||
|
..self.clone()
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
strict_tls: None, // Automatic.
|
||||||
|
..self
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![self]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expands vector of `ServerParams`, replacing placeholders with
|
/// Expands vector of `ServerParams`, replacing placeholders with
|
||||||
@@ -138,10 +158,32 @@ pub(crate) fn expand_param_vector(
|
|||||||
domain: &str,
|
domain: &str,
|
||||||
) -> Vec<ServerParams> {
|
) -> Vec<ServerParams> {
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
// The order of expansion is important: ports are expanded the
|
.map(|params| {
|
||||||
// last, so they are changed the first. Username is only
|
if params.socket == Socket::Plain {
|
||||||
// changed if default value (address with domain) didn't work
|
ServerParams {
|
||||||
// for all available hosts and ports.
|
// Avoid expanding plaintext configuration into configuration with and without
|
||||||
|
// `strict_tls` if `strict_tls` is set to `None` as `strict_tls` is not used for
|
||||||
|
// plaintext connections. Always setting it to "enabled", just in case.
|
||||||
|
strict_tls: Some(true),
|
||||||
|
..params
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// The order of expansion is important.
|
||||||
|
//
|
||||||
|
// Ports are expanded the last, so they are changed the first. Username is only changed if
|
||||||
|
// default value (address with domain) didn't work for all available hosts and ports.
|
||||||
|
//
|
||||||
|
// Strict TLS must be expanded first, so we try all configurations with strict TLS first
|
||||||
|
// and only then try again without strict TLS. Otherwise we may lock to wrong hostname
|
||||||
|
// without strict TLS when another hostname with strict TLS is available. For example, if
|
||||||
|
// both smtp.example.net and mail.example.net are running an SMTP server, but both use a
|
||||||
|
// certificate that is only valid for mail.example.net, we want to skip smtp.example.net
|
||||||
|
// and use mail.example.net with strict TLS instead of using smtp.example.net without
|
||||||
|
// strict TLS.
|
||||||
|
.flat_map(|params| params.expand_strict_tls().into_iter())
|
||||||
.flat_map(|params| params.expand_usernames(addr).into_iter())
|
.flat_map(|params| params.expand_usernames(addr).into_iter())
|
||||||
.flat_map(|params| params.expand_hostnames(domain).into_iter())
|
.flat_map(|params| params.expand_hostnames(domain).into_iter())
|
||||||
.flat_map(|params| params.expand_ports().into_iter())
|
.flat_map(|params| params.expand_ports().into_iter())
|
||||||
@@ -161,6 +203,7 @@ mod tests {
|
|||||||
port: 0,
|
port: 0,
|
||||||
socket: Socket::Ssl,
|
socket: Socket::Ssl,
|
||||||
username: "foobar".to_string(),
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: Some(true),
|
||||||
}],
|
}],
|
||||||
"foobar@example.net",
|
"foobar@example.net",
|
||||||
"example.net",
|
"example.net",
|
||||||
@@ -174,6 +217,7 @@ mod tests {
|
|||||||
port: 993,
|
port: 993,
|
||||||
socket: Socket::Ssl,
|
socket: Socket::Ssl,
|
||||||
username: "foobar".to_string(),
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: Some(true)
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -184,6 +228,7 @@ mod tests {
|
|||||||
port: 123,
|
port: 123,
|
||||||
socket: Socket::Automatic,
|
socket: Socket::Automatic,
|
||||||
username: "foobar".to_string(),
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: None,
|
||||||
}],
|
}],
|
||||||
"foobar@example.net",
|
"foobar@example.net",
|
||||||
"example.net",
|
"example.net",
|
||||||
@@ -197,16 +242,59 @@ mod tests {
|
|||||||
hostname: "example.net".to_string(),
|
hostname: "example.net".to_string(),
|
||||||
port: 123,
|
port: 123,
|
||||||
socket: Socket::Ssl,
|
socket: Socket::Ssl,
|
||||||
username: "foobar".to_string()
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: Some(true),
|
||||||
},
|
},
|
||||||
ServerParams {
|
ServerParams {
|
||||||
protocol: Protocol::Smtp,
|
protocol: Protocol::Smtp,
|
||||||
hostname: "example.net".to_string(),
|
hostname: "example.net".to_string(),
|
||||||
port: 123,
|
port: 123,
|
||||||
socket: Socket::Starttls,
|
socket: Socket::Starttls,
|
||||||
username: "foobar".to_string()
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: Some(true)
|
||||||
|
},
|
||||||
|
ServerParams {
|
||||||
|
protocol: Protocol::Smtp,
|
||||||
|
hostname: "example.net".to_string(),
|
||||||
|
port: 123,
|
||||||
|
socket: Socket::Ssl,
|
||||||
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: None,
|
||||||
|
},
|
||||||
|
ServerParams {
|
||||||
|
protocol: Protocol::Smtp,
|
||||||
|
hostname: "example.net".to_string(),
|
||||||
|
port: 123,
|
||||||
|
socket: Socket::Starttls,
|
||||||
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: None
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test that strict_tls is not expanded for plaintext connections.
|
||||||
|
let v = expand_param_vector(
|
||||||
|
vec![ServerParams {
|
||||||
|
protocol: Protocol::Smtp,
|
||||||
|
hostname: "example.net".to_string(),
|
||||||
|
port: 123,
|
||||||
|
socket: Socket::Plain,
|
||||||
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: None,
|
||||||
|
}],
|
||||||
|
"foobar@example.net",
|
||||||
|
"example.net",
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
v,
|
||||||
|
vec![ServerParams {
|
||||||
|
protocol: Protocol::Smtp,
|
||||||
|
hostname: "example.net".to_string(),
|
||||||
|
port: 123,
|
||||||
|
socket: Socket::Plain,
|
||||||
|
username: "foobar".to_string(),
|
||||||
|
strict_tls: Some(true)
|
||||||
|
}],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user