GNU Emacs is where is spend most of my computer time. Using Emacs, I’m writing texts in general and this post in particular, I’m programming, I’m reading RSS feeds and news articles, I’m reading and writing e-mails. Emacs is highly customizable and extensible which is great, in general. However, in the past Emacs valued convenience over security, and by default it does not protect against man-in-the-middle (MITM) attacks. This is about to change with upcoming releases.
In a previous post, I explained how certificate pinning protects against MITM attacks and I recommended GnuTLS with its command line tool gnutls-cli
for do-it-yourself certificate pinning based on trust-on-first-use (TOFU). In this post, I explain my Emacs configuration for certificate pinning with GnuTLS. The lisp code shown in the following is executed from ~/.emacs
, as usual.
Emacs comes with at least three different libraries to establish SSL/TLS connections (net/gnutls.el
, net/tls.el
, gnus/starttls.el
), and some libraries implement their own approach (e.g., net/imap.el
). Which approach is used when does not seem to be documented; in general, it depends on what software is installed on your machine. By default, various Emacs libraries will use net/gnutls.el
, which is vulnerable to MITM attacks. So I disable that library if it is available:
(if (fboundp 'gnutls-available-p) (fmakunbound 'gnutls-available-p))
Without net/gnutls.el
, lots of code falls back to net/tls.el
, which uses gnutls-cli
, but with the switch --insecure
. Clearly, that option is called “insecure” for a reason, and by replacing that option certificate pinning based on TOFU can be activated:
(setq tls-program '("gnutls-cli --strict-tofu -p %p %h")
(Recall from my previous post that you need a recent version of GnuTLS for this to work.)
In particular, the above change enables certificate pinning for news servers via NNTPS. E.g., I’m using the following for news.gmane.org
:
(setq gnus-select-method '(nntp "news.gmane.org" (nntp-open-connection-function nntp-open-tls-stream) (nntp-port-number 563) (nntp-address "news.gmane.org")))
(Recall from my previous post that you need to pin the server’s certificate first, e.g., via gnutls-cli --tofu -p 563 news.gmane.org
. The same holds for every server.)
I’m sending e-mails via mail/smtpmail.el
, which also defaults to net/gnutls.el
but falls back to gnus/starttls.el
. In my case, that library uses gnutls-cli
, and option --strict-tofu
can be added via a variable, starttls-extra-arguments
:
(setq starttls-extra-arguments '("--strict-tofu"))
I’m reading e-mails via net/imap.el
, which does not use net/gnutls.el
but its own approach based on Openssl’s s_client
. While s_client
is great to debug SSL/TLS connections, it is useless for everyday encryption as it prints an error message if certificates cannot be verified, but it opens the connection anyways. And, those errors are not shown in Emacs. So, switch to gnutls-cli
with certificate pinning:
(setq imap-ssl-program '("gnutls-cli --strict-tofu -p %p %s"))
To summarize, this is what I’m currently using in and recommending for Emacs:
(if (fboundp 'gnutls-available-p) (fmakunbound 'gnutls-available-p)) (setq tls-program '("gnutls-cli --strict-tofu -p %p %h") imap-ssl-program '("gnutls-cli --strict-tofu -p %p %s") smtpmail-stream-type 'starttls starttls-extra-arguments '("--strict-tofu") )