emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] certfp for rcirc


From: Omar Polo
Subject: [RFC] certfp for rcirc
Date: Wed, 11 Nov 2021 10:02:27 +0100
User-agent: mu4e 1.6.9; emacs 29.0.50

Hello,

I was told earlier today that is actually possible to log in to an irc
server using TLS client certificates.  I like the idea and I wanted to
used it, but unfortunately, rcirc doesn't seem to support them.

I briefly tried circe, which has support for certfp, and while it's a
great irc client, I still like rcirc more (eheh) so here's a try at
adding the certfp login style to rcirc.  It's still missing the
documentation bits, but as per the subject, I'd like to get a feedback
on the diff before proceding with the documentation.

Here's some documentation on how to use certfp:

        https://libera.chat/guides/certfp

To use certfp you need to:

 1. generate a certificate (e.g. with openssl(1))
 2. the first time:
      - connect using the certificate
      - authenticate via the usual /msg nickserv identify ...
      - associate the certificate with your account
                /msg NickServ CERT ADD
 3. from now on every time you connect with that cert, you're
    automatically authenticated.  No passwords needed.

With the following patch I can connect to libera with the following
configuration:

(setq rcirc-server-alist
      '(("irc.libera.chat" :channels (...) :port 6697)))

(setq rcirc-authinfo
      '(("libera"
         certfp
         "/home/op/.emacs.d/irc/key.pem"
         "/home/op/.emacs.d/irc/cert.pem")))

Here's an excerpt from the *irc.libera.chat* server in a emacs -Q with
the above config and the custom rcirc.el loaded:

[...]
23:28 *** erbium.libera.chat 001 Welcome to the Libera.Chat Internet
                                 Relay Chat Network op2
                                                    ^^^
                                      note how I'm already logged in
[...]
23:28 *** op2 MODE +Zi
23:28 -NickServ- This nickname is registered. Please choose a
                 different nickname, or identify via /msg NickServ
                 IDENTIFY op2 <password>
23:28 -NickServ- You have 30 seconds to identify to your nickname
                 before it is changed.
23:28 -NickServ- You are now identified for op2.
23:28 -NickServ- Last login from: ~op<redacted>
                 on Nov 10 22:27:31 2021 +0000.
23:29 /whois op2
[...]
23:29 *** 276 op2 has client certificate fingerprint
              <redacted>
[...]

For some reason I don't know yet, the NickServ still says that I've got
30 seconds to identify myself, but in reality I'm already logged in.  I
don't know basically anything about how the irc protocol works, so I'm
probably missing something incredibly obvious.

What do you think?

Cheers,

Omar Polo


diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 52d74a3394..070218ef0a 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -262,10 +262,12 @@ The ARGUMENTS for each METHOD symbol are:
   `bitlbee': NICK PASSWORD
   `quakenet': ACCOUNT PASSWORD
   `sasl': NICK PASSWORD
+  `certfp': KEY CERT
 
 Examples:
  ((\"Libera.Chat\" nickserv \"bob\" \"p455w0rd\")
   (\"Libera.Chat\" chanserv \"bob\" \"#bobland\" \"passwd99\")
+  (\"Libera.Chat\" certfp \"/path/to/key.pem\" \"/path/to/cert.pem\")
   (\"bitlbee\" bitlbee \"robert\" \"sekrit\")
   (\"dal.net\" nickserv \"bob\" \"sekrit\" \"NickServ@services.dal.net\")
   (\"quakenet.org\" quakenet \"bobby\" \"sekrit\")
@@ -291,7 +293,11 @@ Examples:
                                     (list :tag "SASL"
                                           (const sasl)
                                           (string :tag "Nick")
-                                          (string :tag "Password")))))
+                                          (string :tag "Password"))
+                                    (list :tag "CertFP"
+                                          (const certfp)
+                                          (string :tag "Key")
+                                          (string :tag "Certificate")))))
 
 (defcustom rcirc-auto-authenticate-flag t
   "Non-nil means automatically send authentication string to server.
@@ -547,6 +553,9 @@ If ARG is non-nil, instead prompt for connection 
parameters."
               (password (plist-get (cdr c) :password))
               (encryption (plist-get (cdr c) :encryption))
               (server-alias (plist-get (cdr c) :server-alias))
+              (client-cert (when (eq (rcirc-get-server-method (car c))
+                                     'certfp)
+                             (rcirc-get-server-cert (car c))))
               contact)
           (when-let (((not password))
                      (auth (auth-source-search :host server
@@ -563,7 +572,7 @@ If ARG is non-nil, instead prompt for connection 
parameters."
                  (condition-case nil
                      (let ((process (rcirc-connect server port nick user-name
                                                     full-name channels 
password encryption
-                                                    server-alias)))
+                                                    client-cert server-alias)))
                         (when rcirc-display-server-buffer
                           (pop-to-buffer-same-window (process-buffer 
process))))
                    (quit (message "Quit connecting to %s"
@@ -662,13 +671,22 @@ See `rcirc-connect' for more details on these variables.")
        (when (string-match server-i server)
           (throw 'pass (car args)))))))
 
+(defun rcirc-get-server-cert (server)
+  "Return a list of key and certificate for SERVER."
+  (catch 'pass
+    (dolist (i rcirc-authinfo)
+      (let ((server-i (car i))
+            (args (cddr i)))
+        (when (string-match server-i server)
+          (throw 'pass args))))))
+
 ;;;###autoload
 (defun rcirc-connect (server &optional port nick user-name
                              full-name startup-channels password encryption
-                             server-alias)
+                             certfp server-alias)
   "Connect to SERVER.
 The arguments PORT, NICK, USER-NAME, FULL-NAME, PASSWORD,
-ENCRYPTION, SERVER-ALIAS are interpreted as in
+ENCRYPTION, CERTFP, SERVER-ALIAS are interpreted as in
 `rcirc-server-alist'.  STARTUP-CHANNELS is a list of channels
 that are joined after authentication."
   (save-excursion
@@ -692,10 +710,16 @@ that are joined after authentication."
         (delete-process process))
 
       ;; Set up process
-      (setq process (open-network-stream
-                     (or server-alias server) nil server port-number
-                     :type (or encryption 'plain)
-                     :nowait t))
+      (setq process (if certfp
+                        (open-network-stream
+                         (or server-alias server) nil server port-number
+                         :type 'tls
+                         :nowait t
+                         :client-certificate certfp)
+                      (open-network-stream
+                       (or server-alias server) nil server port-number
+                       :type (or encryption 'plain)
+                       :nowait t)))
       (set-process-coding-system process 'raw-text 'raw-text)
       (with-current-buffer (get-buffer-create (rcirc-generate-new-buffer-name 
process nil))
         (set-process-buffer process (current-buffer))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]