start_SSL fails to set SSL_verifycn_name
https://bugs.debian.org#973654
As part of a new server setup, I have installed amavisd-new. Since it is running in a different host than the MX, I have set up TLS between every part of the system, but amavis fails to connect back to the MX, with the following error:
(!!)Upgrading socket to TLS failed (in ssl_upgrade): hostname verification failed\n
After some investigation, I found that amavis is not using the IO::Socket::SSL library correctly. The default (and reasonable) SSL parameters for the client TLS connection are:
%smtp_tls_client_options = ( SSL_verifycn_scheme => 'smtp', );
When the
$tls_security_level_out
variable is set to 'may' or 'encrypt', the socket is upgraded to TLS using thestart_SSL
method and the options set by the user but without any way for the library to determine the hostname of the server, and therefore its identity can't be verified.The documentation for the
SSL_verifycn_name
option of thestart_SSL
method states (https://metacpan.org/pod/IO::Socket::SSL#SSL_verifycn_name):SSL_verifycn_name
Set the name which is used in verification of hostname. If SSL_verifycn_scheme is set and no SSL_verifycn_name is given it will try to use SSL_hostname or PeerHost and PeerAddr settings and fail if no name can be determined. If SSL_verifycn_scheme is not set it will use a default scheme and warn if it cannot determine a hostname, but it will not fail. Using PeerHost or PeerAddr works only if you create the connection directly with IO::Socket::SSL->new, if an IO::Socket::INET object is upgraded with start_SSL the name has to be given in SSL_verifycn_name or SSL_hostname.
The solution for this is pretty simple:
SSL_verifycn_name
has to be set by the calling function using the same hostname used to connect the TCP socket in the first place. A workaround is to pass this option manually in the configuration, but that fails to work if there is more than one SSL target (for example, different hostnames fornotify_method
andforward_method
).