Skip to content

Commit 1e744f8

Browse files
dxdxdtgitster
authored andcommitted
send-mail: add client certificate options
For SMTP servers that do "mutual certificate verification", the mail client is required to present its own TLS certificate as well. This patch adds --smtp-ssl-client-cert and --smtp-ssl-client-key for such servers. Signed-off-by: David Timber <dxdt@dev.snart.me> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 67ad421 commit 1e744f8

3 files changed

Lines changed: 60 additions & 11 deletions

File tree

Documentation/config/sendemail.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ 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 a client certificate file to present to the SMTP server.
17+
18+
sendemail.smtpSSLClientKey::
19+
Path to the client private key file.
20+
1521
sendemail.<identity>.*::
1622
Identity-specific versions of the `sendemail.*` parameters
1723
found below, taking precedence over those when this

Documentation/git-send-email.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,23 @@ 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 a client certificate file to present to the SMTP server. This option
295+
can be used when the server verifies the certificate from the client. The
296+
format could be in either PKCS12 or PEM. In the latter case, the private key
297+
can be specified using `--smtp-ssl-client-key` option. More more
298+
detail, see
299+
https://metacpan.org/pod/IO::Socket::SSL#SSL_cert_file-|-SSL_cert-|-SSL_key_file-|-SSL_key
300+
Defaults to the value of the `sendemail.smtpSSLClientCert` configuration
301+
variable, if set.
302+
303+
--smtp-ssl-client-key <path>::
304+
Optional path to the client private key file. If this is not given and a
305+
PKCS12 certificate file is used, the private key from the PKCS12 certificate
306+
will be used(see `--smtp-ssl-client-cert`). Defaults to the value of the
307+
`sendemail.smtpSSLClientKey` configuration variable, if set.
308+
309+
293310
--smtp-user=<user>::
294311
Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`;
295312
if a username is not specified (with `--smtp-user` or `sendemail.smtpUser`),

git-send-email.perl

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ 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 client certificate file to present to SMTP server
70+
--smtp-ssl-client-key <str> * Path to the private key file for the client certificate
71+
(optional if a PKCS12 client certificate is used)
6972
--smtp-domain <str> * The domain name sent to HELO/EHLO handshake
7073
--smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
7174
"none" to disable authentication.
@@ -279,6 +282,7 @@ sub do_edit {
279282
my ($to_cmd, $cc_cmd, $header_cmd);
280283
my ($smtp_server, $smtp_server_port, @smtp_server_options);
281284
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
285+
my ($smtp_ssl_client_cert, $smtp_ssl_client_key);
282286
my ($batch_size, $relogin_delay);
283287
my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
284288
my ($imap_sent_folder);
@@ -350,6 +354,8 @@ sub do_edit {
350354
my %config_path_settings = (
351355
"aliasesfile" => \@alias_files,
352356
"smtpsslcertpath" => \$smtp_ssl_cert_path,
357+
"smtpsslclientcert" => \$smtp_ssl_client_cert,
358+
"smtpsslclientkey" => \$smtp_ssl_client_key,
353359
"mailmap.file" => \$mailmap_file,
354360
"mailmap.blob" => \$mailmap_blob,
355361
);
@@ -531,6 +537,8 @@ sub config_regexp {
531537
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
532538
"smtp-encryption=s" => \$smtp_encryption,
533539
"smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
540+
"smtp-ssl-client-cert=s" => \$smtp_ssl_client_cert,
541+
"smtp-ssl-client-key=s" => \$smtp_ssl_client_key,
534542
"smtp-debug:i" => \$debug_net_smtp,
535543
"smtp-domain:s" => \$smtp_domain,
536544
"smtp-auth=s" => \$smtp_auth,
@@ -1520,6 +1528,8 @@ sub handle_smtp_error {
15201528
}
15211529

15221530
sub ssl_verify_params {
1531+
my %ret = ();
1532+
15231533
eval {
15241534
require IO::Socket::SSL;
15251535
IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
@@ -1531,20 +1541,36 @@ sub ssl_verify_params {
15311541

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

1537-
if ($smtp_ssl_cert_path eq "") {
1538-
return (SSL_verify_mode => SSL_VERIFY_NONE());
1539-
} elsif (-d $smtp_ssl_cert_path) {
1540-
return (SSL_verify_mode => SSL_VERIFY_PEER(),
1541-
SSL_ca_path => $smtp_ssl_cert_path);
1542-
} elsif (-f $smtp_ssl_cert_path) {
1543-
return (SSL_verify_mode => SSL_VERIFY_PEER(),
1544-
SSL_ca_file => $smtp_ssl_cert_path);
1545-
} else {
1546-
die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1560+
if (defined $smtp_ssl_client_cert) {
1561+
# The cert could be in PKCS12 format, which can store both cert and key
1562+
$ret{SSL_cert_file} = $smtp_ssl_client_cert;
1563+
$ret{SSL_use_cert} = 1;
15471564
}
1565+
if (defined $smtp_ssl_client_key) {
1566+
if (!defined $smtp_ssl_client_cert) {
1567+
# doesn't make sense to use a client key only
1568+
die sprintf(__("Only client key \"%s\" specified"), $smtp_ssl_client_key);
1569+
}
1570+
$ret{SSL_key_file} = $smtp_ssl_client_key;
1571+
}
1572+
1573+
return %ret;
15481574
}
15491575

15501576
sub file_name_is_absolute {

0 commit comments

Comments
 (0)