Husk

Documentation

Installation

Husk is written in Rust, so you need a recent rust toolchain to compile the source. If your distribution doesn't provide such a toolchain (or it is to old), you can get an up-to-date version from here.

To compile Husk from source, clone its repository and compile:

$ git clone https://gitlab.com/husk-project/husk-milter
$ cd husk-milter
$ cargo install --locked --path .

Configuration

The configuration file of Husk uses the toml format.

Husk is a milter (mail filter), which means it's a background process (daemon) which listens on a TCP port for incoming requests. This port is configured under the name connection.

connection = "localhost:3000"

This example tells Husk to listen on 127.0.0.1 (localhost), port 3000. There is a corresponding configuration for the MTA, so that the MTA knows where to find Husk (see below).

Husk uses OpenPGP certificates for encryption. It needs a storage location for these certificates. As Husk uses Sequoia PGP, the name for this parameter is sequoia_home.

sequoia_home = "/var/lib/husk/"

Husk queries online sources for missing certificates. For WKD and DANE the URL of the online source is derived from the email. Keyservers have to be configured separately.

keyservers = [ "hkps://keys.openpgp.org/", "hkps://mail-api.proton.me" ]

Husk uses log4rs for logging. The configuration of log4rs is merged into the main configuration file under the node named logging. That means that you take a log4rs configuration and prepend logging to each section:

[logging.appenders.console]
kind = "console"
[logging.appenders.console.encoder]
pattern = "{d(%Y-%m-%d %H:%M:%S)(local)} {h({l})} [{t}] {m}{n}"

[logging.appenders.file]
kind = "file"
path = "/tmp/husk.log"

[logging.appenders.file.encoder]
pattern = "{d(%Y-%m-%d %H:%M:%S)(local)} {h({l})} [{t}] {m}{n}"

[logging.root]
level = "debug"
appenders = ["file"]

[logging.loggers."husk"]
level = "debug"

so that [appenders.console] becomes [logging.appenders.console] and so on.

If you do not specify any logging, Husk will default to log to the console.

Location

You can put the configuration file at any place and start Husk with

$ husk ... --config <LOCATION> ...

or use the default location /etc/husk/config.toml. In this case you can skip --config.

Configure postfix

This is a description on how to add Husk to the postfix MTA. If you want to use Husk with a different MTA, please refer to its documentation on how to add a milter.

For postfix you have to tell the MTA where it can find the milter port. The configuration entries are smtpd_milters and non_smtpd_milters.

smtpd_milters = inet:localhost:3000
non_smtpd_milters = $smtpd_milters

inet:localhost:3000 corresponds to the connection configuration parameter in the Husk configuration.

The example above configures non_smtpd_milters by using the setting of smtpd_milters (via the $ operator).

Please keep in mind that in case you configured multiple milters, the sequence is important, as Husk will change the content of the mail.

Usage

Husk has two aspects:

  • it can run as a background process
  • it can be used as a cli-tool for administrating the background process.

The CLI syntax follows the scheme NOUN (more NOUNs), VERB and then parameters (if sensible). Like

$ husk introducer add --cert-file FILE --domains DOMAIN

or

$ husk daemon start --config config.toml

Husk includes a help system, which can be used by passing --help.

$ husk --help

or

$ husk introducer add --help

and so on. It shows you the available subcommands and parameters.

The daemon

The daemon is the background process which processes mails and encrypts them if possible. It has to be started separately, the MTA expects it to be reachable and doesn't start it on it's own.

Start the daemon

$ husk daemon start

or use

$ husk daemon start --config /path/to/the/configuration/file.toml

If you want to start the daemon as a background process add --background to the command:

$ husk daemon start --background

Husk can (and should) run as an unprivileged process (keep in mind to use a port number above 1024 as ports below require a privileged process).

Stop the daemon

Stopping means terminating the process. Please note that your MTA will start producing error messages if a registered milter disappears.

$ husk daemon stop 

Status of the daemon

$ husk daemon status

If the daemon is running, daemon status will also report the pid of the process.

Use systemd

TBD

Introducers

For Husk to use a certificate for encryption, it has to be authenticated - meaning the user id of the certificate (usually an email address) is indeed the user id of the key holder of said certificate.

This authentication can only be done by humans, but once it's done, its result can be shared.

This is what an introducer does - it authenticates certificates and publishes the result in form of a certification which becomes part of the certificate.

Husk allows to use introducers to benefit from their work. At the same time, introducers are limited to a list of domains for which certifications are accepted. This is a restriction Husk imposes. The list of domains is specified by the administrator, not the introducer.

Add an introducer

To add an introducer you need its certificate and specify which domains certifications done with this certificate should be accepted.

$ husk introducer add --cert-file FILE --domains example.com

You can specify a list of domains by

... ---domains domain1 domains2 domain3

FILE must contain a valid certificate, not expired and not revoked.

In case you already added the certificate to Husk, you can promote it by using its fingerprint.

$ husk introducer add --cert FINGERPRINT --domains example.com 

List introducers

$ husk introducer list 

Remove an introducer

$ husk introducer remove --cert FINGERPRINT

If you remove an introducer, the certificate will stay in the certificate store - only it's special powers will be removed. You can reactivate an introducer by using husk introducer add --cert FINGERPRINT ..., if you accidentally removed one.

Create an introducer

Introducers are maintained separately from Husk. The following is an example on how to create and use one using the command line tool sq from Sequoia PGP.

For the sake of this example we have two sides: Husk as consumer and CA as a producer. CA stands for certificate authority. CA is an ordinary OpenPGP key, what makes it a certificate authority is its usage.

In most cases, CA is not you, but the one who's work you want to use - see above.

Create a key:

$ sq key generate --own-key --userid 'My CA'

You can create a more complex key with more user ids and capabilities, but for a CA this is enough.

This CA can now be used to certify other keys (or more precise: certificates).

Let B0F698D7419862EAC6F435B0D5FC683922578868 be the fingerprint of a certificate.

$ sq pki vouch add --certifier-userid 'My CA' \
  --cert B0F698D7419862EAC6F435B0D5FC683922578868 \
  --all 

This example certifies all user ids of B0F698D7419862EAC6F435B0D5FC683922578868. You can be more selective by using --userid or --email instead of --all.

Now publish the certified key:

$ sq network keyserver publish --cert B0F698D7419862EAC6F435B0D5FC683922578868

Repeat the last two steps for all certificates you want to certify.

Now let Husk know and use your CA. First copy the certificate of CA to where Husk is running.

$ sq cert export --cert-userid 'My CA' > ca.pgp
$ scp ca.pgp $HUSK_SERVER

On the $HUSK_SERVER:

$ husk introducer add --cert-file ca.pgp --domains ...

Choose the list of domains you want to trust CA to introduce carefully. Lets assume the B0F698D7419862EAC6F435B0D5FC683922578868 is the certificate of alice@example.com and you thrust CA for that domain.

$ husk introducer add --cert-file ca.pgp --domains example.com

If now Husk encounters a mail addressed to alice@example.com (and her certificate isn't yet locally available), Husk will query online sources and check the results for a certification of CA (as CA is registered as an introducer for *@example.com).

If such a certification can be found, the right certificate is identified and Husk will use it for encryption (and stores it locally).

Locals

Locals are certificates which are added to Husk by the administrator and do not require to be introduced.

If you want to test Husk or want to use it only with a few dedicated certificates, you can skip creating an introducer and use locals.

Add Locals

$ husk locals add --cert-file FILE

FILE must contain a valid certificate, not expired and not revoked.

Locals can be promoted to introducers by using husk introducer add --cert FINGERPRINT ....

List locals

$ husk locals list

Remove locals

$ husk locals remove --cert FINGERPRINT

If you remove a local, its certificate will stay in the certificate store, but will be dormant.

Signing key

Husk can sign/encrypt mails instead of only encrypting them. For that, Husk needs the appropriate key.

Signing is done when a signing key is configured, without that key Husk will only encrypt a message.

Setting the signing key

If you already have a key, you can import it into the keystore of Husk by:

$ husk signkey set --cert-file FILE

FILE must contain an OpenPGP key (public and private key material) which is not expired or revoked and must be able to sign messages.

If there is already a key in the keystore which should be used as signing key:

$ husk signkey set --cert FINGERPRINT

If you are using a FINGERPRINT which has no corresponding key in the keystore, Husk will return an error and leaves the current key in place.

If there is already a signing key in place, signkey set will replace it.

The new key will be used instantly, a restart of the daemon is not necessary.

Create a signing key

You can tell Husk to create a signing key by:

$ hust signkey create

This will create a key which can only sign messages. With --userid you can specify a custom user id:

$ hust signkey create --userid "My special signing key"

Without --userid Husk will use Husk signing key as user id.

Displaying the fingerprint of the current signing key

$ husk signkey show

Exporting the certificate of a signing key

You might want to make the signing key public so that users receiving a signed/encrypted message from Husk can identify the signer.

$ husk signkey dump

will print the certificate (public key) to the console so that you can share it with the world.