send-email: be explicit with SSL certificate verification

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>

Ramkumar Ramachandra committed Jul 18, 2013 at 09:53 UTC 35035bbf074d1a4c59cd5f99282c12197105da08
3 files changed +48 -3
Documentation/config.txt
+4
@@ -2022,6 +2022,10 @@ sendemail.smtpencryption::
2022 sendemail.smtpssl::
2023 Deprecated alias for 'sendemail.smtpencryption = ssl'.
2024
2025 +sendemail.smtpsslcertpath::
2026 + Path to ca-certificates (either a directory or a single file).
2027 + Set it to an empty string to disable certificate verification.
2028 +
2029 sendemail.<identity>.*::
2030 Identity-specific versions of the 'sendemail.*' parameters
2031 found below, taking precedence over those when the this
Documentation/git-send-email.txt
+6
@@ -198,6 +198,12 @@ must be used for each option.
198 --smtp-ssl::
199 Legacy alias for '--smtp-encryption ssl'.
200
201 +--smtp-ssl-cert-path::
202 + Path to ca-certificates (either a directory or a single file).
203 + Set it to an empty string to disable certificate verification.
204 + Defaults to the value set to the 'sendemail.smtpsslcertpath'
205 + configuration variable, if set, or `/etc/ssl/certs` otherwise.
206 +
207 --smtp-user=<user>::
208 Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
209 if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
git-send-email.perl
+38 -3
@@ -69,6 +69,9 @@ git send-email [options] <file | directory | rev-list options >
69 --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
70 --smtp-encryption <str> * tls or ssl; anything else disables.
71 --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
72 + --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
73 + Pass an empty string to disable certificate
74 + verification.
75 --smtp-domain <str> * The domain name sent to HELO/EHLO handshake
76 --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
77
@@ -194,7 +197,7 @@ sub do_edit {
197 my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc);
198 my ($to_cmd, $cc_cmd);
199 my ($smtp_server, $smtp_server_port, @smtp_server_options);
197 -my ($smtp_authuser, $smtp_encryption);
200 +my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
201 my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
202 my ($validate, $confirm);
203 my (@suppress_cc);
@@ -222,6 +225,7 @@ my %config_settings = (
225 "smtpserveroption" => \@smtp_server_options,
226 "smtpuser" => \$smtp_authuser,
227 "smtppass" => \$smtp_authpass,
228 + "smtpsslcertpath" => \$smtp_ssl_cert_path,
229 "smtpdomain" => \$smtp_domain,
230 "to" => \@initial_to,
231 "tocmd" => \$to_cmd,
@@ -302,6 +306,7 @@ my $rc = GetOptions("h" => \$help,
306 "smtp-pass:s" => \$smtp_authpass,
307 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
308 "smtp-encryption=s" => \$smtp_encryption,
309 + "smtp-ssl-cert-path" => \$smtp_ssl_cert_path,
310 "smtp-debug:i" => \$debug_net_smtp,
311 "smtp-domain:s" => \$smtp_domain,
312 "identity=s" => \$identity,
@@ -1089,6 +1094,34 @@ sub smtp_auth_maybe {
1094 return $auth;
1095 }
1096
1097 +sub ssl_verify_params {
1098 + eval {
1099 + require IO::Socket::SSL;
1100 + IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1101 + };
1102 + if ($@) {
1103 + print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1104 + return;
1105 + }
1106 +
1107 + if (!defined $smtp_ssl_cert_path) {
1108 + $smtp_ssl_cert_path = "/etc/ssl/certs";
1109 + }
1110 +
1111 + if ($smtp_ssl_cert_path eq "") {
1112 + return (SSL_verify_mode => SSL_VERIFY_NONE());
1113 + } elsif (-d $smtp_ssl_cert_path) {
1114 + return (SSL_verify_mode => SSL_VERIFY_PEER(),
1115 + SSL_ca_path => $smtp_ssl_cert_path);
1116 + } elsif (-f $smtp_ssl_cert_path) {
1117 + return (SSL_verify_mode => SSL_VERIFY_PEER(),
1118 + SSL_ca_file => $smtp_ssl_cert_path);
1119 + } else {
1120 + print STDERR "Not using SSL_VERIFY_PEER because the CA path does not exist.\n";
1121 + return (SSL_verify_mode => SSL_VERIFY_NONE());
1122 + }
1123 +}
1124 +
1125 # Returns 1 if the message was sent, and 0 otherwise.
1126 # In actuality, the whole program dies when there
1127 # is an error sending a message.
@@ -1194,7 +1227,8 @@ X-Mailer: git-send-email $gitversion
1227 $smtp_domain ||= maildomain();
1228 $smtp ||= Net::SMTP::SSL->new($smtp_server,
1229 Hello => $smtp_domain,
1197 - Port => $smtp_server_port);
1230 + Port => $smtp_server_port,
1231 + ssl_verify_params());
1232 }
1233 else {
1234 require Net::SMTP;
@@ -1207,7 +1241,8 @@ X-Mailer: git-send-email $gitversion
1241 $smtp->command('STARTTLS');
1242 $smtp->response();
1243 if ($smtp->code == 220) {
1210 - $smtp = Net::SMTP::SSL->start_SSL($smtp)
1244 + $smtp = Net::SMTP::SSL->start_SSL($smtp,
1245 + ssl_verify_params())
1246 or die "STARTTLS failed! ".$smtp->message;
1247 $smtp_encryption = '';
1248 # Send EHLO again to receive fresh