For a while now I’ve been interested in using client certificates for authentication of e-mail clients using IMAP and SMTP, while still permitting password authentication. This week I finally decided to actually figure out how I could get this to work. Because it took me quite some effort to discover how to do this but couldn’t find anyone else documenting the same I thought it might help other people to describe my setup.

I’m using Postfix 2.11.3 for SMTP and a patched Dovecot 2.2.27 for IMAP. I had to patch Dovecot because the required functionality only gets introduced with 2.2.28 in cdf00f5:

auth: Support filtering by SASL mechanism: passdb { mechanisms }

So if you want to get the same functionality either use Dovecot 2.2.28 or higher or backport the mentioned commit like I did.

Certificate Authority

To manage my CA I’m using the easy-rsa utility. For brevity I’m not documenting how to use that, except to mention how I’m exporting the combined CA+CRL file which is what I’m using in the rest of this article. Producing that file is done as follows:

$ cd easy-rsa/easyrsa3
$ ./easyrsa gen-crl
$ cat pki/ca.crt pki/crl.pem > pki/ca+crl.pem

SMTP server Postfix

First lets add certificate authentication to Postfix as it’s the easiest. We’re assuming that any valid certificate, signed by our CA, is authorized to use this server for relaying mail. If you actually want more complicated authentication than that I don’t think Postfix can currently help you.

In /etc/postfix/ configure TLS to be required and ask for a client certificate on the submission port. You don’t want to do this globally, in, because some servers, wishing to deliver mail to you, might not deal well with being asked for a client certificate.

submission inet n       -       -       -       -       smtpd
  # mandatory encryption. 'may', opportunistic encryption, works too, but you
  # probably don't want that
  -o smtpd_tls_security_level=encrypt

  # enable regular SASL authentication (with passwords, assuming you currently
  # have this and want to retain it)
  -o smtpd_sasl_auth_enable=yes

  # ask for a client certificate: gives the client the opportunity to provide
  # one, not the obligation to do so
  -o smtpd_tls_ask_ccert=yes

Then in /etc/postfix/ configure certificate verification and give permission for relay access:

smtpd_tls_CAfile = /etc/easy-rsa/easyrsa3/pki/ca+crl.pem
# necessary to prevent any random, public, CA from giving relay access to your server
tls_append_default_CA = no

# add to either smtpd_recipient_restrictions or smtpd_relay_restrictions
# depending on which of those you use to control authenticated relay access
smtpd_relay_restrictions =

IMAP server Dovecot

For setting up Dovecot I’ll assume you already have it running with TLS enabled. I’m only describing the additional configuration options that are needed. In /etc/dovecot/conf.d/10-ssl.conf add:

# Our CA that we use to sign the client certificates
ssl_ca = </etc/easy-rsa/easyrsa3/pki/ca+crl.pem

# only permit non-revoked certificates
ssl_require_crl = yes

# ask for client certificates (but don't require them)
ssl_verify_client_cert = yes

# I'm using a full mail address as username and storing it in the emailAddres
# field of the certificate
ssl_cert_username_field = emailAddres

In /etc/dovecot/conf.d/10-auth.conf add EXTERNAL as an authentication mechanism:

# Use the username taken from the client certificate
auth_ssl_username_from_cert = yes

# Add 'external' to auth_mechanisms. That will use the username extracted from
# the certificate combined with the empty string as password to authenticate.
# This is my list of enabled mechanisms
auth_mechanisms = plain login external

Now comes the “trick” to making the combination of password and certificate authentication work. Because Dovecot’s EXTERNAL authentication mechanism attempts to authenticate with the empty string as password, we need to have a password database that permits that. At the same time though, we want to prevent regular logins, with password, to succeed when specifying the empty string as password. This requires the filtering of password databases by SASL mechanism added to Dovecot 2.2.28 that I mentioned earlier. I’m adding a passwd-file password database containing only the usernames, without passwords, as /etc/dovecot/users-external:

Subsequently I’m adding an EXTERNAL-specific password database to /etc/dovecot/conf.d/auth-passwdfile.conf.ext. Make sure to also include it, near the bottom of /etc/dovecot/10-auth.conf.

passdb {
  driver = passwd-file
  # the PLAIN scheme prevents us from having to hash the empty string
  args = scheme=PLAIN username_format=%u /etc/dovecot/users-external

  # this option requires Dovecot 2.2.28 (or the patch), without it this setup
  # is insecure because it permits logins with the empty string as password
  mechanisms = external

  # explicitly permit empty passwords
  override_fields = nopassword

You can test this on a terminal with the openssl s_client:

$ openssl s_client -CAfile /etc/ssl/certs/ca-certificates.crt -verify 4 \
>   -cert ${PATH_TO_CLIENT_CERT} \
>   -tls1 -starttls imap -connect
<lots of text scrolling by>
. OK Pre-login capabilities listed, post-login capabilities have more.
* CAPABILITY IMAP4rev1 ......
A001 OK Logged in

Thunderbird as Client

When using Thunderbird as a client you can specify the “TLS certificate” “authentication method” in the “security settings” portion of the “server settings” for your account settings. Unfortunately you cannot choose this during the account setup wizard. So during the wizard you’ll still need to use password authentication. For SMTP you can just use “no authentication” as the “authentication method” (it’s a misleading name).


There are no comments yet.

Add a comment via email

Comment Atom Feed