send-email: be explicit with SSL certificate verification
authorRamkumar Ramachandra <artagnon@gmail.com>
Thu, 18 Jul 2013 16:53:11 +0000 (09:53 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Jul 2013 23:01:30 +0000 (16:01 -0700)
When initiating an SSL connection without explicitly specifying the
SSL certificate verification mode, Net::SMTP::SSL defaults to no
verification, but recent versions of the module gives a warning
against this use of the default.

Enable certificate verification by default, using /etc/ssl/certs as
the default path for certificates of certificate authorities. This
path can be overriden by the --smtp-ssl-cert-path command line
option and the sendemail.smtpSSLCertPath configuration variable.

Passing an empty string as the path for CA certificates path disables
the SSL certificate verification explicitly, which does not trigger
the warning from recent versions of Net::SMTP::SSL.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
Helped-by: Brian M. Carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
Documentation/git-send-email.txt
git-send-email.perl
index 6e53fc507489fb2add3184998b8ec2a43e84b249..4de154ca6714e24e532cee3a7f352d59682b6895 100644 (file)
@@ -2022,6 +2022,10 @@ sendemail.smtpencryption::
 sendemail.smtpssl::
        Deprecated alias for 'sendemail.smtpencryption = ssl'.
 
+sendemail.smtpsslcertpath::
+       Path to ca-certificates (either a directory or a single file).
+       Set it to an empty string to disable certificate verification.
+
 sendemail.<identity>.*::
        Identity-specific versions of the 'sendemail.*' parameters
        found below, taking precedence over those when the this
index 40a9a9abc14f175738986b244207655b296cc31d..f0e57a597b6e551d891c064fa69837db632237c6 100644 (file)
@@ -198,6 +198,12 @@ must be used for each option.
 --smtp-ssl::
        Legacy alias for '--smtp-encryption ssl'.
 
+--smtp-ssl-cert-path::
+       Path to ca-certificates (either a directory or a single file).
+       Set it to an empty string to disable certificate verification.
+       Defaults to the value set to the 'sendemail.smtpsslcertpath'
+       configuration variable, if set, or `/etc/ssl/certs` otherwise.
+
 --smtp-user=<user>::
        Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
        if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
index bd13cc812d2a0115edcdd2c3ec146665ddfc5e29..60eaed32eab2ccb59bd00ac97adbf9c3e39244d6 100755 (executable)
@@ -69,6 +69,9 @@ sub usage {
     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
     --smtp-encryption       <str>  * tls or ssl; anything else disables.
     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
+    --smtp-ssl-cert-path    <str>  * Path to ca-certificates (either directory or file).
+                                     Pass an empty string to disable certificate
+                                     verification.
     --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
     --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
 
@@ -194,7 +197,7 @@ sub do_edit {
 my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc);
 my ($to_cmd, $cc_cmd);
 my ($smtp_server, $smtp_server_port, @smtp_server_options);
-my ($smtp_authuser, $smtp_encryption);
+my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
 my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
 my ($validate, $confirm);
 my (@suppress_cc);
@@ -222,6 +225,7 @@ sub do_edit {
     "smtpserveroption" => \@smtp_server_options,
     "smtpuser" => \$smtp_authuser,
     "smtppass" => \$smtp_authpass,
+    "smtpsslcertpath" => \$smtp_ssl_cert_path,
     "smtpdomain" => \$smtp_domain,
     "to" => \@initial_to,
     "tocmd" => \$to_cmd,
@@ -302,6 +306,7 @@ sub signal_handler {
                    "smtp-pass:s" => \$smtp_authpass,
                    "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
                    "smtp-encryption=s" => \$smtp_encryption,
+                   "smtp-ssl-cert-path" => \$smtp_ssl_cert_path,
                    "smtp-debug:i" => \$debug_net_smtp,
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
@@ -1089,6 +1094,34 @@ sub smtp_auth_maybe {
        return $auth;
 }
 
+sub ssl_verify_params {
+       eval {
+               require IO::Socket::SSL;
+               IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
+       };
+       if ($@) {
+               print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
+               return;
+       }
+
+       if (!defined $smtp_ssl_cert_path) {
+               $smtp_ssl_cert_path = "/etc/ssl/certs";
+       }
+
+       if ($smtp_ssl_cert_path eq "") {
+               return (SSL_verify_mode => SSL_VERIFY_NONE());
+       } elsif (-d $smtp_ssl_cert_path) {
+               return (SSL_verify_mode => SSL_VERIFY_PEER(),
+                       SSL_ca_path => $smtp_ssl_cert_path);
+       } elsif (-f $smtp_ssl_cert_path) {
+               return (SSL_verify_mode => SSL_VERIFY_PEER(),
+                       SSL_ca_file => $smtp_ssl_cert_path);
+       } else {
+               print STDERR "Not using SSL_VERIFY_PEER because the CA path does not exist.\n";
+               return (SSL_verify_mode => SSL_VERIFY_NONE());
+       }
+}
+
 # Returns 1 if the message was sent, and 0 otherwise.
 # In actuality, the whole program dies when there
 # is an error sending a message.
@@ -1194,7 +1227,8 @@ sub send_message {
                        $smtp_domain ||= maildomain();
                        $smtp ||= Net::SMTP::SSL->new($smtp_server,
                                                      Hello => $smtp_domain,
-                                                     Port => $smtp_server_port);
+                                                     Port => $smtp_server_port,
+                                                     ssl_verify_params());
                }
                else {
                        require Net::SMTP;
@@ -1207,7 +1241,8 @@ sub send_message {
                                $smtp->command('STARTTLS');
                                $smtp->response();
                                if ($smtp->code == 220) {
-                                       $smtp = Net::SMTP::SSL->start_SSL($smtp)
+                                       $smtp = Net::SMTP::SSL->start_SSL($smtp,
+                                                                         ssl_verify_params())
                                                or die "STARTTLS failed! ".$smtp->message;
                                        $smtp_encryption = '';
                                        # Send EHLO again to receive fresh