Skip to content

Commit 2a47df2

Browse files
committed
Merge branch 'dt/send-email-client-cert' into next
"git send-email" learns to support use of client-side certificates. * dt/send-email-client-cert: send-email: add client certificate options
2 parents 60b308a + a8215a2 commit 2a47df2

3 files changed

Lines changed: 71 additions & 11 deletions

File tree

Documentation/config/sendemail.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ sendemail.smtpSSLCertPath::
1212
Path to ca-certificates (either a directory or a single file).
1313
Set it to an empty string to disable certificate verification.
1414

15+
sendemail.smtpSSLClientCert::
16+
Path to the client certificate file to present if requested by the
17+
server. This is required when the server is set up to verify client
18+
certificates. If the corresponding private key is not included in the
19+
file, it must be supplied using `sendemail.smtpSSLClientKey` or the
20+
`--smtp-ssl-client-key` option.
21+
22+
sendemail.smtpSSLClientKey::
23+
Path to the client private key file that corresponds to the client
24+
certificate. To avoid misconfiguration, this configuration must be used
25+
in conjunction with `sendemail.smtpSSLClientKey` or the
26+
`--smtp-ssl-client-cert` option. If the client key is included in the
27+
client certificate, the choice of private key depends on the format of
28+
the certificate. Visit https://metacpan.org/pod/IO::Socket::SSL for more
29+
details.
30+
1531
sendemail.<identity>.*::
1632
Identity-specific versions of the `sendemail.*` parameters
1733
found below, taking precedence over those when this

Documentation/git-send-email.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,25 @@ must be used for each option.
290290
variable, if set, or the backing SSL library's compiled-in default
291291
otherwise (which should be the best choice on most platforms).
292292

293+
--smtp-ssl-client-cert <path>::
294+
Path to the client certificate file to present if requested by the
295+
server. This option is required when the server is set up to verify
296+
client certificates. If the corresponding private key is not included in
297+
the file, it must be supplied using the `sendemail.smtpSSLClientKey`
298+
configuration variable or the `--smtp-ssl-client-key` option. Defaults
299+
to the value of the `sendemail.smtpSSLClientCert` configuration
300+
variable, if set.
301+
302+
--smtp-ssl-client-key <path>::
303+
Path to the client private key file that corresponds to the client
304+
certificate. To avoid misconfiguration, this option must be used in
305+
conjunction with the `sendemail.smtpSSLClientKey` configuration variable
306+
or the `--smtp-ssl-client-cert` option. If the client key is included in
307+
the client certificate, the choice of private key depends on the format
308+
of the certificate. Visit https://metacpan.org/pod/IO::Socket::SSL for
309+
more details. Defaults to the value of the `sendemail.smtpSSLClientKey`
310+
configuration variable, if set.
311+
293312
--smtp-user=<user>::
294313
Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`;
295314
if a username is not specified (with `--smtp-user` or `sendemail.smtpUser`),

git-send-email.perl

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ sub usage {
6666
--smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
6767
Pass an empty string to disable certificate
6868
verification.
69+
--smtp-ssl-client-cert <str> * Path to the client certificate file
70+
--smtp-ssl-client-key <str> * Path to the private key file for the client certificate
6971
--smtp-domain <str> * The domain name sent to HELO/EHLO handshake
7072
--smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
7173
"none" to disable authentication.
@@ -279,6 +281,7 @@ sub do_edit {
279281
my ($to_cmd, $cc_cmd, $header_cmd);
280282
my ($smtp_server, $smtp_server_port, @smtp_server_options);
281283
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
284+
my ($smtp_ssl_client_cert, $smtp_ssl_client_key);
282285
my ($batch_size, $relogin_delay);
283286
my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
284287
my ($imap_sent_folder);
@@ -350,6 +353,8 @@ sub do_edit {
350353
my %config_path_settings = (
351354
"aliasesfile" => \@alias_files,
352355
"smtpsslcertpath" => \$smtp_ssl_cert_path,
356+
"smtpsslclientcert" => \$smtp_ssl_client_cert,
357+
"smtpsslclientkey" => \$smtp_ssl_client_key,
353358
"mailmap.file" => \$mailmap_file,
354359
"mailmap.blob" => \$mailmap_blob,
355360
);
@@ -531,6 +536,8 @@ sub config_regexp {
531536
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
532537
"smtp-encryption=s" => \$smtp_encryption,
533538
"smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
539+
"smtp-ssl-client-cert=s" => \$smtp_ssl_client_cert,
540+
"smtp-ssl-client-key=s" => \$smtp_ssl_client_key,
534541
"smtp-debug:i" => \$debug_net_smtp,
535542
"smtp-domain:s" => \$smtp_domain,
536543
"smtp-auth=s" => \$smtp_auth,
@@ -1522,6 +1529,8 @@ sub handle_smtp_error {
15221529
}
15231530

15241531
sub ssl_verify_params {
1532+
my %ret = ();
1533+
15251534
eval {
15261535
require IO::Socket::SSL;
15271536
IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
@@ -1533,20 +1542,36 @@ sub ssl_verify_params {
15331542

15341543
if (!defined $smtp_ssl_cert_path) {
15351544
# use the OpenSSL defaults
1536-
return (SSL_verify_mode => SSL_VERIFY_PEER());
1545+
$ret{SSL_verify_mode} = SSL_VERIFY_PEER();
1546+
}
1547+
else {
1548+
if ($smtp_ssl_cert_path eq "") {
1549+
$ret{SSL_verify_mode} = SSL_VERIFY_NONE();
1550+
} elsif (-d $smtp_ssl_cert_path) {
1551+
$ret{SSL_verify_mode} = SSL_VERIFY_PEER();
1552+
$ret{SSL_ca_path} = $smtp_ssl_cert_path;
1553+
} elsif (-f $smtp_ssl_cert_path) {
1554+
$ret{SSL_verify_mode} = SSL_VERIFY_PEER();
1555+
$ret{SSL_ca_file} = $smtp_ssl_cert_path;
1556+
} else {
1557+
die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1558+
}
15371559
}
15381560

1539-
if ($smtp_ssl_cert_path eq "") {
1540-
return (SSL_verify_mode => SSL_VERIFY_NONE());
1541-
} elsif (-d $smtp_ssl_cert_path) {
1542-
return (SSL_verify_mode => SSL_VERIFY_PEER(),
1543-
SSL_ca_path => $smtp_ssl_cert_path);
1544-
} elsif (-f $smtp_ssl_cert_path) {
1545-
return (SSL_verify_mode => SSL_VERIFY_PEER(),
1546-
SSL_ca_file => $smtp_ssl_cert_path);
1547-
} else {
1548-
die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1561+
if (defined $smtp_ssl_client_cert) {
1562+
$ret{SSL_cert_file} = $smtp_ssl_client_cert;
15491563
}
1564+
if (defined $smtp_ssl_client_key) {
1565+
if (!defined $smtp_ssl_client_cert) {
1566+
# Accept the client key only when a certificate is given.
1567+
# We die here because this case is a user error.
1568+
die sprintf(__("Only client key \"%s\" specified"),
1569+
$smtp_ssl_client_key);
1570+
}
1571+
$ret{SSL_key_file} = $smtp_ssl_client_key;
1572+
}
1573+
1574+
return %ret;
15501575
}
15511576

15521577
sub file_name_is_absolute {

0 commit comments

Comments
 (0)