Introduction
Introduction Statistics Contact Development Disclaimer Help
Title: Emails encryption at rest on OpenBSD using dovecot and GPG
Author: Solène
Date: 14 August 2024
Tags: security privacy emails openbsd
Description: In this blog post, you will learn how to configure your
email server to automatically encrypt incoming emails using GPG.
# Introduction
In this blog post, you will learn how to configure your email server to
encrypt all incoming emails using user's GPG public keys (when it
exists). This will prevent anyone from reading the emails, except if
you own the according GPG private key. This is known as "encryption at
rest".
This setup, while effective, has limitations. Headers will not be
encrypted, search in emails will break as the content is encrypted, and
you obviously need to have the GPG private key available when you want
to read your emails (if you read emails on your smartphone, you need to
decide if you really want your GPG private key there).
Encryption is CPU consuming (and memory too for emails of a
considerable size), I tried it on an openbsd.amsterdam virtual machine,
and it was working fine until someone sent me emails with 20MB
attachments. On a bare-metal server, there is absolutely no issue.
Maybe GPG makes use of hardware acceleration cryptography, and it is
not available in virtual machines hosted under the OpenBSD hypervisor
vmm.
This is not an original idea, Etienne Perot wrote about a similar setup
in 2012 and enhanced the `gpgit` script we will use in the setup.
While his blog post is obsolete by now because of all the changes that
happened in Dovecot, the core idea remains the same. Thank you very
much Etienne for your job!
Etienne Perot: Encrypt specific incoming emails using Dovecot and Sieve
gpgit GitHub project page
gpgit mirror on tildegit.org
This guide is an extension of my recent email server setup guide:
2024-07-24 Full-featured email server running OpenBSD
# Threat model
This setup is useful to protect your emails stored on the IMAP server.
If the server or your IMAP account are compromised, the content of your
emails will be encrypted and unusable.
You must be aware that emails headers are not encrypted: recipients /
senders / date / subject will remain in clear text even after
encryption. If you already use end-to-end encryption with your
recipients, there are no benefits using this setup.
An alternative is to not let any emails on the IMAP server, although
they could be recovered as they are written in the disk until you
retrieve them.
Personally, I keep many emails of my server, and I am afraid that a
0day vulnerability could be exploited on my email server, allowing an
attacker to retrieve the content of all my emails. OpenSMTPD had
critical vulnerabilities a few years ago, including a remote code
execution, so it is a realistic threat.
I wrote a privacy guide (for a client) explaining all the information
shared through emails, with possible mitigations and their limitations.
IVPN: The Technical Realities of Email Privacy
# Setup
This setup makes use of the program `gpgit` which is a Perl script
encrypt emails received over the standard input using GPG, it is a
complicated task because the email structure can be very complicated.
I have not been able to find any alternative to this script. In gpgit
repository there is a script to encrypt an existing mailbox (maildir
format), that script must be run on the server, I did not test it yet.
You will configure a specific sieve rule which is "global" (not
user-defined) that will process all emails before any other sieve
filter. This sieve script will trigger a `filter` (a program allowed
to modify the email) and pass the email on the standard input of the
shell script `encrypt.sh`, which in turn will run `gpgit` with the
according username after verifying a gnupg directory existed for them.
If there is no gnupg directory, the email is not encrypted, this allows
multiple users on the email server without enforcing encryption for
everyone.
If a user has multiple addresses, this is the system account name that
is used in the local part of the GPG key address.
## GPGit
Some packages are required for gpgit to work, they are all available on
OpenBSD:
```shell
pkg_add p5-Mail-GnuPG p5-List-MoreUtils
```
Download gpgit git repository and copy its `gpgpit` script into
`/usr/local/bin/` as an executable:
```
cd /tmp/
git clone https://github.com/EtiennePerot/gpgit
cd gpgit
install -o root -g wheel -m 555 gpgit /usr/local/bin/
```
## Sieve
All the following paths will be relative to the directory
`/usr/local/lib/dovecot/sieve/`, you can `cd` into it now.
Create the file `encrypt.sh` with this content, replace the variable
`DOMAIN` with the domain configured in the GPG key:
```sh
#!/bin/sh
DOMAIN="puffy.cafe"
NOW=$(date +%s)
DATA="$(cat)"
if test -d ~/.gnupg
then
echo "$DATA" | /usr/local/bin/gpgit "${USER}@${DOMAIN}"
NOW2=$(date +%s)
echo "Email encryption for user ${USER}: $(( NOW2 - NOW )) seconds" | logge…
else
echo "$DATA"
echo "Email encryption for user for ${USER} none" | logger -p mail.info
fi
```
Make the script executable with `chmod +x encrypt.sh`. This script
will create a new log line in your email logs every time an email is
processed, including the username and the time required for encryption
(in case of encryption). You could extend the script to discard the
`Subject` header from the email if you want to hide it, I do not
provide the implementation as I expect this task to be trickier than it
looks like if you want to handle all corner cases.
Create the file `global.sieve` with the content:
```sieve
require ["vnd.dovecot.filter"];
filter "encrypt.sh";
```
Compile the sieve rules with `sievec global.sieve`.
## Dovecot
Edit the file `/etc/dovecot/conf.d/90-plugin.conf` to add the following
code within the `plugin` block:
```
sieve_filter_bin_dir = /usr/local/lib/dovecot/sieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment +vnd.dov…
sieve_before = /usr/local/lib/dovecot/sieve/global.sieve
sieve_filter_exec_timeout = 200s
```
You may have `sieve_global_extensions` already set, in that case update
its value.
The variable `sieve_filter_exec_timeout` allows the script `encrypt.sh`
to run for 200 seconds before being stopped, you should adapt the value
to your system. I came up with 200 seconds to be able to encrypt email
with 20MB attachments on an openbsd.amsterdam virtual machine. On a
bare metal server with a Ryzen 5 CPU, it takes less than one second for
the same email.
The full file should look like the following (in case you followed my
previous email guide):
```
##
## Plugin settings
##
# All wanted plugins must be listed in mail_plugins setting before any of the
# settings take effect. See <doc/wiki/Plugins.txt> for list of plugins and
# their configuration. Note that %variable expansion is done for all values.
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
# From elsewhere to Spam folder
imapsieve_mailbox1_name = Spam
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/usr/local/lib/dovecot/sieve/report-spam.siev
# From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Spam
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/usr/local/lib/dovecot/sieve/report-ham.sieve
sieve_pipe_bin_dir = /usr/local/lib/dovecot/sieve
# for GPG encryption
sieve_filter_bin_dir = /usr/local/lib/dovecot/sieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment +vnd.dov…
sieve_before = /usr/local/lib/dovecot/sieve/global.sieve
sieve_filter_exec_timeout = 200s
}
```
Open the file `/etc/dovecot/conf.d/10-master.conf` and uncomment the
variable `default_vsz_limit` and set its value to `1024M`. This is
required as GPG uses a lot of memory and without this, the process will
be killed and the email lost. I found 1024M to works with attachments
up to 45 MB, however you should raise this value higher value if you
plan to receive bigger attachments.
Restart dovecot to take account of the changes: `rcctl restart
dovecot`.
## User GPG setup
You need to create a GPG keyring for each users you want use
encryption, the simplest method is to setup a passwordless keyring and
import your public key:
```
$ gpg --quick-generate-key --passphrase '' --batch "$USER"
$ gpg --import public-key-file.asc
$ gpg --edit-key FINGERPRINT_HERE
gpg> sign
[....]
gpg> save
```
If you want to disable GPG encryption for the user, remove the
directory `~/.gnupg`.
## Anti-spam service
If you use a spam filter such as rspamd or spamassassin relying on
bayes filter, it will only work if it process the emails before
arriving at dovecot, for instance in my email setup this is the case as
rspamd is a filter of opensmtpd and pass the email before being
delivered to Dovecot.
Such service can have privacy issues, especially if you use encryption.
Bayes filter works by splitting an email content into tokens (not
really words but almost) and looking for patterns using these tokens,
basically each emails is split and stored in the anti-spam local
database in small parts. I am not sure one could recreate the emails
based on tokens, but if someone like an attacker is able to access the
token list, they may have some insights about your email content. If
this is part of your threat model, disable your anti-spam Bayes filter.
# Conclusion
This setup is quite helpful if you want to protect all your emails on
their storage. Full disk encryption on the server does not prevent
anyone able to connect over SSH (as root or the email user) from
reading the emails, even file recovery is possible when the volume is
unlocked (not on the real disk, but the software encrypted volume),
this is where encryption at rest is beneficial.
I know from experience it is complicated to use end-to-end encryption
with tech-savvy users, and that it is even unthinkable with regular
users. This is a first step if you need this kind of security (see the
threat model section), but you need to remember a copy of all your
emails certainly exist on the servers used by the persons you exchange
emails with.
You are viewing proxied material from dataswamp.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.