General-Purpose Mail Filter
DKIM or DomainKeys Identified Mail is an email authentication method that allows recipients to verify if an email was authorized by the owner of the domain that email claims to originate from. It does so by adding a digital signature which is verified using a public key published as a DNS TXT record. For technical details about DKIM, please refer to RFC 6376 (http://tools.ietf.org/html/rfc6376).
MFL provides functions for DKIM signing and verification.
Verifies the message msg (a message descriptor, obtained from
a call to
message_from_stream or a similar function).
Return value (constants defined in the ‘status’ module):
The message contains one or more ‘DKIM-Signature’ headers and one of them verified successfully.
The message contains one or more ‘DKIM-Signature’ headers, all of which failed to verify.
The message was not signed using DKIM, or the DNS query to obtain the public key failed, or an internal software error occured during verification.
The following two global variables are always set upon return from this function: ‘dkim_explanation’ and ‘dkim_explanation_code’. These can be used to clarify the verification result to the end user.
Upon successful return, the variable ‘dkim_verified_signature’ is set to the value of the successfully verified DKIM signature.
An explanatory message clarifying the verification result.
A numeric code corresponding to the ‘dkim_explanation’ string. Its possible values are defined in ‘status.mf’:
DKIM verification passed.
No DKIM signature.
Signature syntax error
Signature is missing required tag
Domain part of the
i= tag does not match and is not a subdomain
of the domain listed in the
Incompatible DKIM version listed in the
Unsupported query method.
From field not signed.
Public key unavailable.
Public key not found.
Key syntax error.
Body hash did not verify.
Can’t decode the content of the
Signature did not verify.
Upon successful return from the
dkim_verify function, this
variable holds the value of the successfully verified DKIM header.
This value is unfolded and all whitespace is removed from it.
An example of using the ‘dkim_verify’ function:
require status require dkim prog eom do strint result switch dkim_verify(current_message()) do case DKIM_VERIFY_OK: set result "pass; verified for " . dkim_verified_signature_tag('i') case DKIM_VERIFY_PERMFAIL: set result "fail (%dkim_explanation)" case DKIM_VERIFY_TEMPFAIL: set result "neutral" done header_add("X-Verification-Result", "dkim=%result") done
The ‘dkim’ module defines convenience functions for manipulating with DKIM signatures:
Extracts the value of the tag tag from the DKIM signature sig. Signature must be normalized by performing the header unwrapping and removing whitespace characters.
If the tag was not found, returns empty string, unless tag is one of the tags listed in the table below. If any of these tags are absent, the following values are returned instead:
|i||‘@’ + the value of the ‘d’ tag.|
Returns the value of tag tag from the ‘dkim_verified_signature’ variable.
This function is available only in the
Signs the current message. Notice, that no other modification should be attempted on the message after calling this function. Doing so wold make the signature invalid.
Name of the domain claiming responsibility for an introduction of a message into the mail stream. It is also known as the signing domain identifier (SDID).
The selector name. This value, along with d identifies the location of the DKIM public key necessary for verifying the message. The public key is stored in the DNS TXT record for
Name of the disk file that keeps the private key for signing the message. The file must be in PEM format.
Canonicalization algorithm for message headers. Valid values are: ‘simple’ and ‘relaxed’. ‘simple’ is the default.
Canonicalization algorithm for message body. Valid and default values are the same as for ch.
A colon-separated list of header field names that identify the header fields that must be signed. Optional whitespace is allowed at either side of each colon separator. Header names are case-insensitive. This list must contain at least the ‘From’ header.
It may contain names of headers that are not present in the message being signed. This provides a way to explicitly assert the absence of a header field. For example, if headers contained ‘X-Mailer’ and that header is not present in the message being signed, but is added by a third party later, the signature verification will fail.
Similarly, listing a header field name once more than the actual number of its occurrences in a message allows you to prevent any further additions. For example, if there is a single ‘Comments’ header field at the time of signing, putting ‘Comments:Comments:’ in the headers parameter is sufficient to prevent any surplus ‘Comments’ headers from being added later on.
Multiple instances of the same header name are allowed. They mean that multiple occurrences of the corresponding header field will be included in the header hash. When such multiple header occurrences are referenced, they will be presented to the hashing algorithm in the reverse order. E.g. if the header list contained ‘Received:Received’) and the current message contained three ‘Received’ headers:
Received: A Received: B Received: C
then these headers will be signed in the following order:
Received: C Received: B
The default value for this parameter, split over multiple lines for readability, is as follows:
An example of using this function:
precious domain "example.org" precious selector "s2048" prog eom do dkim_sign("example.org", "s2048", "/etc/pem/my-private.pem", "relaxed", "relaxed", "from:to:subject") done
(see Header modification functions) as well as the
action (see header manipulation) cannot interact properly with
dkim_sign due to the shortcomings of the Milter API. If any of
these was called,
dkim_sign will throw the
exception with the diagnostics following diagnostics:
MMQ incompatible with dkim_sign: op on h, value v
where op is the operation code (‘ADD HEADER’ or ‘INSERT HEADER’), h is the header name and v is its value.
The following example shows one graceful way of handling such exception:
prog eom do try do dkim_sign("example.org", "s2048", "/etc/pem/my-private.pem") done catch e_badmmq do # Purge the message modification queue mmq_purge() # and retry dkim_sign("example.org", "s2048", "/etc/pem/my-private.pem") done done
See Message modification queue, for a discussion of the message modification queue.
This document was generated on July 26, 2020 using makeinfo.Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.