Hello everyone,
As promised last week, here is a CVS snapshot of Exim containing
DomainKeys support:
http://duncanthrax.net/exim-experimental/
The snapshot carries a version number of 4.47. It represents the current
state of Exim CVS (includes exiscan-acl support) plus the DomainKeys code.
Please find the spec of the DK additions below. This is the first
release of that code, so you should treat it with some amount of
suspicion (run it under surveillance for a while ...).
DK support will NOT be in 4.50, but maybe in 4.51 or 4.52.
Experimental Exim DomainKeys Support
------------------------------------------------------------------------
Tom Kistner <tom@???>
http://duncanthrax.net/exim-experimental/
THIS IS PRELIMINARY DOCUMENTATION. IMPLEMENTATION DETAILS MAY CHANGE
WITHOUT WARNING IN FUTURE RELEASES.
DomainKeys (DK) support is built into Exim using the "libdomainkeys"
reference library implementation. It is available at
http://domainkeys.sf.net
You must build this library on your system and compile Exim against it.
To build Exim with DK support, add these lines to your Local/Makefile:
EXPERIMENTAL_DOMAINKEYS=yes
CFLAGS += -I/home/tom/exim-cvs/extra/libdomainkeys
LDFLAGS += -ldomainkeys -L/home/tom/exim-cvs/extra/libdomainkeys
Remember to tweak the CFLAGS and LDFLAGS lines to match the location of
the libdomainkeys includes and lib on your system.
The current experimental implementation supports two independent
functions:
o Validate incoming DK-signed email.
o Sign outgoing email with DK.
The former is implemented in the ACLs for SMTP, the latter as an
extension to the SMTP transport. That means both facilities are limited
to SMTP I/O.
Validate incoming DK-signed email
---------------------------------
Incoming messages are fed to the DK validation process as they are
received "on the wire". This happens synchronously to Exim's buffering
of the message in the spool. You must set "control = dk_verify" in
one of the ACLs preceding DATA (you will typically use acl_smtp_rcpt).
Example:
warn log_message = Feeding message to DK validator.
control = dk_verify
You can check for the outcome of the DK check in the ACL after data
(acl_smtp_data), using these expansion variables:
$dk_status This variable contains a lowercase string, describing
the outcome of the messages' DK validation. Typically,
it will contain the following strings:
o good Message signature verifies against
domainkey published in DNS. We have a
winner!
o bad Message signature does not verify
against domainkey published in DNS.
o no_signature The message does not carry a DK
signature.
o no_key The message had a signature, but the DNS
of the sending domain does not carry a
public key.
o revoked_key The key used to sign this message has
been revoked by the sending domain.
In addition, these following strings are also possible.
They describe error conditions.
o cannot_verify Both signature and key are available,
but verification processing failed (e.g.
signature was created using an
unsupported hashing algorithm).
o bad_key The domainkey published in DNS has a
format error.
o bad_syntax The domainkey record published in DNS
has a syntax error.
Finally, the following describe internal errors in the
local DK processing:
o error Internal disaster.
o no_resources Out of memory. This will be the least of
your problems.
o bad_argument Yours truly has screwed up. Please
report a bug.
If $dk_status is empty, the message has not been
processed by the DK engine.
$dk_signs_all This variable is "1" when the sending domain signs all
outgoing email, "0" otherwise.
$dk_is_testing This variable is "1" when the sending domain is
currently testing DomainKeys, "0" otherwise.
Using these variables, you COULD reject mail in the DATA ACL:
deny message = This message is unsigned. "$sender_address_domain" \
policy is to sign all outgoing email. Go away.
!condition = ${if eq{$dk_status}{}{1}{0}}
!condition = $dk_is_testing
condition = $dk_signs_all
condition = ${if eq{$dk_status}{no_signature}{1}{0}}
deny message = DomainKeys signature did not verify.
!condition = ${if eq{$dk_status}{}{1}{0}}
!condition = $dk_is_testing
condition = $dk_signs_all
condition = ${if eq{$dk_status}{bad}{1}{0}}
The author does NOT RECOMMEND to use this code snippet. Consider it to
be for educational purposes. DK interoperability is not very good at the
moment and signatures may not evaluate to "good" for bona fide email.
What is recommended, however, is to add a DomainKey-Status: header that
informs end users about the result:
warn message = DomainKey-Status: $dk_status
!condition = ${if eq{$dk_status}{}{1}{0}}
Sign outgoing email with DK
---------------------------
Outgoing messages are signed just before exim puts them "on the wire".
The only thing that happens after DK signing is eventual TLS encryption.
Signing is implemented by setting private options on the SMTP transport.
This simple example shows all the options (not all of them are needed,
check the explanations below):
dk_smtp:
driver = smtp
dk_private_key = /etc/exim/dk/foobar
dk_selector = foobar
dk_domain = duncanthrax.net
dk_canon = nofws
dk_private_key (MANTADORY)
--------------------------
This option MUST be present, otherwise the message will not be signed.
Its value is expanded before being used, and must result in:
o the absolute filename (including path starting with a slash) of
the private key, in which case the message will be signed using
this key.
o "0" or the empty string, in which case the message will not be
signed.
dk_selector (OPTIONAL, BUT RECOMMENDED - PLEASE READ)
-----------------------------------------------------
This option sets the key selector string. DK supports having multiple
keys in your DNS zone in order to be able to switch keys. Each key has
a "name", which is the selector. This option defaults to the filename
part of the dk_private_key setting (starting after the last slash), so
if your private key filenames are the same as your selector strings,
you can omit this option. Otherwise, you MUST set this option.
dk_domain (OPTIONAL)
--------------------
This option can override the domain (d=) field of the
DomainKey-Signature header. You should normally not set this option
since the domain will be automatically selected by fishing it out of
the address headers.
dk_canon (OPTIONAL)
-------------------
This option sets the canonicalization method used when signing a
message. The DK draft currently supports two methods: "simple" and
"nofws". The option defaults to "simple" when unset.
TODO
----
The implementation is currently "work-in-progress". The author plans the
following additions:
o Have a "dk_status" ACL condition instead of just an expansion
variable.
o Support the "h=" parameter (include only selected headers when
signing).
o Write $dk_status to the spool file, so it is available in routers and
transports later.