ERC is fully equipped to connect to SSL/TLS-enabled servers (e.g. OFTC and Freenode) however, Certificate Authentication support is rather untested.

Note added August, 2017: ‘M-x erc-tls’ might just work without further configuration. Be sure to use the server’s TLS port, e.g. 6697 for freenode.

For the purposes of this guide, head on over to the following OFTC page to get an idea on how to create the necessary certificates

Getting Started

Hack away at your init files, ensuring that SSL/TLS support is enabled:

 (require 'tls)

This allows us to set the tls-program variable that calls external tools “openssl” or “gnutls-cli” to perform the actual connection.

To see how the variable is initally defined:

 [F1] V tls-program

You’ll notice that there are several options for tls-program. tls-program will cycle through the commands until a connection is established with the fallback.

Please note that while you can add CA-chain & accompanying keys to gnutls-cli, ERC may fail to recognise them, and will proceed to create the secure connection using gnutls without certificate authentication.

It is this reason alone that I have opted for openssl:

 (setq tls-program '("openssl s_client -connect %h:%p -no_ssl2 -ign_eof
                                       -CAfile /home/ootput/.private/certs/CAs.pem 
                                       -cert /home/ootput/.private/certs/nick.pem" 
                     "gnutls-cli --priority secure256 
                                 --x509cafile /home/ootput/.private/certs/CAs.pem 
                                 --x509certfile /home/ootput/.private/certs/nick.pem -p %p %h" 
                     "gnutls-cli --priority secure256 -p %p %h"))

Please note that your distro’s implementation of libgnutls may be unsuitable for CA-chaining, as was my case.

Use of gnutls-cli is recommended in the future, however, as most linux projects have sought to replace openssl dependencies with gnutls

Now, assuming you’ve already enabled ‘erc, we can continue to work with the supplied erc-tls command:

 ; M-x start-irc
 (defun start-irc ()
   "Connect to IRC."
   (erc-tls :server "" :port 6697
        :nick "ootput" :full-name "ootput")
   (erc :server "" :port 6667
        :nick "ootput" :full-name "ootput")
   (setq erc-autojoin-channels-alist '(("" "#emacs" "#screen" "#ion")
                                       ("" "#debian"))))

This will establish connection to OFTC on port 6697 (SSL), but more importantly, it will allow us to use certificates for transparent Nickserv auth.

Enjoy your SSL-encrypted IRC session!



While the start-irc will initiate the cert-based ssl connection, a terminated connection will fail to trigger an auto-reconnect with certs. In the absence of valid ssl credentials, this will mean repeated failed attempts to reconnect. A temporary solution would be to have nickserv login and password saved to an erc-auth file to be loaded by erc. – ootput

Yeah, that's an issue indeed. As a temporary hotfix I set erc-server-auto-reconnect to nil

Is there a plan to provide some real fix for this issue? Workaround does not look as ‘solution’. 😟 – gour

Symbol's function definition is void: erc-tls

Hey, put (require ‘erc) in your ~/.emacs. – talau

I followed the tutorial on creating the cert keys and I have Nick.cer, Nick.key and Nick.pem. When I go to configure the tls-program variable, the -CAfile option requires CAs.pem. This tutorial doesn’t explain where to get this file from. – E1f

You skipped a part of the tutorial, E1f. Check under “Connecting to OFTC with your Cert” → “Unlisted Clients” → “Irssi”, and adjust for your designated paths. – ootput

Switching to Emacs 24 seems to ignore tls-program

When using emacs24, I am no longer seeing the openssl process running on my system so I assume it uses a built-in tls library. The certificate isn’t passed in the SSL session either. – vled

Emacs24 doesn’t bother validating the server certificate when using the built-in TLS support either, so the NSA could be right there in the middle and you’d never know. 😟 --seanl

A workaround (found on stack overflow): to not use the built-in GnuTLS support by redefining gnutls-available-p

    (defun gnutls-available-p ()
    "Function redefined in order not to use built-in GnuTLS support"


Emacs 25 bugfix

In emacs 25.2 ‘erc-open-tls-stream’ doesn’t work because it uses ‘open-network-stream’ instead of ‘open-tls-stream’. This version works for me:

    (defun erc-open-tls-stream (name buffer host port)
      "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-tls-stream name buffer host port))

Emacs 26/27 onwards

If you want to use ‘gnutls’(default) with client certificates, then you have to override ‘open-gnutls-stream’, as it is not flexible enough(a patch to upstream would be nice).

Note: You don’t need any previous workarounds on this page like setting ‘tls-program’ (it is deprecated) and the builtin ‘gnutls’ lib does vaildate server certificates(see ‘gnutls-trustfiles’).

I use the following code that uses the cert defined in a global variable when called from ‘erc-tls’:

  (with-eval-after-load 'erc
    ;; erc hack for gnutls for client cert.
    (defvar *uconf/erc-certs* nil
      "erc client certs used by gnutls package for :keylist.")
    ;; copied from the gnutls lib but set :keylist to client certs.
    ;; this function is called from `open-network-stream' with :type tls.
    (defun uconf/open-gnutls-stream (name buffer host service &optional nowait)
      (let ((process (open-network-stream
                      name buffer host service
                      :nowait nowait
                      (and nowait
                           (cons 'gnutls-x509pki
                                  :type 'gnutls-x509pki
                                  :keylist *uconf/erc-certs* ;;added parameter to pass the cert.
                                  :hostname (puny-encode-domain host)))))))
        (if nowait
          (gnutls-negotiate :process process
                            :type 'gnutls-x509pki
                            :keylist *uconf/erc-certs* ;;added parameter to pass the cert.
                            :hostname (puny-encode-domain host)))))
    ;; only set the global variable when used from `erc-tls'.
    (defun uconf/erc-open-tls-stream (name buffer host port)
            (setq *uconf/erc-certs*
                  '(("your keyfile" "your certfile")))
            (open-network-stream name buffer host port
                                 :nowait t
                                 :type 'tls))
        (setq *uconf/erc-certs* nil)))
    (advice-add 'open-gnutls-stream :override #'uconf/open-gnutls-stream)
    (advice-add 'erc-open-tls-stream :override #'uconf/erc-open-tls-stream)