Subject: Re: bug#76278: 29.4; ERC 5.5.0.29.1: ERC Manual does not mention usage of .pem client certificates

From: "J.P." <[email-masked]>
Date: Fri, 14 Feb 2025 19:47:08 -0800

Hi Archie,

Archie Halliwell <[email-masked]> writes:

> On 14/2/25 19:34, Eli Zaretskii wrote:
>>> Date: Fri, 14 Feb 2025 14:43:32 +1100
>>> From: Archie Halliwell <[email-masked]>
>>>
>>> The ERC Manual does not explain how to use .pem client certificates,
>>> only how to use the combination of a .crt certificate and .key private
>>> key. This is confusing as Libera.Chat's CertFP instructions only mention
>>> the use of a .pem file, instructing users on how to create an
>>> appropriate one.
>>>
>>> The manual should really mention that a .pem file can be used as both
>>> files in the client-certificate list.
>> Does ERC use the .pem file directly, or does it use it indirectly,
>> though some GnuTLS interface?  If the latter, then the source might
>> not be from a .pem file, but instead from some equivalent OS service
>> (this happens on MS-Windows, for example).  So the manual should not
>> cause users of such systems go look for a .pem file that might not
>> even exist, or be irrelevant.
>>
>> Apologies if the above makes no sense: I don't use ERC and know very
>> little about it.
>>
>> Thanks.
> I believe that ERC uses GnuTLS, however the filenames are either specified in
> the client-certificate argument to ,,erc-tls,, or found in .authinfo.gpg. The
> manual gives examples using .key and .crt files, but not using .pem files.
> There is mention of using other services to provide certificates using
> auth-service, however auth-service seems to have disappeared and all links to
> it are broken. Libera.Chat's instructions mention the creation of .pem files
> on Windows as well, so I expect that specifing a .pem file through the
> client-certificate keyword argument is the "correct" way on all platforms.

ERC supposedly relies on a generalized underlying transport to provide a
network process for exchanging IRC protocol messages with a server. In
practice, it's only equipped to handle TCP streams and defers to an
`open-network-stream'-compatible "opener" to create the necessary goods.

The opener for TLS encrypted streams is `erc-open-tls-stream', a thin
wrapper around `open-network-stream'. In this case, ERC passes the
:client-certificate from `erc-tls' directly to `open-network-stream',
which ultimately relies on `network-stream-certificate' to transform it
into something suitable for the :keylist parameter of `gnutls-boot'.
FWIW, the doc string of `gnutls-boot' does mention that

  :keylist is an alist of PEM-encoded key files and PEM-encoded
  certificates for ‘gnutls-x509pki’

which comports with its calling gnutls_certificate_set_x509_key_file2
and friends with a hard-coded GNUTLS_X509_FMT_PEM, although there's a
friendly note saying

  /* TODO: GNUTLS_X509_FMT_DER is also an option.  */

In any case, this info is likely one too many clicks removed from ERC's
docs. So, I think it makes sense for us to mention the format must be
PEM and that the key and the cert can be the same concatenated file.

In terms of file-name extensions, it's true that the examples on
Libera's site (and OFTC's) all appear to be .pem. OpenSSL's man pages
use .pem when contrasting it with .der, although the format is typically
declared explicitly with options like -outform. The .key and .crt
extensions in ERC's manual may originate from the docs of other IRC
clients or from the world of domain-name validation. Either way, I agree
we should probably change them all to .pem.

As for the broken auth-source hyperlinks, I'm not sure they're fixable
on ERC's side (ditto for all other non-ERC links). FWIW, they should
only be broken on https://elpa.gnu.org/packages/doc/erc.html. The ones
on https://www.gnu.org/software/emacs/manual/html_mono/erc.html and in
the Info manual (info "(erc) client-certificate") should work fine.

Anyway, the attached patch includes the mentioned changes, which are
mostly mechanical in nature. Please give feedback if you can.

Thanks,
J.P.

>From b03220e92e1b497f3db119d69264c056c9e64835 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Fri, 14 Feb 2025 18:57:41 -0800
Subject: [PATCH] [5.6.1] Use .pem extension for client certs in ERC docs

* doc/misc/erc.texi (Connecting): Change file-name extensions to .pem in
all examples, and explain that the key and the cert can be combined into
one file.
* lisp/erc/erc.el (erc-tls): Use .pem extension for certs.  (Bug#76278)
---
 doc/misc/erc.texi | 18 +++++++++++-------
 lisp/erc/erc.el   |  4 ++--
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 1c0afa3b300..dac90e2ad7f 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -866,15 +866,15 @@ Connecting
 @example
 (erc-tls :server "irc.libera.chat" :port 6697
          :client-certificate
-         '("/home/bandali/my-cert.key"
-           "/home/bandali/my-cert.crt"))
+         (list (expand-file-name "~/my-key.pem")
+               (expand-file-name "~/my-cert.pem")))
 @end example
 
 @example
 (erc-tls :server "irc.libera.chat" :port 6697
          :client-certificate
-         `(,(expand-file-name "~/cert-libera.key")
-           ,(expand-file-name "~/cert-libera.crt")))
+         '("/home/bandali/libera.pem"
+           "/home/bandali/libera.pem")) ; same file
 @end example
 
 @example
@@ -882,12 +882,16 @@ Connecting
          :client-certificate t)
 @end example
 
+Make sure to use absolute file names for the key and the cert.  The
+files themselves must be in the PEM-encoded text format and can be
+concatenated into a single file.
+
 In the case of @code{:client-certificate t}, you will need to add a
 line like the following to your authinfo file
 (for example, @file{~/.authinfo.gpg}):
 
 @example
-machine irc.libera.chat key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt
+machine irc.libera.chat key /home/bandali/my-key.pem cert /home/bandali/my-cert.pem
 @end example
 
 @xref{Help for users,,,auth, Emacs auth-source Library}, for more on the
@@ -1244,7 +1248,7 @@ SASL
 
 (erc-tls :server "irc.libera.chat" :port 6697 :nick "aph"
          :client-certificate
-         '("/home/aph/my.key" "/home/aph/my.crt"))
+         '("/home/aph/my-key.pem" "/home/aph/my-cert.pem"))
 @end lisp
 
 You decide to switch things up and try out the @samp{EXTERNAL}
@@ -1258,7 +1262,7 @@ SASL
 @example
 # ~/.authinfo.gpg
 
-machine irc.libera.chat key /home/aph/my.key cert /home/aph/my.crt
+machine irc.libera.chat key /home/aph/my-key.pem cert /home/aph/my-cert.pem
 machine Example.Net login alyssa password sEcReT
 machine Example.Net login aph-bot password sesame
 @end example
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 0d72b46360e..887df0c9e4a 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -2921,8 +2921,8 @@ erc-tls
 
     (erc-tls :server \"irc.libera.chat\" :port 6697
              :client-certificate
-             \\='(\"/home/bandali/my-cert.key\"
-               \"/home/bandali/my-cert.crt\"))
+             \\='(\"/home/bandali/my-key.pem\"
+               \"/home/bandali/my-cert.pem\"))
 
 See the alternative entry-point command `erc' as well as Info
 node `(erc) Connecting' for a fuller description of the various
-- 
2.48.1