Mailfromd Manual (split by section):   Section:   Chapter:FastBack: Library   Up: Library   FastForward: Using MFL Mode   Contents: Table of ContentsIndex: Concept Index

5.34 DKIM

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.

Built-in Function: number dkim_verify (number msg)

Verifies the message msg (a message descriptor, obtained from a call to current_message, mailbox_get_message, message_from_stream or a similar function).

Return value (constants defined in the ‘status’ module):

DKIM_VERIFY_OK

The message contains one or more ‘DKIM-Signature’ headers and one of them verified successfully.

DKIM_VERIFY_PERMFAIL

The message contains one or more ‘DKIM-Signature’ headers, all of which failed to verify.

DKIM_VERIFY_TEMPFAIL

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.

Built-in variable: string dkim_explanation

An explanatory message clarifying the verification result.

Built-in variable: number dkim_explanation_code

A numeric code corresponding to the ‘dkim_explanation’ string. Its possible values are defined in ‘status.mf’:

DKIM_EXPL_OK

DKIM verification passed.

DKIM_EXPL_NO_SIG

No DKIM signature.

DKIM_EXPL_INTERNAL_ERROR

Internal error

DKIM_EXPL_SIG_SYNTAX

Signature syntax error

DKIM_EXPL_SIG_MISS

Signature is missing required tag

DKIM_EXPL_DOMAIN_MISMATCH

Domain part of the i= tag does not match and is not a subdomain of the domain listed in the d= tag.

DKIM_EXPL_BAD_VERSION

Incompatible DKIM version listed in the v= tag.

DKIM_EXPL_BAD_ALGORITHM

Unsupported algorithm.

DKIM_EXPL_BAD_QUERY

Unsupported query method.

DKIM_EXPL_FROM

From field not signed.

DKIM_EXPL_EXPIRED

Ssignature expired.

DKIM_EXPL_DNS_UNAVAIL

Public key unavailable.

DKIM_EXPL_DNS_NOTFOUND

Public key not found.

DKIM_EXPL_KEY_SYNTAX

Key syntax error.

DKIM_EXPL_KEY_REVOKED

Key revoked.

DKIM_EXPL_BAD_BODY

Body hash did not verify.

DKIM_EXPL_BAD_BASE64

Can’t decode the content of the b= tag.

DKIM_EXPL_BAD_SIG

Signature did not verify.

Built-in variable: string dkim_verified_signature

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:

Library Function: dkim_signature_tag (string sig, string tag)

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:

TagDefault value
csimple/simple
qdns/txt
i@’ + the value of the ‘d’ tag.
Library Function: dkim_verified_signature_tag (string tag)

Returns the value of tag tag from the ‘dkim_verified_signature’ variable.

Built-in Function: void dkim_sign (string d, string s, string keyfile, [ string ch, string cb, string headers ])

This function is available only in the eom handler.

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.

Mandatory arguments:

d

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).

s

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

  s._domainkey.d
keyfile

Name of the disk file that keeps the private key for signing the message. The file must be in PEM format.

Optional arguments:

ch

Canonicalization algorithm for message headers. Valid values are: ‘simple’ and ‘relaxed’. ‘simple’ is the default.

cb

Canonicalization algorithm for message body. Valid and default values are the same as for ch.

headers

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:

  • "From:From:"
  • "Reply-To:Reply-To:"
  • "Subject:Subject:"
  • "Date:Date:"
  • "To:"
  • "Cc:"
  • "Resent-Date:"
  • "Resent-From:"
  • "Resent-To:"
  • "Resent-Cc:"
  • "In-Reply-To:"
  • "References:"
  • "List-Id:"
  • "List-Help:"
  • "List-Unsubscribe:"
  • "List-Subscribe:"
  • "List-Post:"
  • "List-Owner:"
  • "List-Archive"

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

Note on interation of dkim_sign with MMQ

The functions header_add and header_insert (see Header modification functions) as well as the add 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 e_badmmq 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.

5.34.1 Setting up a DKIM record

Follow these steps to set up your own DKIM record:

  1. Generate the key pair Use the openssl genrsa command. Run:
    openssl genrsa -out private.pem 2048
    

    The last argument is the size of the private key to generate in bits.

  2. Extract the public key
    openssl rsa -in private.pem -pubout -outform PEM -out public.pem
    
  3. Set up a DKIM record in your domain A DKIM record is a TXT type DNS record that holds the public key part for verifying messages. Its format is defined in RFC 487125. The label for this record is composed as follows:
      s._domainkey.d
    

    where d is your domain name, and s is the selector you chose to use. You will use these two values as parameters to the dkim_sign function in your eom handler. E.g. if your domain in ‘example.com’ and selector is ‘s2048’, then the DKIM TXT record label is ‘s2048._domainkey.example.com’.

    The public key file generated in step 2 will have the following contents:

    -----BEGIN PUBLIC KEY-----
    base64
    -----END PUBLIC KEY-----
    

    where base64 is the key itself in base64 encoding. The minimal DKIM TXT record will be:

    "v=DKIM1; p=base64"
    

    The only mandatory tag is in fact ‘p=’. The use of ‘v=’ is recommended. More tags can be added as needed. In particular, while testing the DKIM support, it is advisable to add the ‘t=y’ tag.

Footnotes

(25)

https://tools.ietf.org/html/rfc4871

Mailfromd Manual (split by section):   Section:   Chapter:FastBack: Library   Up: DKIM   FastForward: Using MFL Mode   Contents: Table of ContentsIndex: Concept Index