public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/1] send-email: add client certificate options
@ 2026-02-20  8:17 David Timber
  2026-02-20  8:17 ` [PATCH v1 1/1] send-mail: " David Timber
  2026-02-20 16:19 ` [PATCH v1 0/1] " Junio C Hamano
  0 siblings, 2 replies; 10+ messages in thread
From: David Timber @ 2026-02-20  8:17 UTC (permalink / raw)
  To: git; +Cc: David Timber

Additional doc touch up on configurations. No code change :)

David Timber (1):
  send-mail: add client certificate options

 Documentation/config/sendemail.adoc |  6 ++++
 Documentation/git-send-email.adoc   | 17 ++++++++++
 git-send-email.perl                 | 48 ++++++++++++++++++++++-------
 3 files changed, 60 insertions(+), 11 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v1 1/1] send-mail: add client certificate options
  2026-02-20  8:17 [PATCH v1 0/1] send-email: add client certificate options David Timber
@ 2026-02-20  8:17 ` David Timber
  2026-02-20 16:35   ` Junio C Hamano
  2026-02-20 16:19 ` [PATCH v1 0/1] " Junio C Hamano
  1 sibling, 1 reply; 10+ messages in thread
From: David Timber @ 2026-02-20  8:17 UTC (permalink / raw)
  To: git; +Cc: David Timber

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>
---
 Documentation/config/sendemail.adoc |  6 ++++
 Documentation/git-send-email.adoc   | 17 ++++++++++
 git-send-email.perl                 | 48 ++++++++++++++++++++++-------
 3 files changed, 60 insertions(+), 11 deletions(-)

diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc
index 90164c734d..3d9925c1e0 100644
--- a/Documentation/config/sendemail.adoc
+++ b/Documentation/config/sendemail.adoc
@@ -12,6 +12,12 @@ 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 a client certificate file to present to the SMTP server.
+
+sendemail.smtpSSLClientKey::
+	Path to the client private key file.
+
 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 ebe8853e9f..51177508c1 100644
--- a/Documentation/git-send-email.adoc
+++ b/Documentation/git-send-email.adoc
@@ -290,6 +290,23 @@ 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 a client certificate file to present to the SMTP server. This option
+	can be used when the server verifies the certificate from the client. The
+	format could be in either PKCS12 or PEM. In the latter case, the private key
+	can be specified using `--smtp-ssl-client-key` option. More more
+	detail, see
+	https://metacpan.org/pod/IO::Socket::SSL#SSL_cert_file-|-SSL_cert-|-SSL_key_file-|-SSL_key
+	Defaults to the value of the `sendemail.smtpSSLClientCert` configuration
+	variable, if set.
+
+--smtp-ssl-client-key <path>::
+	Optional path to the client private key file. If this is not given and a
+	PKCS12 certificate file is used, the private key from the PKCS12 certificate
+	will be used(see `--smtp-ssl-client-cert`). 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 cd4b316ddc..49601a91d8 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -66,6 +66,9 @@ sub usage {
     --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 client certificate file to present to SMTP server
+    --smtp-ssl-client-key   <str>  * Path to the private key file for the client certificate
+                                     (optional if a PKCS12 client certificate is used)
     --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 +282,7 @@ sub do_edit {
 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 +354,8 @@ sub do_edit {
 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 +537,8 @@ sub config_regexp {
 		    "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,
@@ -1520,6 +1528,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/);
@@ -1531,20 +1541,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) {
+		# The cert could be in PKCS12 format, which can store both cert and key
+		$ret{SSL_cert_file} = $smtp_ssl_client_cert;
+		$ret{SSL_use_cert} = 1;
 	}
+	if (defined $smtp_ssl_client_key) {
+		if (!defined $smtp_ssl_client_cert) {
+			# doesn't make sense to use a client key only
+			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 {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 0/1] send-email: add client certificate options
  2026-02-20  8:17 [PATCH v1 0/1] send-email: add client certificate options David Timber
  2026-02-20  8:17 ` [PATCH v1 1/1] send-mail: " David Timber
@ 2026-02-20 16:19 ` Junio C Hamano
  1 sibling, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2026-02-20 16:19 UTC (permalink / raw)
  To: David Timber; +Cc: git

David Timber <dxdt@dev.snart.me> writes:

> Additional doc touch up on configurations. No code change :)

Just to unconfuse me, this mention of "No code change" is relative to
https://lore.kernel.org/git/20260220075304.536514-1-dxdt@dev.snart.me/?

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] send-mail: add client certificate options
  2026-02-20  8:17 ` [PATCH v1 1/1] send-mail: " David Timber
@ 2026-02-20 16:35   ` Junio C Hamano
  2026-02-21  9:16     ` David Timber
  0 siblings, 1 reply; 10+ messages in thread
From: Junio C Hamano @ 2026-02-20 16:35 UTC (permalink / raw)
  To: David Timber; +Cc: git

David Timber <dxdt@dev.snart.me> writes:

> +sendemail.smtpSSLClientCert::
> +	Path to a client certificate file to present to the SMTP server.
> +
> +sendemail.smtpSSLClientKey::
> +	Path to the client private key file.

Do we want to add "that corresponds to the smtpSSLClientCert" at the
end, perhaps?

> diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc
> index ebe8853e9f..51177508c1 100644
> --- a/Documentation/git-send-email.adoc
> +++ b/Documentation/git-send-email.adoc
> @@ -290,6 +290,23 @@ 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 a client certificate file to present to the SMTP server. This option
> +	can be used when the server verifies the certificate from the client. The

Shouldn't there be a word "require" somewhere in the above to
clarify why a user may want to use this option?  A server may
optionally verify a certificate only when it is given one, but if it
lets us do what we want without such verification, we do not have
much incentive to give them a certificate.

> +	format could be in either PKCS12 or PEM. In the latter case, the private key
> +	can be specified using `--smtp-ssl-client-key` option. More more

Is that "can be specified" or "should be specified"?
"More more" -> "For more".

> +	detail, see
> +	https://metacpan.org/pod/IO::Socket::SSL#SSL_cert_file-|-SSL_cert-|-SSL_key_file-|-SSL_key
> +	Defaults to the value of the `sendemail.smtpSSLClientCert` configuration
> +	variable, if set.
> +
> +--smtp-ssl-client-key <path>::
> +	Optional path to the client private key file. If this is not given and a
> +	PKCS12 certificate file is used, the private key from the PKCS12 certificate
> +	will be used(see `--smtp-ssl-client-cert`). Defaults to the value of the
> +	`sendemail.smtpSSLClientKey` configuration variable, if set.
> +

"will be used(see" -> "will be used (see".

This makes me wonder what the use case is for giving separate key
file with a certificate file with its own private key in it.  The
documentation above clearly describes what happens (i.e., the
separate key file makes the key embedded in the certificate file
ignored), but I cannot quite think of a reason why anybody would
want to do so.  The key in the separate file is still something that
corresponds to the public part in the certificate, no?  The certificate
can say "The subject of the certificate may use a private key that
corresponds to any of these three public keys", and the certificate
file may only have one or two but not all of these three public
keys, or something?

> +	if (defined $smtp_ssl_client_cert) {
> +		# The cert could be in PKCS12 format, which can store both cert and key

The comment confused me initially.  Yes, the cert could be PKCS12
with key.  But the mention of the fact supports what design
decision?  Not requiring $smtp_ssl_client_key here (unlike the next
if block that requires cert when key is used)?  If so, perhaps we
would want to spell that out?

		# We do not check and die when client_key is not
                # given, as a separate key file is unneeded for
                # PKCS12 certs.

or something?

> +		$ret{SSL_cert_file} = $smtp_ssl_client_cert;
> +		$ret{SSL_use_cert} = 1;
>  	}
> +	if (defined $smtp_ssl_client_key) {
> +		if (!defined $smtp_ssl_client_cert) {
> +			# doesn't make sense to use a client key only
> +			die sprintf(__("Only client key \"%s\" specified"), $smtp_ssl_client_key);

Can you wrap this overly long line?

			die sprintf(__("Only client key \"%s\" specified"),
					$smtp_ssl_client_key);

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] send-mail: add client certificate options
  2026-02-20 16:35   ` Junio C Hamano
@ 2026-02-21  9:16     ` David Timber
  2026-02-26 16:41       ` Junio C Hamano
  0 siblings, 1 reply; 10+ messages in thread
From: David Timber @ 2026-02-21  9:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 2/21/26 01:35, Junio C Hamano wrote:
> This makes me wonder what the use case is for giving separate key
> file with a certificate file with its own private key in it.  The
> documentation above clearly describes what happens (i.e., the
> separate key file makes the key embedded in the certificate file
> ignored), but I cannot quite think of a reason why anybody would
> want to do so. 
I know. The design of the Perl SSL interface is not top notch.

https://metacpan.org/dist/IO-Socket-SSL/view/lib/IO/Socket/SSL.pod
>
> For each certificate a key is need, which can either be given as a
> file with SSL_key_file or as an internal representation of an
> EVP_PKEY* object with SSL_key (like you get from Net::SSLeay or
> IO::Socket::SSL::Utils::PEM_xxx2key). If a key was already given
> within the PKCS#12 file specified by SSL_cert_file it will ignore any
> SSL_key or SSL_key_file. If no SSL_key or SSL_key_file was given it
> will try to use the PEM file given with SSL_cert_file again, maybe it
> contains the key too.
>
To summarise:

  * PKCS12: the key in the cert always takes the precedence
  * PEM: if the key file is not given, it will "try" to read one from
    the cert PEM file

I don't know why anyone would want to put the cert and the key in the
same file, not even openssl impose that, but somehow, somewhere, there
are people who do and Perl had to cater for the kind as it seems.

> The key in the separate file is still something that
> corresponds to the public part in the certificate, no?  The certificate
> can say "The subject of the certificate may use a private key that
> corresponds to any of these three public keys", and the certificate
> file may only have one or two but not all of these three public
> keys, or something?
I think this is why they made the logic that way (at least for PKCS12)
to prevent the exact madness you were describing. Still, I'd agree that
the asymmetry is horrendous.

I'm just trying to expose what's possible with the Perl SSL interface to
the user as much as possible. Paranoid people(like me who would want to
set up mtual vertification to deter bot attacks) would want both PEM and
PKCS12 because major implementations including Thunderbird and K-9 only
accept PKCS#12(imposed by the application and imposed by the operating
system - Android, respectively) while the openssl x509 stack is more
suited for PEM(separate cert and key).

It's a niche, I know. But something tells me that you'd want to push
this feature forward. Thank you for the rest of the comments. Will come
back with the revised patch that I hope may unconfuse you. Good to know
the project is in good hands.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] send-mail: add client certificate options
  2026-02-21  9:16     ` David Timber
@ 2026-02-26 16:41       ` Junio C Hamano
  2026-03-02  3:16         ` [PATCH v2 0/1] send-email: " David Timber
  0 siblings, 1 reply; 10+ messages in thread
From: Junio C Hamano @ 2026-02-26 16:41 UTC (permalink / raw)
  To: David Timber; +Cc: git

David Timber <dxdt@dev.snart.me> writes:

> I'm just trying to expose what's possible with the Perl SSL interface to
> the user as much as possible. Paranoid people(like me who would want to
> set up mtual vertification to deter bot attacks) would want both PEM and
> PKCS12 because major implementations including Thunderbird and K-9 only
> accept PKCS#12(imposed by the application and imposed by the operating
> system - Android, respectively) while the openssl x509 stack is more
> suited for PEM(separate cert and key).
>
> It's a niche, I know. But something tells me that you'd want to push
> this feature forward. Thank you for the rest of the comments. Will come
> back with the revised patch that I hope may unconfuse you. Good to know
> the project is in good hands.

OK, please incorporate what you explained here in the commit log
message and/or in-code comment, in order to help future readers of
"git log -p".  I'd prefer to see it done before the topic goes out
of my short-term memory ;-)

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 0/1] send-email: add client certificate options
  2026-02-26 16:41       ` Junio C Hamano
@ 2026-03-02  3:16         ` David Timber
  2026-03-02  3:16           ` [PATCH v2 1/1] " David Timber
  0 siblings, 1 reply; 10+ messages in thread
From: David Timber @ 2026-03-02  3:16 UTC (permalink / raw)
  To: git; +Cc: David Timber

I'm sorry that I missed last week's submission deadline.

On 2/21/26 01:35, Junio C Hamano wrote:
> Shouldn't there be a word "require" somewhere in the above to
> clarify why a user may want to use this option?  A server may
> optionally verify a certificate only when it is given one, but if it
> lets us do what we want without such verification, we do not have
> much incentive to give them a certificate.

RFC 8446 section 4.3.2:
> The client MUST send a Certificate message if and only if the server
> has requested client authentication via a CertificateRequest message
> (Section 4.3.2).

In other words, the client won't send its cert to the server unless
requested by the server. So, the client presenting its cert to the
server in the client hello from the get-go is in violation of this
requirement. I reflected that in the reroll.

Also, removed the `$ret{SSL_use_cert} = 1;` line in the code to be in
line with the requirement. That line was confusing and unnecessary in
the first place. Whether to use a client cert or not should be up to
the underlying implementation to decide.

Removed the whole PKCS#12 vs PEM debacle in the change as I reckon it's
a behaviour that could change overnight without a warning. Feels kind
of defensive, but a reasonable change all things considered. Users
affected by such library behaviour change can always refer to the
manual.

David Timber (1):
  send-email: add client certificate options

 Documentation/config/sendemail.adoc | 16 ++++++++++
 Documentation/git-send-email.adoc   | 19 ++++++++++++
 git-send-email.perl                 | 47 ++++++++++++++++++++++-------
 3 files changed, 71 insertions(+), 11 deletions(-)

-- 
2.53.0.1.ga224b40d3f.dirty


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/1] send-email: add client certificate options
  2026-03-02  3:16         ` [PATCH v2 0/1] send-email: " David Timber
@ 2026-03-02  3:16           ` David Timber
  2026-03-02 16:43             ` Junio C Hamano
  0 siblings, 1 reply; 10+ messages in thread
From: David Timber @ 2026-03-02  3:16 UTC (permalink / raw)
  To: git; +Cc: David Timber

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.

The problem of which private key for the certificate is chosen arises
when there are private keys in both the certificate and private key
file. According to the documentation of IO::Socket::SSL(link supplied),
the behaviour(the private key chosen) depends on the format of the
certificate. In a nutshell,

	- PKCS12: the key in the cert always takes the precedence
	- PEM: if the key file is not given, it will "try" to read one
	  from the cert PEM file

Many users may find this discrepancy unintuitive.

In terms of client certificate, git-send-email is implemented in a way
that what's possible with perl's SSL library is exposed to the user as
much as possible. In this instance, the user may choose to use a PEM
file that contains both certificate and private key should be
at their discretion despite the implications.

Link: https://metacpan.org/pod/IO::Socket::SSL#SSL_cert_file-%7C-SSL_cert-%7C-SSL_key_file-%7C-SSL_key
Link: https://lore.kernel.org/all/319bf98c-52df-4bf9-b157-e4bc2bf087d6@dev.snart.me/

Signed-off-by: David Timber <dxdt@dev.snart.me>
---
 Documentation/config/sendemail.adoc | 16 ++++++++++
 Documentation/git-send-email.adoc   | 19 ++++++++++++
 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 ebe8853e9f..ed9a0d3053 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 cd4b316ddc..324fa0056c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -66,6 +66,8 @@ sub usage {
     --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 @@ sub do_edit {
 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 @@ sub do_edit {
 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 @@ sub config_regexp {
 		    "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,
@@ -1520,6 +1527,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/);
@@ -1531,20 +1540,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 {
-- 
2.53.0.1.ga224b40d3f.dirty


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/1] send-email: add client certificate options
  2026-03-02  3:16           ` [PATCH v2 1/1] " David Timber
@ 2026-03-02 16:43             ` Junio C Hamano
  2026-03-04 14:39               ` David Timber
  0 siblings, 1 reply; 10+ messages in thread
From: Junio C Hamano @ 2026-03-02 16:43 UTC (permalink / raw)
  To: David Timber; +Cc: git

David Timber <dxdt@dev.snart.me> writes:

> 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.
>
> The problem of which private key for the certificate is chosen arises
> when there are private keys in both the certificate and private key
> file. According to the documentation of IO::Socket::SSL(link supplied),
> the behaviour(the private key chosen) depends on the format of the
> certificate. In a nutshell,
>
> 	- PKCS12: the key in the cert always takes the precedence
> 	- PEM: if the key file is not given, it will "try" to read one
> 	  from the cert PEM file
>
> Many users may find this discrepancy unintuitive.
>
> In terms of client certificate, git-send-email is implemented in a way
> that what's possible with perl's SSL library is exposed to the user as
> much as possible. In this instance, the user may choose to use a PEM
> file that contains both certificate and private key should be
> at their discretion despite the implications.
>
> Link: https://metacpan.org/pod/IO::Socket::SSL#SSL_cert_file-%7C-SSL_cert-%7C-SSL_key_file-%7C-SSL_key
> Link: https://lore.kernel.org/all/319bf98c-52df-4bf9-b157-e4bc2bf087d6@dev.snart.me/
>
> Signed-off-by: David Timber <dxdt@dev.snart.me>
> ---
>  Documentation/config/sendemail.adoc | 16 ++++++++++
>  Documentation/git-send-email.adoc   | 19 ++++++++++++
>  git-send-email.perl                 | 47 ++++++++++++++++++++++-------
>  3 files changed, 71 insertions(+), 11 deletions(-)

It's a lot of text but quite informative.  Will replace.

Shall we declare victory and mark the topic for 'next' now?

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/1] send-email: add client certificate options
  2026-03-02 16:43             ` Junio C Hamano
@ 2026-03-04 14:39               ` David Timber
  0 siblings, 0 replies; 10+ messages in thread
From: David Timber @ 2026-03-04 14:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 3/3/26 01:43, Junio C Hamano wrote:
> Shall we declare victory and mark the topic for 'next' now?
By all means! Keep up the good work!

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-03-04 14:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20  8:17 [PATCH v1 0/1] send-email: add client certificate options David Timber
2026-02-20  8:17 ` [PATCH v1 1/1] send-mail: " David Timber
2026-02-20 16:35   ` Junio C Hamano
2026-02-21  9:16     ` David Timber
2026-02-26 16:41       ` Junio C Hamano
2026-03-02  3:16         ` [PATCH v2 0/1] send-email: " David Timber
2026-03-02  3:16           ` [PATCH v2 1/1] " David Timber
2026-03-02 16:43             ` Junio C Hamano
2026-03-04 14:39               ` David Timber
2026-02-20 16:19 ` [PATCH v1 0/1] " Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox