* bug#47788: Add support for TLS client certificates to 'erc-tls' @ 2021-04-15 4:16 Amin Bandali 2021-04-15 12:44 ` J.P. 2021-04-16 7:38 ` Robert Pluim 0 siblings, 2 replies; 8+ messages in thread From: Amin Bandali @ 2021-04-15 4:16 UTC (permalink / raw) To: 47788; +Cc: emacs-erc, jp [-- Attachment #1: Type: text/plain, Size: 1719 bytes --] Tags: patch After a few recent changes in my IRC/ERC setup, I felt ERC's lack of support for connecting to IRC networks using TLS client certificates as an alternative to traditional password-based authentication. So I spent some time a few nights ago and wired things up in ERC to allow passing a client certificate to `open-network-stream'. Fellow ERC user 'neverwas' was kind enough to take my patch for a test drive and provide feedback. I have done some work on addressing their feedback, but for now I'm attaching my very first draft here which I'd sent to neverwas, and will attach the next version of my patch (along with a proper commit message, NEWS entry, etc) shortly after neverwas's reply with their feedback. For anyone wanting to take this for a spin, the changes here should be fully backward-compatible, and should not break anything in existing ERC configurations. To specify a client certificate, call `erc-tls' with the new keywords :client-key and :client-crt with the file name of the certificate key and certificate file itself respectively: (erc-tls :server "chat.freenode.net" :port 6697 :client-key "~/my-freenode-cert.key" :client-crt "~/my-freenode-cert.crt") In GNU Emacs 28.0.50 (build 43, x86_64-pc-linux-gnu, X toolkit, cairo version 1.15.10, Xaw3d scroll bars) of 2021-04-14 built on trisquel Repository revision: 4ddad8f1db1f888f3365ac1330989dfbee605dd5 Repository branch: master Windowing system distributor 'The X.Org Foundation', version 11.0.11906000 System Description: Trisquel GNU/Linux Etiona (9.0) Configured using: 'configure --without-gconf --without-gsettings --without-gpm --with-x-toolkit=lucid --with-xaw3d --with-mailutils' [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-support-for-TLS-client-certificates-to-erc-tls.patch --] [-- Type: text/patch, Size: 8023 bytes --] From cec5c02a8a82a904a68d705ad54c3ccdcd0774cc Mon Sep 17 00:00:00 2001 From: Amin Bandali <bandali@gnu.org> Date: Wed, 14 Apr 2021 23:32:54 -0400 Subject: [PATCH] Add support for TLS client certificates to 'erc-tls' --- lisp/erc/erc-backend.el | 32 +++++++++++++++------- lisp/erc/erc.el | 59 ++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index b1f97aea06..056cc5c68f 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -138,6 +138,16 @@ erc-session-connector (defvar-local erc-session-port nil "The port used to connect to.") +(defvar-local erc-session-cert-key nil + "File name of the private key of the client certificate used to connect over TLS. +The corresponding client certificate's file name must be set in +`erc-session-cert-crt'.") + +(defvar-local erc-session-cert-crt nil + "File name of the client certificate used to connect over TLS. +The file name of the corresponding client certificate's private +key must be set in `erc-session-cert-key'.") + (defvar-local erc-server-announced-name nil "The name the server announced to use.") @@ -505,18 +515,22 @@ erc-server-process-alive (memq (process-status erc-server-process) '(run open))))) ;;;; Connecting to a server -(defun erc-open-network-stream (name buffer host service) - "As `open-network-stream', but does non-blocking IO" - (make-network-process :name name :buffer buffer - :host host :service service :nowait t)) +(defun erc-open-network-stream (name buffer host service &rest parameters) + "Like `open-network-stream', but does non-blocking IO." + (let ((p (plist-put parameters :nowait t))) + (open-network-stream name buffer host service p))) -(defun erc-server-connect (server port buffer) +(defun erc-server-connect (server port buffer &optional client-key client-crt) "Perform the connection and login using the specified SERVER and PORT. -We will store server variables in the buffer given by BUFFER." - (let ((msg (erc-format-message 'connect ?S server ?p port)) process) +We will store server variables in the buffer given by BUFFER. +CLIENT-KEY and CLIENT-CRT may optionally be used to specify a TLS +client certificate." + (let ((msg (erc-format-message 'connect ?S server ?p port)) process + (args `(,(format "erc-%s-%s" server port) nil ,server ,port))) + (when (and client-key client-crt) + (setq args `(,@args :client-certificate (,client-key ,client-crt)))) (message "%s" msg) - (setq process (funcall erc-server-connect-function - (format "erc-%s-%s" server port) nil server port)) + (setq process (apply erc-server-connect-function args)) (unless (processp process) (error "Connection attempt failed")) ;; Misc server variables diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index e20aa8057d..45594d7b87 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1967,7 +1967,8 @@ erc-setup-buffer (switch-to-buffer buffer))))) (defun erc-open (&optional server port nick full-name - connect passwd tgt-list channel process) + connect passwd tgt-list channel process + client-key client-crt) "Connect to SERVER on PORT as NICK with FULL-NAME. If CONNECT is non-nil, connect to the server. Otherwise assume @@ -1977,6 +1978,10 @@ erc-open Use PASSWD as user password on the server. If TGT-LIST is non-nil, use it to initialize `erc-default-recipients'. +CLIENT-KEY and CLIENT-CRT can be file names for the private key +and certificate parts of a client certificate to use when +connecting over TLS. + Returns the buffer for the given server or channel." (let ((server-announced-name (when (and (boundp 'erc-session-server) (string= server erc-session-server)) @@ -2073,13 +2078,18 @@ erc-open (erc-display-prompt) (goto-char (point-max))) - (erc-determine-parameters server port nick full-name) + (erc-determine-parameters server port nick full-name + client-key client-crt) ;; Saving log file on exit (run-hook-with-args 'erc-connect-pre-hook buffer) (when connect - (erc-server-connect erc-session-server erc-session-port buffer)) + (erc-server-connect erc-session-server + erc-session-port + buffer + erc-session-cert-key + erc-session-cert-crt)) (erc-update-mode-line) ;; Now display the buffer in a window as per user wishes. @@ -2192,7 +2202,9 @@ erc (port (erc-compute-port)) (nick (erc-compute-nick)) password - (full-name (erc-compute-full-name))) + (full-name (erc-compute-full-name)) + client-key + client-crt) "ERC is a powerful, modular, and extensible IRC client. This function is the main entry point for ERC. @@ -2203,17 +2215,25 @@ erc (port (erc-compute-port)) (nick (erc-compute-nick)) password - (full-name (erc-compute-full-name))) + (full-name (erc-compute-full-name)) + client-key + client-crt That is, if called with (erc :server \"chat.freenode.net\" :full-name \"Harry S Truman\") -then the server and full-name will be set to those values, whereas -`erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will -be invoked for the values of the other parameters." +then the server and full-name will be set to those values, +whereas `erc-compute-port', `erc-compute-nick' and +`erc-compute-full-name' will be invoked for the values of the +other parameters. CLIENT-KEY and CLIENT-CRT, if non-nil, should +be file names for the private key and certificate parts of a +client certificate respectively to be used when connecting over +TLS." (interactive (erc-select-read-args)) - (erc-open server port nick full-name t password)) + (erc-open server port nick full-name t password + nil nil nil + client-key client-crt)) ;;;###autoload (defalias 'erc-select #'erc) @@ -2228,13 +2248,18 @@ erc-tls (let ((erc-server-connect-function 'erc-open-tls-stream)) (apply #'erc r))) -(defun erc-open-tls-stream (name buffer host port) +(defun erc-open-tls-stream (name buffer host port &rest parameters) "Open an TLS stream to an IRC server. -The process will be given the name NAME, its target buffer will be -BUFFER. HOST and PORT specify the connection target." - (open-network-stream name buffer host port - :nowait t - :type 'tls)) +The process will be given the name NAME, its target buffer will +be BUFFER. HOST and PORT specify the connection target. +PARAMETERS should be a sequence of keywords and values, per +`open-network-stream'." + (let ((p (plist-put parameters :type 'tls)) + args) + (unless (plist-get p :nowait) + (setq p (plist-put p :nowait t))) + (setq args `(,name ,buffer ,host ,port ,@p)) + (apply #'open-network-stream args))) ;;; Displaying error messages @@ -6030,7 +6055,7 @@ erc-login ;; connection properties' heuristics -(defun erc-determine-parameters (&optional server port nick name) +(defun erc-determine-parameters (&optional server port nick name key crt) "Determine the connection and authentication parameters. Sets the buffer local variables: @@ -6042,6 +6067,8 @@ erc-determine-parameters (setq erc-session-connector erc-server-connect-function erc-session-server (erc-compute-server server) erc-session-port (or port erc-default-port) + erc-session-cert-key key + erc-session-cert-crt crt erc-session-user-full-name (erc-compute-full-name name)) (erc-set-current-nick (erc-compute-nick nick))) -- 2.17.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* bug#47788: Add support for TLS client certificates to 'erc-tls' 2021-04-15 4:16 bug#47788: Add support for TLS client certificates to 'erc-tls' Amin Bandali @ 2021-04-15 12:44 ` J.P. 2021-04-18 19:23 ` Amin Bandali [not found] ` <87h7k3mm6x.fsf@gnu.org> 2021-04-16 7:38 ` Robert Pluim 1 sibling, 2 replies; 8+ messages in thread From: J.P. @ 2021-04-15 12:44 UTC (permalink / raw) To: Amin Bandali; +Cc: 47788, emacs-erc Amin Bandali <bandali@gnu.org> writes: > Fellow ERC user 'neverwas' was kind enough to take my patch for a test > drive and provide feedback. I have done some work on addressing their > feedback, but for now I'm attaching my very first draft here which I'd > sent to neverwas, and will attach the next version of my patch (along > with a proper commit message, NEWS entry, etc) shortly after neverwas's > reply with their feedback. Hey 'bandali' :-) Below is what I sent you previously. I look forward to trying out the latest changes! -------------------- Start of forwarded message -------------------- From: "J.P." <jp@neverwas.me> To: bandali@gnu.org Subject: ERC TLS client certificate Date: Sat, 10 Apr 2021 07:41:56 -0700 As always, these are just the impressions of an average dummy, so feel free to dismiss them. Since my setup is probably the most common (GNU/Linux, x86_64, 28.0.50), you likely already have it pretty well covered. A few environmental details I'll mention anyway just in case they add anything: 1. patch applied atop commit 0db2126d7176b0bd1b13d4b0d1cd958c8cf55714 Author: Dmitry Gutov <dgutov@yandex.ru> Date: Sat Apr 10 01:51:39 2021 +0300 with debugging symbols present and no optimization 2. Emacs invoked with -Q -nw and piloted manually thereafter 3. single file used for both key and cert (combined PEM format) 4. isolated network namespace sh:~$ ss -tpn Local Address:Port Peer Address:Port Process 127.0.0.1:54982 127.0.0.1:6670 users:(("emacs",pid=151118,fd=8)) 127.0.0.1:34874 127.0.0.1:6697 users:(("socat",pid=160299,fd=5)) 127.0.0.1:6670 127.0.0.1:54982 users:(("socat",pid=160299,fd=6)) [::1]:42176 [::1]:6667 [::1]:42178 [::1]:6667 [::1]:6667 [::1]:42178 users:(("oragono",pid=147008,fd=9)) ff:127.0.0.1]:6697 ff:127.0.0.1]:34874 users:(("oragono",pid=147008,fd=11)) [::1]:6667 [::1]:42176 users:(("oragono",pid=147008,fd=10)) Oragono is the server accepting TLS on 6697 and talking to the two non-Emacs clients (bots) on 6667 (non-TLS). The socat proc is listening on 6670 and forwarding to 6697; its purpose is explained below. Notes ~~~~~ The buffer-local vars you've introduced follow existing conventions in that they're basically there for recording the options during entry-point invocation to aid later in reconnecting. For example, erc-session-connector remembers the initial stream opener, etc. I've tested this persistence aspect by pulling the plug on an active session with healthy traffic (hence the socat proxy). It reconnected successfully with no hiccups, so I think that's one for the win column. You've probably gamed out the trade-offs more than I have, but seems to me that mulling over all the ways of specifying TLS connection params short of explicitly passing them around as you do is kind of moot. I couldn't think of any that (1) don't buck existing library trends and (2) make things any easier to maintain/debug. So might as well stick to the status quo, I guess. In terms of preserving extensibility and leaving existing escape hatches intact, it's hard to be sure without test cases or protracted trials, but if I had to guess, it looks like you're pretty safe in that department as well. For example, I can't see how folks with their own erc-server-connect-function would experience any churn from these changes. I see you've updated the doc string for the plain `erc' entry point to include the two new params. Maybe it's also worth mentioning that specifying them won't magically enable TLS. Users will still need to use `erc-tls' (right?). Beyond that, users may appreciate a mention of the new additions in the info manual and maybe the wiki as well (instead of just NEWS). Lastly, in the function erc-open-tls-stream, do you maybe want plist-member instead of plist-get? (let ((p (plist-put parameters :type 'tls)) args) (unless (plist-get p :nowait) ;; ^~~~~~~~~~~ (setq p (plist-put p :nowait t))) (setq args `(,name ,buffer ,host ,port ,@p)) As is, I think it basically enforces non-nil (unless that's the idea). In general, I think these changes lower the barrier to entry by getting folks connected faster OOTB, which can only help with adoption and mind/market share. J.P. -------------------- End of forwarded message -------------------- ^ permalink raw reply [flat|nested] 8+ messages in thread
* bug#47788: Add support for TLS client certificates to 'erc-tls' 2021-04-15 12:44 ` J.P. @ 2021-04-18 19:23 ` Amin Bandali [not found] ` <87h7k3mm6x.fsf@gnu.org> 1 sibling, 0 replies; 8+ messages in thread From: Amin Bandali @ 2021-04-18 19:23 UTC (permalink / raw) To: 47788, emacs-erc; +Cc: Robert Pluim, J.P. [-- Attachment #1: Type: text/plain, Size: 5219 bytes --] J.P. writes: [...] > > Hey 'bandali' :-) Hey :-) > Below is what I sent you previously. I look forward to trying out the > latest changes! Thanks again for your feedback! I'll address each point inline, and attach an updated version at the end of the message. > From: "J.P." <jp@neverwas.me> > Subject: ERC TLS client certificate > Date: Sat, 10 Apr 2021 10:41:56 -0400 (5 days, 9 hours, 28 minutes ago) > To: bandali@gnu.org > > As always, these are just the impressions of an average dummy, so feel > free to dismiss them. Please be kinder to yourself :-). All feedback and impressions are welcome and very much appreciated. [...] > > Notes > ~~~~~ > > The buffer-local vars you've introduced follow existing conventions in > that they're basically there for recording the options during > entry-point invocation to aid later in reconnecting. For example, > erc-session-connector remembers the initial stream opener, etc. Indeed. > I've tested this persistence aspect by pulling the plug on an active > session with healthy traffic (hence the socat proxy). It reconnected > successfully with no hiccups, so I think that's one for the win column. Oh great, thanks for testing that scenario specifically! > You've probably gamed out the trade-offs more than I have, but seems to > me that mulling over all the ways of specifying TLS connection params > short of explicitly passing them around as you do is kind of moot. I > couldn't think of any that (1) don't buck existing library trends and > (2) make things any easier to maintain/debug. So might as well stick to > the status quo, I guess. Right, I gave it some thought and I thought this would be the most straightforward and "idiomatic" (w.r.t. the rest of the ERC codebase) way of doing it. That said, I'd welcome ideas for simplifying and/or improving the implementation as part of this patch, or the status quo in general in separate patches. > In terms of preserving extensibility and leaving existing escape hatches > intact, it's hard to be sure without test cases or protracted trials, > but if I had to guess, it looks like you're pretty safe in that > department as well. For example, I can't see how folks with their own > erc-server-connect-function would experience any churn from these > changes. Right, yeah I made sure to not change the existing parameters of any of the functions and/or their order and only add new parameters at the end, so as to not break any existing configurations. But indeed, having a test suite would've been nice to help give more assurance about that. > I see you've updated the doc string for the plain `erc' entry point to > include the two new params. Maybe it's also worth mentioning that > specifying them won't magically enable TLS. Users will still need to use > `erc-tls' (right?). Indeed, very much so! Thanks for noticing that; amended in v2. > Beyond that, users may appreciate a mention of the new additions in the > info manual and maybe the wiki as well (instead of just NEWS). Certainly; done in v2. > Lastly, in the function erc-open-tls-stream, do you maybe want > plist-member instead of plist-get? > > (let ((p (plist-put parameters :type 'tls)) > args) > (unless (plist-get p :nowait) > ;; ^~~~~~~~~~~ > (setq p (plist-put p :nowait t))) > (setq args `(,name ,buffer ,host ,port ,@p)) > > As is, I think it basically enforces non-nil (unless that's the idea). Indeed :-). My intention was to enforce non-nil there, to always make the connection in an asynchronous/non-blocking way, similar to its dual, `erc-open-network-stream'. I think passing :nowait nil could be useful for debugging, but off top of my head I can't think of any other reason one would want to do it. And for debugging, one could easily redefine the function completely. On the other hand, I don't see any harm in allowing/respecting :nowait nil if it's explicitly set. So I've changed the above plist-get to plist-member in v2. > In general, I think these changes lower the barrier to entry by getting > folks connected faster OOTB, which can only help with adoption and > mind/market share. Great! It certainly scratches an itch for me personally and greatly simplifies the use-case of authenticating with client certificates. Hopefully others will find this useful as well. :-) * * * Robert Pluim writes: [...] > It would be nice if you could arrange for an option to pass > ':client-certificate t' to 'open-network-stream' so it would leverage > 'auth-source' Thanks for the suggestion. After some thought, I decided to change the interface of erc-tls from the two separate :client-key and :client-crt arguments in v1 of the patch to just one :client-certificate in v2, matching that of `open-network-stream'. I tested the change with `:client-certificate t' and confirm that it works fine for me. I've attached v2 below, and if there are no other comments or feedback I'll commit it to emacs.git in a few days. Main changes from v1 include using just one :client-certificate argument like `open-network-stream', adding a NEWS entry, and documenting erc-tls in the ERC manual. * * * [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-support-for-using-a-TLS-client-certificate-with-.patch --] [-- Type: text/x-diff, Size: 14404 bytes --] From 0070321f127169262e1f562734485e495e041e32 Mon Sep 17 00:00:00 2001 From: Amin Bandali <bandali@gnu.org> Date: Wed, 14 Apr 2021 23:32:54 -0400 Subject: [PATCH] Add support for using a TLS client certificate with 'erc-tls' * lisp/erc/erc-backend.el (erc-session-client-certificate): New buffer-local variable storing the TLS client certificate used for the current connection. (erc-open-network-stream): Use open-network-stream instead of make-network-process, and pass any additional arguments to it. (erc-server-connect): Add an optional client-certificate argument that if present is passed with the :client-certificate keyword as part of the arguments to erc-server-connect-function. * lisp/erc/erc.el (erc-open): Add new optional client-certificate argument, set it as erc-session-client-certificate, and pass it along to erc-server-connect. (erc-tls): Add new client-certificate keyword argument and pass it in the direct call to erc-open (instead of going through erc). (erc-open-tls-stream): Pass any additional arguments (such as :client-certificate) to open-network-stream. Also allow overriding :nowait if desired. * doc/misc/erc.texi: Add documentation for erc-tls, including the new :client-certificate argument. * etc/NEWS: Announce the change. --- doc/misc/erc.texi | 66 +++++++++++++++++++++++++++++ etc/NEWS | 36 ++++++++++++++++ lisp/erc/erc-backend.el | 30 +++++++++---- lisp/erc/erc.el | 94 +++++++++++++++++++++++++++++++++-------- 4 files changed, 200 insertions(+), 26 deletions(-) diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index d635cac5ab..0620f18096 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -523,6 +523,72 @@ Connecting @end example @end defun +To connect securely over an encrypted TLS connection, use @kbd{M-x +erc-tls}. + +@defun erc-tls +Select connection parameters and run ERC over TLS@. +Non-interactively, it takes the following keyword arguments. + +@itemize @bullet +@item @var{server} +@item @var{port} +@item @var{nick} +@item @var{password} +@item @var{full-name} +@item @var{client-certificate} +@end itemize + +That is, if called with the following arguments, @var{server} and +@var{full-name} will be set to those values, whereas +@code{erc-compute-port}, @code{erc-compute-nick} and +@code{erc-compute-full-name} will be invoked for the values of the +other parameters, and @code{client-certificate} will be @code{nil}. + +@example +(erc-tls :server "chat.freenode.net" :full-name "Harry S Truman") +@end example + +To use a certificate with @code{erc-tls}, specify the optional +@var{client-certificate} keyword argument, whose value should be +as described in the documentation of @code{open-network-stream}: if +non-@code{nil}, it should either be a list where the first element is +the file name of the private key corresponding to a client certificate +and the second element is the file name of the client certificate +itself to use when connecting over TLS, or @code{t}, which means that +@code{auth-source} will be queried for the private key and the +certificate. + +Examples of use: + +@example + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + '("/home/bandali/my-cert.key" + "/home/bandali/my-cert.crt")) +@end example + +@example + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + `(,(expand-file-name "~/cert-freenode.key") + ,(expand-file-name "~/cert-freenode.crt"))) +@end example + +@example + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate t) +@end example + +In the case of @code{:client-certificate t}, you will need to add a +line like the following to your authinfo file +(e.g. @file{~/.authinfo.gpg}): + +@example +machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt +@end example +@end defun + @subheading Server @defun erc-compute-server &optional server diff --git a/etc/NEWS b/etc/NEWS index b641e8d95f..22a9243ae2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1731,6 +1731,42 @@ type for highlighting the entire message but not the sender's nick. The 'erc-status-sidebar' package which provides a HexChat-like activity overview sidebar for joined IRC channels is now part of ERC. ++++ +*** erc-tls now supports specifying a TLS client certificate. +The 'erc-tls' function has been updated to allow specifying a TLS +client certificate for authentication, as an alternative to NickServ +password-based authentication. This is referred to as "CertFP" (short +for Certificate Fingerprint) by several IRC networks. + +To use a certificate with 'erc-tls', specify the ':client-certificate' +optional parameter, whose value should be as described in the +documentation of 'open-network-stream': if non-nil, it should either +be a list where the first element is the file name of the private key +corresponding to a client certificate and the second element is the +file name of the client certificate itself to use when connecting over +TLS, or t, which means that 'auth-source' will be queried for the +private key and the certificate. + +Examples of use: + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + '("/home/bandali/my-cert.key" + "/home/bandali/my-cert.crt")) + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + `(,(expand-file-name "~/cert-freenode.key") + ,(expand-file-name "~/cert-freenode.crt"))) + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate t) + +In the case of ':client-certificate t', you will need to add a line +like the following to your authinfo file (e.g. "~/.authinfo.gpg"): + + machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt + ** Battery --- diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index b1f97aea06..67db572701 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -138,6 +138,13 @@ erc-session-connector (defvar-local erc-session-port nil "The port used to connect to.") +(defvar-local erc-session-client-certificate nil + "TLS client certificate used when connecting over TLS. +If non-nil, should either be a list where the first element is +the certificate key file name, and the second element is the +certificate file name itself, or t, which means that +`auth-source' will be queried for the key and the certificate.") + (defvar-local erc-server-announced-name nil "The name the server announced to use.") @@ -505,18 +512,23 @@ erc-server-process-alive (memq (process-status erc-server-process) '(run open))))) ;;;; Connecting to a server -(defun erc-open-network-stream (name buffer host service) - "As `open-network-stream', but does non-blocking IO" - (make-network-process :name name :buffer buffer - :host host :service service :nowait t)) +(defun erc-open-network-stream (name buffer host service &rest parameters) + "Like `open-network-stream', but does non-blocking IO." + (let ((p (plist-put parameters :nowait t))) + (open-network-stream name buffer host service p))) -(defun erc-server-connect (server port buffer) +(defun erc-server-connect (server port buffer &optional client-certificate) "Perform the connection and login using the specified SERVER and PORT. -We will store server variables in the buffer given by BUFFER." - (let ((msg (erc-format-message 'connect ?S server ?p port)) process) +We will store server variables in the buffer given by BUFFER. +CLIENT-CERTIFICATE may optionally be used to specify a TLS client +certificate to use for authentication when connecting over +TLS (see `erc-session-client-certificate' for more details)." + (let ((msg (erc-format-message 'connect ?S server ?p port)) process + (args `(,(format "erc-%s-%s" server port) nil ,server ,port))) + (when client-certificate + (setq args `(,@args :client-certificate ,client-certificate))) (message "%s" msg) - (setq process (funcall erc-server-connect-function - (format "erc-%s-%s" server port) nil server port)) + (setq process (apply erc-server-connect-function args)) (unless (processp process) (error "Connection attempt failed")) ;; Misc server variables diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index e20aa8057d..c97f6d4342 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -47,8 +47,12 @@ ;; ;; M-x erc RET ;; -;; After you are connected to a server, you can use C-h m or have a look at -;; the ERC menu. +;; or +;; +;; M-x erc-tls RET +;; +;; to connect over TLS (encrypted). Once you are connected to a +;; server, you can use C-h m or have a look at the ERC menu. ;;; Code: @@ -1967,7 +1971,8 @@ erc-setup-buffer (switch-to-buffer buffer))))) (defun erc-open (&optional server port nick full-name - connect passwd tgt-list channel process) + connect passwd tgt-list channel process + client-certificate) "Connect to SERVER on PORT as NICK with FULL-NAME. If CONNECT is non-nil, connect to the server. Otherwise assume @@ -1977,6 +1982,13 @@ erc-open Use PASSWD as user password on the server. If TGT-LIST is non-nil, use it to initialize `erc-default-recipients'. +CLIENT-CERTIFICATE, if non-nil, should either be a list where the +first element is the file name of the private key corresponding +to a client certificate and the second element is the file name +of the client certificate itself to use when connecting over TLS, +or t, which means that `auth-source' will be queried for the +private key and the certificate. + Returns the buffer for the given server or channel." (let ((server-announced-name (when (and (boundp 'erc-session-server) (string= server erc-session-server)) @@ -2059,6 +2071,8 @@ erc-open (if (functionp secret) (funcall secret) secret)))) + ;; client certificate (only useful if connecting over TLS) + (setq erc-session-client-certificate client-certificate) ;; debug output buffer (setq erc-dbuf (when erc-log-p @@ -2079,7 +2093,10 @@ erc-open (run-hook-with-args 'erc-connect-pre-hook buffer) (when connect - (erc-server-connect erc-session-server erc-session-port buffer)) + (erc-server-connect erc-session-server + erc-session-port + buffer + erc-session-client-certificate)) (erc-update-mode-line) ;; Now display the buffer in a window as per user wishes. @@ -2203,15 +2220,15 @@ erc (port (erc-compute-port)) (nick (erc-compute-nick)) password - (full-name (erc-compute-full-name))) + (full-name (erc-compute-full-name)) That is, if called with (erc :server \"chat.freenode.net\" :full-name \"Harry S Truman\") then the server and full-name will be set to those values, whereas -`erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will -be invoked for the values of the other parameters." +`erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' +will be invoked for the values of the other parameters." (interactive (erc-select-read-args)) (erc-open server port nick full-name t password)) @@ -2220,21 +2237,64 @@ 'erc-select (defalias 'erc-ssl #'erc-tls) ;;;###autoload -(defun erc-tls (&rest r) - "Interactively select TLS connection parameters and run ERC. -Arguments are the same as for `erc'." +(cl-defun erc-tls (&key (server (erc-compute-server)) + (port (erc-compute-port)) + (nick (erc-compute-nick)) + password + (full-name (erc-compute-full-name)) + client-certificate) + "ERC is a powerful, modular, and extensible IRC client. +This function is the main entry point for ERC over TLS. + +It allows you to select connection parameters, and then starts +ERC over TLS. + +Non-interactively, it takes the keyword arguments + (server (erc-compute-server)) + (port (erc-compute-port)) + (nick (erc-compute-nick)) + password + (full-name (erc-compute-full-name)) + client-certificate + +That is, if called with + + (erc-tls :server \"chat.freenode.net\" :full-name \"Harry S Truman\") + +then the server and full-name will be set to those values, whereas +`erc-compute-port', `erc-compute-nick', and `erc-compute-full-name' +will be invoked for the values of their respective parameters. + +CLIENT-CERTIFICATE, if non-nil, should either be a list where the +first element is the certificate key file name, and the second +element is the certificate file name itself, or t, which means +that `auth-source' will be queried for the key and the +certificate. + +Example usage: + + (erc-tls :server \"chat.freenode.net\" :port 6697 + :client-certificate + '(\"/data/bandali/my-cert.key\" + \"/data/bandali/my-cert.crt\"))" (interactive (let ((erc-default-port erc-default-port-tls)) (erc-select-read-args))) (let ((erc-server-connect-function 'erc-open-tls-stream)) - (apply #'erc r))) + (erc-open server port nick full-name t password + nil nil nil client-certificate))) -(defun erc-open-tls-stream (name buffer host port) +(defun erc-open-tls-stream (name buffer host port &rest parameters) "Open an TLS stream to an IRC server. -The process will be given the name NAME, its target buffer will be -BUFFER. HOST and PORT specify the connection target." - (open-network-stream name buffer host port - :nowait t - :type 'tls)) +The process will be given the name NAME, its target buffer will +be BUFFER. HOST and PORT specify the connection target. +PARAMETERS should be a sequence of keywords and values, per +`open-network-stream'." + (let ((p (plist-put parameters :type 'tls)) + args) + (unless (plist-member p :nowait) + (setq p (plist-put p :nowait t))) + (setq args `(,name ,buffer ,host ,port ,@p)) + (apply #'open-network-stream args))) ;;; Displaying error messages -- 2.17.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <87h7k3mm6x.fsf@gnu.org>]
* bug#47788: Add support for TLS client certificates to 'erc-tls' [not found] ` <87h7k3mm6x.fsf@gnu.org> @ 2021-04-20 13:49 ` J.P. 2021-04-23 0:45 ` Amin Bandali [not found] ` <871rb1zv4m.fsf@gnu.org> 0 siblings, 2 replies; 8+ messages in thread From: J.P. @ 2021-04-20 13:49 UTC (permalink / raw) To: Amin Bandali; +Cc: 47788, Robert Pluim, emacs-erc Amin Bandali <bandali@gnu.org> writes: >> It reconnected successfully with no hiccups, so I think that's one >> for the win column. This continues to be the case with the latest changes applied; ditto when using the authinfo variant of the new :client-certificate param. >> Beyond that, users may appreciate a mention of the new additions in the >> info manual and maybe the wiki as well (instead of just NEWS). > > Certainly; done in v2. Nice job. This sort of thing can be a real time sink (at least for me). One question. And stop me if I've confused myself here, but the doc string and the tex-info section for `erc-tls' both offer the same example (borrowed from their plain `erc' counterparts) in which the function `erc-compute-full-name' is said to be consulted despite the :full-name "Harry S. Truman" keyword arg being present. While it's (technically) true that `erc-compute-full-name' always runs, I suspect its inclusion in the original example was inadvertent (or something about it has changed since 2007). Would it perhaps make sense to omit `erc-compute-full-name' from the Truman example? >> As is, I think it basically enforces non-nil (unless that's the idea). > > Indeed :-). My intention was to enforce non-nil there, to always make > the connection in an asynchronous/non-blocking way, similar to its dual, > `erc-open-network-stream'. I think passing :nowait nil could be useful > for debugging, but off top of my head I can't think of any other reason > one would want to do it. And for debugging, one could easily redefine > the function completely. On the other hand, I don't see any harm in > allowing/respecting :nowait nil if it's explicitly set. So I've changed > the above plist-get to plist-member in v2. Thanks, but I shouldn't have proposed that tweak without a concrete use case in mind. In fact, I've only ever needed :nowait to be nil when using a custom opener. If my suggestion made things more confusing or distracting, my apologies. Perhaps it's best to just revert to what you had originally or even just force it to t. (Not that you should waste another second on this relative nothingburger.) > Thanks for the suggestion. After some thought, I decided to change the > interface of erc-tls from the two separate :client-key and :client-crt > arguments in v1 of the patch to just one :client-certificate in v2, > matching that of `open-network-stream'. I tested the change with > `:client-certificate t' and confirm that it works fine for me. The interface change is a welcome improvement, IMO. Although dealing with a list may feel slightly more cumbersome to some, the multiple helpful examples make that a nonissue. (And sparing contributors an extra param to worry about is a nice bonus as well.) But I guess the real win is in accommodating the authinfo facility, which seems a rather obvious and essential inclusion in retrospect. Great work! ^ permalink raw reply [flat|nested] 8+ messages in thread
* bug#47788: Add support for TLS client certificates to 'erc-tls' 2021-04-20 13:49 ` J.P. @ 2021-04-23 0:45 ` Amin Bandali [not found] ` <871rb1zv4m.fsf@gnu.org> 1 sibling, 0 replies; 8+ messages in thread From: Amin Bandali @ 2021-04-23 0:45 UTC (permalink / raw) To: J.P.; +Cc: Robert Pluim, 47788-done, emacs-erc [-- Attachment #1: Type: text/plain, Size: 3115 bytes --] J.P. writes: > Amin Bandali <bandali@gnu.org> writes: > >>> It reconnected successfully with no hiccups, so I think that's one >>> for the win column. > > This continues to be the case with the latest changes applied; ditto > when using the authinfo variant of the new :client-certificate param. Great! >>> Beyond that, users may appreciate a mention of the new additions in the >>> info manual and maybe the wiki as well (instead of just NEWS). >> >> Certainly; done in v2. > > Nice job. This sort of thing can be a real time sink (at least for me). Thanks, and agreed; but it's good to take the time and do it anyway. :-) > One question. And stop me if I've confused myself here, but the doc > string and the tex-info section for `erc-tls' both offer the same > example (borrowed from their plain `erc' counterparts) in which the > function `erc-compute-full-name' is said to be consulted despite the > :full-name "Harry S. Truman" keyword arg being present. While it's > (technically) true that `erc-compute-full-name' always runs, I suspect > its inclusion in the original example was inadvertent (or something > about it has changed since 2007). Would it perhaps make sense to omit > `erc-compute-full-name' from the Truman example? Yeah that's fair! I've tried to clarify/remedy that in the latest revision. [...] > > Thanks, but I shouldn't have proposed that tweak without a concrete use > case in mind. In fact, I've only ever needed :nowait to be nil when > using a custom opener. If my suggestion made things more confusing or > distracting, my apologies. Perhaps it's best to just revert to what you > had originally or even just force it to t. (Not that you should waste > another second on this relative nothingburger.) No worries :-). And per our short discussion on #erc the other day, there could be a legitimate use-case for that. So I think it's safe to say that all in all it was a net positive change. >> Thanks for the suggestion. After some thought, I decided to change the >> interface of erc-tls from the two separate :client-key and :client-crt >> arguments in v1 of the patch to just one :client-certificate in v2, >> matching that of `open-network-stream'. I tested the change with >> `:client-certificate t' and confirm that it works fine for me. > > The interface change is a welcome improvement, IMO. Although dealing > with a list may feel slightly more cumbersome to some, the multiple > helpful examples make that a nonissue. (And sparing contributors an > extra param to worry about is a nice bonus as well.) But I guess the > real win is in accommodating the authinfo facility, which seems a rather > obvious and essential inclusion in retrospect. Great work! > Awesome. Yeah I couldn't think of a more straightforward and/or less cumbersome way of doing it, except for using the same shape of argument as expected by `open-network-stream'. Per usual, I would be open to reconsideration if a better way of doing it is suggested. For now, I went ahead and finally installed the attached patch on the master branch. Thanks for all the feedback/suggestions. :-) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-support-for-using-a-TLS-client-certificate-with-.patch --] [-- Type: text/x-diff, Size: 15514 bytes --] From 344f769491a84b6d47ee3722054b214167572219 Mon Sep 17 00:00:00 2001 From: Amin Bandali <bandali@gnu.org> Date: Thu, 22 Apr 2021 20:22:38 -0400 Subject: [PATCH] Add support for using a TLS client certificate with 'erc-tls' (bug#47788) * lisp/erc/erc-backend.el (erc-session-client-certificate): New buffer-local variable storing the TLS client certificate used for the current connection. (erc-open-network-stream): Use open-network-stream instead of make-network-process, and pass any additional arguments to it. (erc-server-connect): Add an optional client-certificate argument that if present is passed with the :client-certificate keyword as part of the arguments to erc-server-connect-function. * lisp/erc/erc.el (erc-open): Add new optional client-certificate argument, set it as erc-session-client-certificate, and pass it along to erc-server-connect. (erc): Clarify documentation string with respect to the full-name argument. (erc-tls): Add new client-certificate keyword argument and pass it in the direct call to erc-open (instead of going through erc). (erc-open-tls-stream): Pass any additional arguments (such as :client-certificate) to open-network-stream. Also allow overriding :nowait if desired. * doc/misc/erc.texi: Add documentation for erc-tls, including the new :client-certificate argument. * etc/NEWS: Announce the change. --- doc/misc/erc.texi | 73 +++++++++++++++++++++++++++-- etc/NEWS | 36 +++++++++++++++ lisp/erc/erc-backend.el | 30 ++++++++---- lisp/erc/erc.el | 100 ++++++++++++++++++++++++++++++++-------- 4 files changed, 208 insertions(+), 31 deletions(-) diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index d635cac5ab..45a753d43e 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -514,15 +514,82 @@ Connecting That is, if called with the following arguments, @var{server} and @var{full-name} will be set to those values, whereas -@code{erc-compute-port}, @code{erc-compute-nick} and -@code{erc-compute-full-name} will be invoked for the values of the other -parameters. +@code{erc-compute-port} and @code{erc-compute-nick} will be invoked +for the values of the other parameters. @example (erc :server "chat.freenode.net" :full-name "Harry S Truman") @end example @end defun +To connect securely over an encrypted TLS connection, use @kbd{M-x +erc-tls}. + +@defun erc-tls +Select connection parameters and run ERC over TLS@. +Non-interactively, it takes the following keyword arguments. + +@itemize @bullet +@item @var{server} +@item @var{port} +@item @var{nick} +@item @var{password} +@item @var{full-name} +@item @var{client-certificate} +@end itemize + +That is, if called with the following arguments, @var{server} and +@var{full-name} will be set to those values, whereas +@code{erc-compute-port} and @code{erc-compute-nick} will be invoked +for the values of the other parameters, and @code{client-certificate} +will be @code{nil}. + +@example +(erc-tls :server "chat.freenode.net" :full-name "Harry S Truman") +@end example + +To use a certificate with @code{erc-tls}, specify the optional +@var{client-certificate} keyword argument, whose value should be as +described in the documentation of @code{open-network-stream}: if +non-@code{nil}, it should either be a list where the first element is +the file name of the private key corresponding to a client certificate +and the second element is the file name of the client certificate +itself to use when connecting over TLS, or @code{t}, which means that +@code{auth-source} will be queried for the private key and the +certificate. Authenticating using a TLS client certificate is also +refered to as ``CertFP'' (Certificate Fingerprint) authentication by +various IRC networks. + +Examples of use: + +@example +(erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + '("/home/bandali/my-cert.key" + "/home/bandali/my-cert.crt")) +@end example + +@example +(erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + `(,(expand-file-name "~/cert-freenode.key") + ,(expand-file-name "~/cert-freenode.crt"))) +@end example + +@example +(erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate t) +@end example + +In the case of @code{:client-certificate t}, you will need to add a +line like the following to your authinfo file +(e.g. @file{~/.authinfo.gpg}): + +@example +machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt +@end example +@end defun + @subheading Server @defun erc-compute-server &optional server diff --git a/etc/NEWS b/etc/NEWS index 6fe4e98a50..34aeaf028b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1746,6 +1746,42 @@ type for highlighting the entire message but not the sender's nick. The 'erc-status-sidebar' package which provides a HexChat-like activity overview sidebar for joined IRC channels is now part of ERC. ++++ +*** erc-tls now supports specifying a TLS client certificate. +The 'erc-tls' function has been updated to allow specifying a TLS +client certificate for authentication, as an alternative to NickServ +password-based authentication. This is referred to as "CertFP" (short +for Certificate Fingerprint) by several IRC networks. + +To use a certificate with 'erc-tls', specify the ':client-certificate' +optional parameter, whose value should be as described in the +documentation of 'open-network-stream': if non-nil, it should either +be a list where the first element is the file name of the private key +corresponding to a client certificate and the second element is the +file name of the client certificate itself to use when connecting over +TLS, or t, which means that 'auth-source' will be queried for the +private key and the certificate. + +Examples of use: + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + '("/home/bandali/my-cert.key" + "/home/bandali/my-cert.crt")) + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate + `(,(expand-file-name "~/cert-freenode.key") + ,(expand-file-name "~/cert-freenode.crt"))) + + (erc-tls :server "chat.freenode.net" :port 6697 + :client-certificate t) + +In the case of ':client-certificate t', you will need to add a line +like the following to your authinfo file (e.g. "~/.authinfo.gpg"): + + machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt + ** Battery --- diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index b1f97aea06..67db572701 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -138,6 +138,13 @@ erc-session-connector (defvar-local erc-session-port nil "The port used to connect to.") +(defvar-local erc-session-client-certificate nil + "TLS client certificate used when connecting over TLS. +If non-nil, should either be a list where the first element is +the certificate key file name, and the second element is the +certificate file name itself, or t, which means that +`auth-source' will be queried for the key and the certificate.") + (defvar-local erc-server-announced-name nil "The name the server announced to use.") @@ -505,18 +512,23 @@ erc-server-process-alive (memq (process-status erc-server-process) '(run open))))) ;;;; Connecting to a server -(defun erc-open-network-stream (name buffer host service) - "As `open-network-stream', but does non-blocking IO" - (make-network-process :name name :buffer buffer - :host host :service service :nowait t)) +(defun erc-open-network-stream (name buffer host service &rest parameters) + "Like `open-network-stream', but does non-blocking IO." + (let ((p (plist-put parameters :nowait t))) + (open-network-stream name buffer host service p))) -(defun erc-server-connect (server port buffer) +(defun erc-server-connect (server port buffer &optional client-certificate) "Perform the connection and login using the specified SERVER and PORT. -We will store server variables in the buffer given by BUFFER." - (let ((msg (erc-format-message 'connect ?S server ?p port)) process) +We will store server variables in the buffer given by BUFFER. +CLIENT-CERTIFICATE may optionally be used to specify a TLS client +certificate to use for authentication when connecting over +TLS (see `erc-session-client-certificate' for more details)." + (let ((msg (erc-format-message 'connect ?S server ?p port)) process + (args `(,(format "erc-%s-%s" server port) nil ,server ,port))) + (when client-certificate + (setq args `(,@args :client-certificate ,client-certificate))) (message "%s" msg) - (setq process (funcall erc-server-connect-function - (format "erc-%s-%s" server port) nil server port)) + (setq process (apply erc-server-connect-function args)) (unless (processp process) (error "Connection attempt failed")) ;; Misc server variables diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index e20aa8057d..43661a2fc4 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -47,8 +47,12 @@ ;; ;; M-x erc RET ;; -;; After you are connected to a server, you can use C-h m or have a look at -;; the ERC menu. +;; or +;; +;; M-x erc-tls RET +;; +;; to connect over TLS (encrypted). Once you are connected to a +;; server, you can use C-h m or have a look at the ERC menu. ;;; Code: @@ -1967,7 +1971,8 @@ erc-setup-buffer (switch-to-buffer buffer))))) (defun erc-open (&optional server port nick full-name - connect passwd tgt-list channel process) + connect passwd tgt-list channel process + client-certificate) "Connect to SERVER on PORT as NICK with FULL-NAME. If CONNECT is non-nil, connect to the server. Otherwise assume @@ -1977,6 +1982,13 @@ erc-open Use PASSWD as user password on the server. If TGT-LIST is non-nil, use it to initialize `erc-default-recipients'. +CLIENT-CERTIFICATE, if non-nil, should either be a list where the +first element is the file name of the private key corresponding +to a client certificate and the second element is the file name +of the client certificate itself to use when connecting over TLS, +or t, which means that `auth-source' will be queried for the +private key and the certificate. + Returns the buffer for the given server or channel." (let ((server-announced-name (when (and (boundp 'erc-session-server) (string= server erc-session-server)) @@ -2059,6 +2071,8 @@ erc-open (if (functionp secret) (funcall secret) secret)))) + ;; client certificate (only useful if connecting over TLS) + (setq erc-session-client-certificate client-certificate) ;; debug output buffer (setq erc-dbuf (when erc-log-p @@ -2079,7 +2093,10 @@ erc-open (run-hook-with-args 'erc-connect-pre-hook buffer) (when connect - (erc-server-connect erc-session-server erc-session-port buffer)) + (erc-server-connect erc-session-server + erc-session-port + buffer + erc-session-client-certificate)) (erc-update-mode-line) ;; Now display the buffer in a window as per user wishes. @@ -2196,22 +2213,22 @@ erc "ERC is a powerful, modular, and extensible IRC client. This function is the main entry point for ERC. -It permits you to select connection parameters, and then starts ERC. +It allows selecting connection parameters, and then starts ERC. Non-interactively, it takes the keyword arguments (server (erc-compute-server)) (port (erc-compute-port)) (nick (erc-compute-nick)) password - (full-name (erc-compute-full-name))) + (full-name (erc-compute-full-name)) That is, if called with (erc :server \"chat.freenode.net\" :full-name \"Harry S Truman\") -then the server and full-name will be set to those values, whereas -`erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will -be invoked for the values of the other parameters." +then the server and full-name will be set to those values, +whereas `erc-compute-port' and `erc-compute-nick' will be invoked +for the values of the other parameters." (interactive (erc-select-read-args)) (erc-open server port nick full-name t password)) @@ -2220,21 +2237,66 @@ 'erc-select (defalias 'erc-ssl #'erc-tls) ;;;###autoload -(defun erc-tls (&rest r) - "Interactively select TLS connection parameters and run ERC. -Arguments are the same as for `erc'." +(cl-defun erc-tls (&key (server (erc-compute-server)) + (port (erc-compute-port)) + (nick (erc-compute-nick)) + password + (full-name (erc-compute-full-name)) + client-certificate) + "ERC is a powerful, modular, and extensible IRC client. +This function is the main entry point for ERC over TLS. + +It allows selecting connection parameters, and then starts ERC +over TLS. + +Non-interactively, it takes the keyword arguments + (server (erc-compute-server)) + (port (erc-compute-port)) + (nick (erc-compute-nick)) + password + (full-name (erc-compute-full-name)) + client-certificate + +That is, if called with + + (erc-tls :server \"chat.freenode.net\" :full-name \"Harry S Truman\") + +then the server and full-name will be set to those values, +whereas `erc-compute-port' and `erc-compute-nick' will be invoked +for the values of their respective parameters. + +CLIENT-CERTIFICATE, if non-nil, should either be a list where the +first element is the certificate key file name, and the second +element is the certificate file name itself, or t, which means +that `auth-source' will be queried for the key and the +certificate. Authenticating using a TLS client certificate is +also refered to as \"CertFP\" (Certificate Fingerprint) +authentication by various IRC networks. + +Example usage: + + (erc-tls :server \"chat.freenode.net\" :port 6697 + :client-certificate + '(\"/data/bandali/my-cert.key\" + \"/data/bandali/my-cert.crt\"))" (interactive (let ((erc-default-port erc-default-port-tls)) (erc-select-read-args))) (let ((erc-server-connect-function 'erc-open-tls-stream)) - (apply #'erc r))) + (erc-open server port nick full-name t password + nil nil nil client-certificate))) -(defun erc-open-tls-stream (name buffer host port) +(defun erc-open-tls-stream (name buffer host port &rest parameters) "Open an TLS stream to an IRC server. -The process will be given the name NAME, its target buffer will be -BUFFER. HOST and PORT specify the connection target." - (open-network-stream name buffer host port - :nowait t - :type 'tls)) +The process will be given the name NAME, its target buffer will +be BUFFER. HOST and PORT specify the connection target. +PARAMETERS should be a sequence of keywords and values, per +`open-network-stream'." + (let ((p (plist-put parameters :type 'tls)) + args) + (unless (plist-member p :nowait) + (setq p (plist-put p :nowait t))) + (setq args `(,name ,buffer ,host ,port ,@p)) + (apply #'open-network-stream args))) ;;; Displaying error messages -- 2.17.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <871rb1zv4m.fsf@gnu.org>]
* bug#47788: Add support for TLS client certificates to 'erc-tls' [not found] ` <871rb1zv4m.fsf@gnu.org> @ 2021-04-23 12:31 ` J.P. [not found] ` <87r1j1chcd.fsf@neverwas.me> 1 sibling, 0 replies; 8+ messages in thread From: J.P. @ 2021-04-23 12:31 UTC (permalink / raw) To: Amin Bandali; +Cc: 47788-done, emacs-erc Hey, guess we both missed this: @@ -505,18 +512,23 @@ erc-server-process-alive (memq (process-status erc-server-process) '(run open))))) ;;;; Connecting to a server -(defun erc-open-network-stream (name buffer host service) - "As `open-network-stream', but does non-blocking IO" - (make-network-process :name name :buffer buffer - :host host :service service :nowait t)) +(defun erc-open-network-stream (name buffer host service &rest parameters) + "Like `open-network-stream', but does non-blocking IO." + (let ((p (plist-put parameters :nowait t))) + (open-network-stream name buffer host service p))) ;; ^~~~~~~~ Need an apply #' here because ~~~~~~^ -(defun erc-server-connect (server port buffer) +(defun erc-server-connect (server port buffer &optional client-certificate) Turns out my silly tests for one of those unofficial #erc bugs (the azur12 one) caught it by failing (which means your patch magically fixed the issue!). Anyway, no rush; I doubt this really impacts anyone. ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <87r1j1chcd.fsf@neverwas.me>]
* bug#47788: Add support for TLS client certificates to 'erc-tls' [not found] ` <87r1j1chcd.fsf@neverwas.me> @ 2021-04-23 22:52 ` Amin Bandali 0 siblings, 0 replies; 8+ messages in thread From: Amin Bandali @ 2021-04-23 22:52 UTC (permalink / raw) To: J.P.; +Cc: 47788-done, emacs-erc J.P. writes: > Hey, guess we both missed this: > > @@ -505,18 +512,23 @@ erc-server-process-alive > (memq (process-status erc-server-process) '(run open))))) > > ;;;; Connecting to a server > -(defun erc-open-network-stream (name buffer host service) > - "As `open-network-stream', but does non-blocking IO" > - (make-network-process :name name :buffer buffer > - :host host :service service :nowait t)) > +(defun erc-open-network-stream (name buffer host service &rest parameters) > + "Like `open-network-stream', but does non-blocking IO." > + (let ((p (plist-put parameters :nowait t))) > + (open-network-stream name buffer host service p))) > ;; ^~~~~~~~ Need an apply #' here because ~~~~~~^ > > -(defun erc-server-connect (server port buffer) > +(defun erc-server-connect (server port buffer &optional client-certificate) > > Turns out my silly tests for one of those unofficial #erc bugs (the > azur12 one) caught it by failing (which means your patch magically fixed > the issue!). > > Anyway, no rush; I doubt this really impacts anyone. > Oh whoops! Good catch, and thanks for the quick notice. :-) I committed a fix to the master branch. ^ permalink raw reply [flat|nested] 8+ messages in thread
* bug#47788: Add support for TLS client certificates to 'erc-tls' 2021-04-15 4:16 bug#47788: Add support for TLS client certificates to 'erc-tls' Amin Bandali 2021-04-15 12:44 ` J.P. @ 2021-04-16 7:38 ` Robert Pluim 1 sibling, 0 replies; 8+ messages in thread From: Robert Pluim @ 2021-04-16 7:38 UTC (permalink / raw) To: Amin Bandali; +Cc: 47788, emacs-erc, jp >>>>> On Thu, 15 Apr 2021 00:16:38 -0400, Amin Bandali <bandali@gnu.org> said: Amin> Tags: patch Amin> After a few recent changes in my IRC/ERC setup, I felt ERC's lack of Amin> support for connecting to IRC networks using TLS client certificates as Amin> an alternative to traditional password-based authentication. So I spent Amin> some time a few nights ago and wired things up in ERC to allow passing a Amin> client certificate to `open-network-stream'. It would be nice if you could arrange for an option to pass ':client-certificate t' to 'open-network-stream' so it would leverage 'auth-source' Robert ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-04-23 22:52 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-04-15 4:16 bug#47788: Add support for TLS client certificates to 'erc-tls' Amin Bandali 2021-04-15 12:44 ` J.P. 2021-04-18 19:23 ` Amin Bandali [not found] ` <87h7k3mm6x.fsf@gnu.org> 2021-04-20 13:49 ` J.P. 2021-04-23 0:45 ` Amin Bandali [not found] ` <871rb1zv4m.fsf@gnu.org> 2021-04-23 12:31 ` J.P. [not found] ` <87r1j1chcd.fsf@neverwas.me> 2021-04-23 22:52 ` Amin Bandali 2021-04-16 7:38 ` Robert Pluim
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).