Gert van Dijk
2021-May-01 12:04 UTC
Ability to reject invalid client certificate at TLS handshake time
Hi, After a bit of struggling I've been able to set up TLS client certificate authentication with Dovecot for both IMAP and Submission. Users are required to present a valid certificate, cool so far! What I noticed however on non-StartTLS listeners IMAPS (993) and SMTPS (465), is that during the TLS handhake presenting a valid client certificate is seemingly optional and is only checked later at time of protocol-level login (external auth in my case). I'd like to change that for security purposes and also a bit of obscurity. Not having the ability to interact with Dovecot on protocol level lowers the attack vector as well as the ease of checking my network security. Also, it would prevent (anonymous) network scanners to easily detect what kind of service is running on the port as they can see the IMAP/SMTP banner without presenting a valid TLS client certificate currently. Is it possible in any version of Dovecot to configure it to set up a TLS server listening context that requires a handshake with a valid client certificate? I'm using Dovecot 2.3.4.1 (actual Debian Buster version 2.3.4.1-5+deb10u6), but willing to upgrade to any newer version when this is offered. Going through some newer revisions changelog this seems not the case, so I didn't spend time on upgrading yet. Relevant config snippets for IMAP authenticating proxy that I use (something similar for Submission): # Opens 143 on StartTLS and 993 in wrapped TLS-only mode. # Only 993 is exposed to the internet. protocols = imap passdb { driver = static args = proxy=y host=10.1.2.3 port=1143 pass=masterpass nopassword=y } auth_username_format = %n ssl = required ssl_cert = </etc/dovecot-ssl/cert.crt ssl_key = </etc/dovecot-ssl/key.pem ssl_prefer_server_ciphers = yes ssl_min_protocol = TLSv1.2 ssl_cipher_list = [omitted for brevity] ssl_ca = </etc/dovecot-ssl/client-ca.crt ssl_verify_client_cert = yes # Required to set this to 'no' if no CRL is set up yet ssl_require_crl = no auth_ssl_require_client_cert = yes # Take the username from the client certificate (CN) auth_mechanisms = external auth_ssl_username_from_cert = yes ssl_cert_username_field = commonName Current behaviour from a client when deliberately not presenting a client certificate shows the IMAP banner: $ openssl s_client -connect myserver:993 CONNECTED(00000003) --- Certificate chain 0 [...] --- Server certificate -----BEGIN CERTIFICATE----- [...] --- Acceptable client certificate CA names C = NL, O = Gert van Dijk, [...] --- SSL handshake has read 1096 bytes and written 413 bytes Verification: OK --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 384 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) --- * OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ LOGINDISABLED AUTH=EXTERNAL] Dovecot (Debian) ready. Expected: TLS alert during handshake, e.g. on my Apache TLS client certificate required configured instance: $ openssl s_client -connect myserver:443 139676785239360:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1543:SSL alert number 40 IOW, I was hoping for something like this to exist: ssl_verify_client_cert = required OR service imap-login { inet_listener imaps { port = 993 ssl = client-cert-required } } Thanks, Gert
Tom Hendrikx
2021-May-01 15:46 UTC
Ability to reject invalid client certificate at TLS handshake time
Hi, Client certificate authentication simply replaces username/password authentication within the IMAP protocol. Before starting authentication, the client still needs to talk to the server, and the server still needs to announce that it is ready to accept your certificate. On this website you'll find a nice picture of the global auth flow: https://comodosslstore.com/blog/what-is-ssl-tls-client-authentication-how-does-it-work.html Wouldn't it be much easier to just change the banner to something less obvious than the default? Unauthenticated connections will still be able to see you have an IMAP server, but the fact that you're using Dovecot might be invisible. Switching to a non-standard port might also help to mislead network scanners. However IMHO the fact that you're running a public network service will never change due to the fact that Dovecot is simply that: a public network service. Your focus should be on useful protection based on the assumption that an external attacker already knows that your server is there, not on trying to hide it. Kind regards, Tom On 01-05-2021 14:04, Gert van Dijk wrote:> Hi, > > After a bit of struggling I've been able to set up TLS client > certificate authentication with Dovecot for both IMAP and Submission. > Users are required to present a valid certificate, cool so far! > > What I noticed however on non-StartTLS listeners IMAPS (993) and SMTPS > (465), is that during the TLS handhake presenting a valid client > certificate is seemingly optional and is only checked later at time of > protocol-level login (external auth in my case). I'd like to change > that for security purposes and also a bit of obscurity. Not having the > ability to interact with Dovecot on protocol level lowers the attack > vector as well as the ease of checking my network security. Also, it > would prevent (anonymous) network scanners to easily detect what kind > of service is running on the port as they can see the IMAP/SMTP banner > without presenting a valid TLS client certificate currently. > > Is it possible in any version of Dovecot to configure it to set up a > TLS server listening context that requires a handshake with a valid > client certificate? > > I'm using Dovecot 2.3.4.1 (actual Debian Buster version > 2.3.4.1-5+deb10u6), but willing to upgrade to any newer version when > this is offered. Going through some newer revisions changelog this > seems not the case, so I didn't spend time on upgrading yet. > > Relevant config snippets for IMAP authenticating proxy that I use > (something similar for Submission): > > # Opens 143 on StartTLS and 993 in wrapped TLS-only mode. > # Only 993 is exposed to the internet. > protocols = imap > passdb { > driver = static > args = proxy=y host=10.1.2.3 port=1143 pass=masterpass nopassword=y > } > auth_username_format = %n > ssl = required > ssl_cert = </etc/dovecot-ssl/cert.crt > ssl_key = </etc/dovecot-ssl/key.pem > ssl_prefer_server_ciphers = yes > ssl_min_protocol = TLSv1.2 > ssl_cipher_list = [omitted for brevity] > ssl_ca = </etc/dovecot-ssl/client-ca.crt > ssl_verify_client_cert = yes > # Required to set this to 'no' if no CRL is set up yet > ssl_require_crl = no > auth_ssl_require_client_cert = yes > # Take the username from the client certificate (CN) > auth_mechanisms = external > auth_ssl_username_from_cert = yes > ssl_cert_username_field = commonName > > Current behaviour from a client when deliberately not presenting a > client certificate shows the IMAP banner: > $ openssl s_client -connect myserver:993 > CONNECTED(00000003) > --- > Certificate chain > 0 [...] > --- > Server certificate > -----BEGIN CERTIFICATE----- > [...] > --- > Acceptable client certificate CA names > C = NL, O = Gert van Dijk, [...] > --- > SSL handshake has read 1096 bytes and written 413 bytes > Verification: OK > --- > New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 > Server public key is 384 bit > Secure Renegotiation IS NOT supported > Compression: NONE > Expansion: NONE > No ALPN negotiated > Early data was not sent > Verify return code: 0 (ok) > --- > * OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE > LITERAL+ LOGINDISABLED AUTH=EXTERNAL] Dovecot (Debian) ready. > > > Expected: > TLS alert during handshake, e.g. on my Apache TLS client certificate > required configured instance: > $ openssl s_client -connect myserver:443 > 139676785239360:error:14094410:SSL routines:ssl3_read_bytes:sslv3 > alert handshake failure:../ssl/record/rec_layer_s3.c:1543:SSL alert > number 40 > > > IOW, I was hoping for something like this to exist: > ssl_verify_client_cert = required > OR > service imap-login { > inet_listener imaps { > port = 993 > ssl = client-cert-required > } > } > > > Thanks, > > Gert >