Dovecot Certificate Authentication

dovecotimapssl-certificate

After implementing certificate authentication on Nginx web server, I would like to do the same on Dovecot mail server. The idea is to create your own CA and manage certificates (both issuing and revoking). To verify the client certificate you need your root CA certificate and the CRL. In order to establish a secure connection, a certificate signed by a true CA can be used (if you don't want to import your own root CA certificate on every workstation).

So far, I have read these pages from the Dovecot official wiki:

  1. http://wiki2.dovecot.org/SSL
  2. http://wiki2.dovecot.org/SSL/DovecotConfiguration

Which have got me to this configuration file:

listen = *,[::]
protocols = imap pop3
auth_mechanisms = plain login
disable_plaintext_auth = no
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_privileged_group = vmail
ssl = required
ssl_cert = </etc/postfix/smtpd.cert
ssl_key = </etc/postfix/smtpd.key
ssl_ca = </etc/postfix/ca.pem
ssl_cert_username_field = emailAddress
ssl_verify_client_cert = yes
ssl_require_crl = yes
auth_ssl_require_client_cert = yes
ssl_username_from_cert = yes
passdb {
  args = /etc/dovecot/dovecot-sql.conf
  driver = sql
}
userdb {
  args = /etc/dovecot/dovecot-sql.conf
  driver = sql
}
plugin {
  quota = dict:user::file:/var/vmail/%d/%n/.quotausage
  sieve=/var/vmail/%d/%n/.sieve
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  unix_listener auth-userdb {
    group = vmail
    mode = 0600
    user = vmail
  }
  user = root
}
service imap-login {
  client_limit = 1000
  process_limit = 500
}
protocol imap {
  mail_plugins = quota imap_quota
}
protocol pop3 {
  pop3_uidl_format = %08Xu%08Xv
  mail_plugins = quota
}
protocol lda {
  mail_plugins = sieve quota
}

The ca.pem, which is used to validate client certificates, is formatted according to the second link above and contains the root CA certificate and the CRL, both in PEM format. Also the certificate and key pair used to establish the secure connection are in PEM format (even though the extensions are .cert and .key).

The settings mentioned in the second link above: ssl_username_from_cert = yes (which is used in combination with ssl_cert_username_field (which defaults to commonName) yields an error:

doveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf line 15: Unknown setting: ssl_username_from_cert
[....] Restarting IMAP/POP3 mail server: dovecotdoveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf line 15: Unknown setting: ssl_username_from_cert
failed!

Commenting out that option and restarting Dovecot, I get no configuration errors, but it's not working.
A shell test results in:

openssl s_client -connect mail.example.com:imaps
CONNECTED(00000003)

That's all.

If I comment out all the lines referring to the certificate authentication (all the line beginning with ssl, except ssl, ssl_cert and ssl_key pair, those are used to allow only secured SSL/TLS connections), it works, but I get not certificate authentication.

Searches on Google result in implementing secured SSL/TLS connections (which I have done so far).
This guide, which explains exactly what I want to do, isn't finished. Right at the Dovecot configuration file, it has a ToDo list.

I'm running version 2.1.7 of Dovecot on an Linux Debian 7 (Wheezy) – currently the Debian stable version.

Any help is appreciated.

Note: I want to implement this only for the IMAP protocol.

EDIT 1:

If you notice something wrong (bad practice, insecure), please leave a comment!

After changing ssl_username_from_cert with auth_ssl_username_from_cert and restarting Dovecot, everything seems to work well.

openssl s_client -connect mail.example.com:imaps
CONNECTED(00000003)
depth=0 description = XXXXXXXXXXXXXXXX, C = XX, CN = mail.example.com, emailAddress = postmaster@example.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 description = XXXXXXXXXXXXXXXX, C = XX, CN = mail.example.com, emailAddress = postmaster@example.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 description = XXXXXXXXXXXXXXXX, C = XX, CN = mail.example.com, emailAddress = postmaster@example.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/description=XXXXXXXXXXXXXXXX/C=XX/CN=mail.example.com/emailAddress=postmaster@example.com
   i:/C=XX/O=Company Ltd./OU=Some High Security Name/CN=Certificate Class
---
Server certificate
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX
-----END CERTIFICATE-----
subject=/description=XXXXXXXXXXXXXXXX/C=XX/CN=mail.example.com/emailAddress=postmaster@example.com
issuer=/C=XX/O=Company Ltd./OU=Some High Security Name/CN=Certificate Class
---
Acceptable client certificate CA names
/C=XX/ST=Some-State/O=Another Company Ltd.
---
SSL handshake has read 3107 bytes and written 519 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: zlib compression
Expansion: zlib compression
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : DHE-RSA-AES256-GCM-SHA384
    Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Session-ID-ctx: 
    Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0010 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0020 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0030 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0040 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0050 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0060 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0070 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0080 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX
    0090 - XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX   XXXXXXXXXXXXXXXX

    Compression: 1 (zlib compression)
    Start Time: 1409206799
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot ready.

and

doveconf -a | grep ssl
auth_ssl_require_client_cert = yes
auth_ssl_username_from_cert = yes
imapc_ssl = no
imapc_ssl_ca_dir = 
imapc_ssl_verify = yes
pop3c_ssl = no
pop3c_ssl_ca_dir = 
pop3c_ssl_verify = yes
    ssl = no
    ssl = yes
    ssl = no
    ssl = yes
service ssl-params {
  executable = ssl-params
  unix_listener login/ssl-params {
ssl = required
ssl_ca = </etc/postfix/ca.pem
ssl_cert = </etc/postfix/smtpd.cert
ssl_cert_username_field = emailAddress
ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
ssl_client_cert = 
ssl_client_key = 
ssl_crypto_device = 
ssl_key = </etc/postfix/smtpd.key
ssl_key_password = 
ssl_parameters_regenerate = 1 weeks
ssl_protocols = !SSLv2
ssl_require_crl = yes
ssl_verify_client_cert = yes
verbose_ssl = no

Time to try it out. I imported a user certificate into Thunderbird and set Authentication method: TLS Certificate. But when I try to connect, I get the following error message:

The IMAP Server user@example.com does not support the selected authentication method. Please change the 'Authentication method' in the 'Account Settings | Server Settings'.

Note: The password authentication works (of course over TLS secured connection).

We're close.

Best Answer

The Dovecot wiki seems to have an error, or maybe the name of the ssl_username_from_cert setting has changed. On my Ubuntu host with Dovecot 2.2.9, in /etc/dovecot/conf.d/10-auth.conf, I have:

# Take the username from client's SSL certificate, using 
# X509_NAME_get_text_by_NID() which returns the subject's DN's
# CommonName. 
#auth_ssl_username_from_cert = no

So it seems that you need to replace ssl_username_from_cert by auth_ssl_username_from_cert, and the wiki needs to be corrected.

Related Topic