aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-03-12 10:56:04 -0700
committerJunio C Hamano <gitster@pobox.com>2026-03-12 10:56:05 -0700
commit898549142353fa105ad2c466a52e497620d12bb3 (patch)
treef0bf8f9cc777e0bb831365cf44a36a1661ed35c1
parentfdfa7f64d641fe21661087d7bdb0f58d66e3d2de (diff)
parenta8215a2051411bbaa1ea1464026cb473fbf8f83c (diff)
downloadgit-898549142353fa105ad2c466a52e497620d12bb3.tar.xz
Merge branch 'dt/send-email-client-cert'
"git send-email" learns to support use of client-side certificates. * dt/send-email-client-cert: send-email: add client certificate options
-rw-r--r--Documentation/config/sendemail.adoc16
-rw-r--r--Documentation/git-send-email.adoc19
-rwxr-xr-xgit-send-email.perl47
3 files changed, 71 insertions, 11 deletions
diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc
index 90164c734d..6560ecc5ab 100644
--- a/Documentation/config/sendemail.adoc
+++ b/Documentation/config/sendemail.adoc
@@ -12,6 +12,22 @@ sendemail.smtpSSLCertPath::
Path to ca-certificates (either a directory or a single file).
Set it to an empty string to disable certificate verification.
+sendemail.smtpSSLClientCert::
+ Path to the client certificate file to present if requested by the
+ server. This is required when the server is set up to verify client
+ certificates. If the corresponding private key is not included in the
+ file, it must be supplied using `sendemail.smtpSSLClientKey` or the
+ `--smtp-ssl-client-key` option.
+
+sendemail.smtpSSLClientKey::
+ Path to the client private key file that corresponds to the client
+ certificate. To avoid misconfiguration, this configuration must be used
+ in conjunction with `sendemail.smtpSSLClientKey` or the
+ `--smtp-ssl-client-cert` option. If the client key is included in the
+ client certificate, the choice of private key depends on the format of
+ the certificate. Visit https://metacpan.org/pod/IO::Socket::SSL for more
+ details.
+
sendemail.<identity>.*::
Identity-specific versions of the `sendemail.*` parameters
found below, taking precedence over those when this
diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc
index 741f748614..dea3b86460 100644
--- a/Documentation/git-send-email.adoc
+++ b/Documentation/git-send-email.adoc
@@ -290,6 +290,25 @@ must be used for each option.
variable, if set, or the backing SSL library's compiled-in default
otherwise (which should be the best choice on most platforms).
+--smtp-ssl-client-cert <path>::
+ Path to the client certificate file to present if requested by the
+ server. This option is required when the server is set up to verify
+ client certificates. If the corresponding private key is not included in
+ the file, it must be supplied using the `sendemail.smtpSSLClientKey`
+ configuration variable or the `--smtp-ssl-client-key` option. Defaults
+ to the value of the `sendemail.smtpSSLClientCert` configuration
+ variable, if set.
+
+--smtp-ssl-client-key <path>::
+ Path to the client private key file that corresponds to the client
+ certificate. To avoid misconfiguration, this option must be used in
+ conjunction with the `sendemail.smtpSSLClientKey` configuration variable
+ or the `--smtp-ssl-client-cert` option. If the client key is included in
+ the client certificate, the choice of private key depends on the format
+ of the certificate. Visit https://metacpan.org/pod/IO::Socket::SSL for
+ more details. Defaults to the value of the `sendemail.smtpSSLClientKey`
+ configuration variable, if set.
+
--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`),
diff --git a/git-send-email.perl b/git-send-email.perl
index 350afa3e71..1448b44097 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -66,6 +66,8 @@ git send-email --translate-aliases
--smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
Pass an empty string to disable certificate
verification.
+ --smtp-ssl-client-cert <str> * Path to the client certificate file
+ --smtp-ssl-client-key <str> * Path to the private key file for the client certificate
--smtp-domain <str> * The domain name sent to HELO/EHLO handshake
--smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
"none" to disable authentication.
@@ -279,6 +281,7 @@ my ($cover_cc, $cover_to);
my ($to_cmd, $cc_cmd, $header_cmd);
my ($smtp_server, $smtp_server_port, @smtp_server_options);
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
+my ($smtp_ssl_client_cert, $smtp_ssl_client_key);
my ($batch_size, $relogin_delay);
my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
my ($imap_sent_folder);
@@ -350,6 +353,8 @@ my %config_settings = (
my %config_path_settings = (
"aliasesfile" => \@alias_files,
"smtpsslcertpath" => \$smtp_ssl_cert_path,
+ "smtpsslclientcert" => \$smtp_ssl_client_cert,
+ "smtpsslclientkey" => \$smtp_ssl_client_key,
"mailmap.file" => \$mailmap_file,
"mailmap.blob" => \$mailmap_blob,
);
@@ -531,6 +536,8 @@ my %options = (
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
"smtp-encryption=s" => \$smtp_encryption,
"smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
+ "smtp-ssl-client-cert=s" => \$smtp_ssl_client_cert,
+ "smtp-ssl-client-key=s" => \$smtp_ssl_client_key,
"smtp-debug:i" => \$debug_net_smtp,
"smtp-domain:s" => \$smtp_domain,
"smtp-auth=s" => \$smtp_auth,
@@ -1522,6 +1529,8 @@ sub handle_smtp_error {
}
sub ssl_verify_params {
+ my %ret = ();
+
eval {
require IO::Socket::SSL;
IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
@@ -1533,20 +1542,36 @@ sub ssl_verify_params {
if (!defined $smtp_ssl_cert_path) {
# use the OpenSSL defaults
- return (SSL_verify_mode => SSL_VERIFY_PEER());
+ $ret{SSL_verify_mode} = SSL_VERIFY_PEER();
+ }
+ else {
+ if ($smtp_ssl_cert_path eq "") {
+ $ret{SSL_verify_mode} = SSL_VERIFY_NONE();
+ } elsif (-d $smtp_ssl_cert_path) {
+ $ret{SSL_verify_mode} = SSL_VERIFY_PEER();
+ $ret{SSL_ca_path} = $smtp_ssl_cert_path;
+ } elsif (-f $smtp_ssl_cert_path) {
+ $ret{SSL_verify_mode} = SSL_VERIFY_PEER();
+ $ret{SSL_ca_file} = $smtp_ssl_cert_path;
+ } else {
+ die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
+ }
}
- 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 {
- die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
+ if (defined $smtp_ssl_client_cert) {
+ $ret{SSL_cert_file} = $smtp_ssl_client_cert;
+ }
+ if (defined $smtp_ssl_client_key) {
+ if (!defined $smtp_ssl_client_cert) {
+ # Accept the client key only when a certificate is given.
+ # We die here because this case is a user error.
+ die sprintf(__("Only client key \"%s\" specified"),
+ $smtp_ssl_client_key);
+ }
+ $ret{SSL_key_file} = $smtp_ssl_client_key;
}
+
+ return %ret;
}
sub file_name_is_absolute {