[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 344f769: Add support for using a TLS client certificate with 'erc
From: |
Amin Bandali |
Subject: |
master 344f769: Add support for using a TLS client certificate with 'erc-tls' (bug#47788) |
Date: |
Thu, 22 Apr 2021 20:23:48 -0400 (EDT) |
branch: master
commit 344f769491a84b6d47ee3722054b214167572219
Author: Amin Bandali <bandali@gnu.org>
Commit: Amin Bandali <bandali@gnu.org>
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 d635cac..45a753d 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -514,15 +514,82 @@ Non-interactively, it takes the following keyword
arguments.
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 6fe4e98..34aeaf0 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 b1f97ae..67db572 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -138,6 +138,13 @@ Use `erc-current-nick' to access this.")
(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 @@ The current buffer is given by BUFFER."
(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 e20aa80..43661a2 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 @@ removed from the list will be disabled."
(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 @@ target CHANNEL.
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 @@ Returns the buffer for the given server or channel."
(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 @@ Returns the buffer for the given server or channel."
(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 @@ parameters SERVER and NICK."
"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 @@ be invoked for the values of the other parameters."
(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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 344f769: Add support for using a TLS client certificate with 'erc-tls' (bug#47788),
Amin Bandali <=