mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-15 18:40:39 -08:00
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.
This commit is contained in:
parent
1c3a86e7fc
commit
344f769491
4 changed files with 208 additions and 31 deletions
|
|
@ -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
|
||||
|
|
|
|||
36
etc/NEWS
36
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
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
100
lisp/erc/erc.el
100
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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue