diff options
| author | Junio C Hamano <gitster@pobox.com> | 2026-03-12 10:56:04 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-12 10:56:05 -0700 |
| commit | 898549142353fa105ad2c466a52e497620d12bb3 (patch) | |
| tree | f0bf8f9cc777e0bb831365cf44a36a1661ed35c1 | |
| parent | fdfa7f64d641fe21661087d7bdb0f58d66e3d2de (diff) | |
| parent | a8215a2051411bbaa1ea1464026cb473fbf8f83c (diff) | |
| download | git-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.adoc | 16 | ||||
| -rw-r--r-- | Documentation/git-send-email.adoc | 19 | ||||
| -rwxr-xr-x | git-send-email.perl | 47 |
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 { |
