URI: 
       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!
       
  HTML Etienne Perot: Encrypt specific incoming emails using Dovecot and Sieve
  HTML gpgit GitHub project page
  HTML gpgit mirror on tildegit.org
       
       This guide is an extension of my recent email server setup guide:
       
  HTML 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.
       
  HTML 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" | logger -p mail.info
       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.dovecot.filter
         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.dovecot.filter
         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.