Mail: Create DKIM Keys and DNS RRs Using Shell


The Internet seems to be overflown with articles that explain how to create DKIM keys and DNS records using a multitude of provider-specific tools. People that maintain their name servers and mail servers themselves are left in the lurch: while one would expect DKIMproxy and OpenDKIM to provide a suitable tool, that is not the case—to the utter disappointment of many.

On this page you can find a very simple, portable script that generates a secret DKIM key and outputs a corresponding DNS resource record that publishes the public part of that key. The script is signed with my PGP key.

Gmail and Office 365 accept the output of this script, dkimproxy_in likes it too: it should not let you down.

The generated DNS RR sets v, k, and p DKIM properties. You can edit the output of the script if you require anything beyond that.

The script generates either a 1024-bit or 2048-bit RSA key. The script follows the common practice of using a timestamp as the name of a DKIM selector; the timestamp is generated using the current system time in the format %Y%m%d%H%M%S as prescribed by strftime(3). The script saves the key in a directory specified by the user in a file named dkim-key-selector name. File ownership and the file mode are set as specified by the user. The script generates either a single-line DNS RR in the case of a 1024-bit key or a multi-line DNS RR for 2048-bit key.

The script gently holds the user by the hand to prevent snatching of a private key by an unauthorised party: the script requires superuser privileges because it first saves a new key in a file that is accessible only to the superuser for reading and then sets file ownership and the file mode. The script duly validates its command-line arguments, it refuses to overwrite existing files or to create writable or executable files. The source code of the script is commented very carefully, you are welcome to study its operation to ensure that it does exactly what you expect (without comments, there are about 150 lines of very straightforward UNIX shell, it will not take much of your time).

For the impatient, the following is the output of the script's usage function:

Usage: dkim-key.sh ttl bits user group mode directory

This script generates
  a) A DKIM key using the current date in the format YYYYMMDDHHSS
     as the selector;
  b) A DNS record that corresponds to (a).

  ttl is the time-to-live (TTL) of the generated DNS record.
  bits the length of the private key; it is either 1024 or 2048.
  user is the name or the ID of the user that owns the private key.
  group is the name or the ID of the user that owns the private key.
  mode is the file mode of the private key.
  directory is the directory where the private key file is stored.

The private key is saved in the directory in a file named using the
result of concatenation of the prefix ‘dkim-key-’ and the generated
selector.

The DNS record is printed to the standard output. Note: the record
assumes that $ORIGIN is defined (see RFC 1035), i.e. the record is relative.
The following is a sample output of a 2048-bit key:
;;; dkim-key.sh: The private key is saved in /tmp/dkim-key-20190613010745
20190613010745._domainkey 300 IN TXT ("v=DKIM1; k=rsa; p="
        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5elx0nlMCz2z0vJ5m4ZQ"
        "NNDyIv1gtlWo9bfK9RmMjeYAtKgfwubqwcrB8mPOuThQRE5ecnA8Yj9y6YaRo+uK"
        "2iKpG0FPJPkyfE6aE338m9HhNQ8nhSEOimrRCFjPKI6Lxnqwsw+RQfTeg93neU4/"
        "UrcAaJ/L6Owjp9swtRc2trDe05njmJyoHlf9vBA+05rFrOivsEJuHoP1O1pkOmKL"
        "EPsCmlXP/papnCG5SW0FEYSK+Qfckn5wfYzSUerSSJnurpAuVcVNDz68FosV85J4"
        "N4r4FMIKlVfHLbWtoRpcOdCQtHiaBzPJNDNMBXnGm5rtRqPNMmgMBuJKWaCU4l9N"
        "VwIDAQAB")

The script has the followind dependencies: doas(1) on OpenBSD or sudo(1) elsewhere, cat(1), basename(1), openssl(1), tr(1), id(1), null(4), group(5), date(1), mktemp(1), chown(1), chmod(1), grep(1), sed(1), and rm(1).

Vadim Penzin, June 12th, 2019


I hereby place this article along with the accompanying source code into the public domain.
I publish this information in the hope that it will be useful, but without ANY WARRANTY.
You are responsible for any and all consequences that may arise as the result of using this information.