Skip to main content

DomainKeys is a technology proposal that can bring "yes or no" back to the decision process by giving email providers a mechanism for verifying both the domain of each email sender and the integrity of the messages sent (i.e,. that they were not altered during transit). And, once the domain can be verified, it can be compared to the domain used by the sender in the From: field of the message to detect forgeries. If it's a forgery, then it's spam or fraud, and it can be dropped without impact to the user. If it's not a forgery, then the domain is known, and a persistent reputation profile can be established for that sending domain that can be tied into anti-spam policy systems, shared between service providers, and even exposed to the user.

How it Works: Sending Servers

  1. Set up: The domain owner (typically the team running the email systems within a company or service provider) generates a public/private key pair to use for signing all outgoing messages (multiple key pairs are allowed). The policy and the public key is published in DNS, and the private key is made available to their DomainKey-enabled outbound email servers. This is step "A" in the diagram to the right.

  2. Signing: When each email is sent by an authorized end-user within the domain, the DomainKey-enabled email system automatically uses the stored private key to generate a digital signature of the message. This signature is then prepended as a header to the email, and the email is sent on to the target recipient's mail server. This is step "B" in the diagram to the right.

How it Works: Receiving Servers

  1. Preparing: The DomainKeys-enabled receiving email system extracts the signature and claimed From: domain from the email headers and fetches the public key from DNS for the claimed From: domain. This is step "C" in the diagram to the right.

  2. Verifying: The public key from DNS is then used by the receiving mail system to verify that the signature was generated by the matching private key. This proves that the email was truly sent by, and with the permission of, the claimed sending From: domain and that its headers and content weren't altered during transfer. It then looks in DNS for the DomainKeys signing policy for the claimed sending domain to assess the result.

  3. Delivering: The receiving email system applies local policies based on the results of the signature test. If the domain is verified and other anti-spam tests don't catch it, the email can be delivered to the user's inbox. If the signature fails to verify, or there isn't one, the email can be dropped, flagged, or quarantined. This is step "D" in the diagram on the right.

Validation

When the dk_validate module is loaded, validation is performed on all inbound messages received via SMTP.

dk_validate "dk_validate1" {
}

When a message is received, it is inspected to determine the responsible sending party which is either the Sender or the From (in that order) from the message headers. If there exists a header called "DomainKey-Signature", the signature is parsed for validity. If valid, the appropriate DNS operations are performed to find the policy and public key for the signer, the message is canonicalized as described in the signature and the signature is validated.

Subsequent to processing the email, any preexisting "DomainKey-Status" headers are removed from the email and the dk_validate module will prepend a "DomainKey-Status" header to the email with the results of the signature verification process. Valid results are "good," "bad," and "error".

Signing

The dk_sign module provides the ability to conditionally attach DomainKeys signatures to emails that are submitted into the MTA via SMTP or ECStream.

14.29.4.1. Publishing a signing policy

The first step of deploying DomainKeys is to specify how you will be using DomainKeys in a public DNS record. This will allow verifiers to process the outcomes of a successful, failed, or missing signature.

The interim sending domain policy is very simple and is expressed in the _domainkey TXT record in the DNS of the sending domain.

The contents of this TXT record are stored as tag=value pairs separated by semicolons.

g=

Granularity of the key. The intent of this tag is to constrain which signing address can legitimately use the selector for this key. The default value for this key is *. If an empty value (i.e. "g=") is specified, no signing address will be able to use this key.

n

This tag is used to provide notes to a human inspecting the record. It is not interpreted by a DomainKeys validator. This tag is optional.

o

This tag specifies the sending domain's signing policy. A value of - indicates that this domain signs all email with DomainKeys. A value of ~ indicates that this domain may sign some email with DomainKeys. ~ is the recommended value at this stage of DomainKeys deployment and adoption.

r

This tag specifies an email address to which notification of invalid verification results will be sent. The frequency and content of such emails has yet to be formally defined. This feature is designed for early implementors and testers. This tag is optional and it is recommended that it be omitted.

t

This tag is used to indicate that a domain is currently testing DomainKeys. y will indicate that this domain is in testing mode. n is not a valid value for the testing tag and this tag should be omitted if DomainKeys is not in testing mode for this domain.

A sample DNS text record would look like:

_domainkey IN TXT "t=y; o=~" 14.29.4.2. Generating keys

In order to generate RSA keys for the domain example.com with a selector called s1024 the following openssl commands should be issued at the command prompt.

# mkdir -p /opt/msys/ecelerity/etc/conf/dk/example.com
# openssl genrsa -out /opt/msys/ecelerity/etc/conf/dk/example.com/s1024.key 1024
# openssl rsa -in /opt/msys/ecelerity/etc/conf/dk/example.com/s1024.key \
        -out /opt/msys/ecelerity/etc/conf/dk/example.com/s1024.pub -pubout -outform PEM

The contents of the file /opt/msys/ecelerity/etc/conf/dk/example.com/s1024.pub should be placed in the DNS TXT record of s1024._domainkey.example.com.

The resulting public key should look something like:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAf1O8E/pDap7nRe1w6hVwsdUC
3BmO/EIE1RCxY92Dk8TwSv7MteLTPfHcasiUDeAboGDjm2U2WfO6AE8detDuKsIN
TGt1QY/ng3aTGq0/93OyeUFnux/8o9rQOjZrmVQQICfgWb4VvhdG6j0tjXoVzGOA
gYdV9a5DY5fwlbM3DwIDAQAB
-----END PUBLIC KEY-----

The DNS text record should look like:

s1024._domainkey IN TXT ""g=*; k=rsa; p=MIGf...IDAQAB"

Note

As a signer, you must select a key size that is supported by validation systems on the remote receiving end. Those implementations must choose key sizes of 512, 768, 1024, 1536 or 2048 bits.

14.29.4.3. Configuring Momentum to sign mail

A Momentum configuration directive similiar to the following is use to load the dk_sign module. Additionally, Domainkeys signing may be enabled/disabled on a global, domain, binding and binding::domain basis using the configuration parameter: domainkeys

dk_sign "dk_sign1" {
  sign_condition = "can_relay"
  canon = "nofws"
  digest = "rsa-sha1"
  key = "/opt/msys/ecelerity/etc/conf/dk/%{d}/%{s}.key"
  dk_domain "example.com" {
    selector = "s1024"
  }
  dk_domain "corp.example.com" {
    selector = "s1024"
    base_domain = "example.com"
  }
}

"dk_sign" configuration options are described below. Any option can appear as a dk_sign or dk_domain scope configuration option with the exception of the base_domain option which can only appear within the dk_domain scope.

base_domain

base_domain specifies which domain should be used for the signing. DomainKeys allows for emails to be signed by a parent domain. For example, a mail from test@corp.example.com can be signed in the example.com domain. This option is only valid within the dk_domain scope.

canon

Specifies the canonicalization that should be performed on the email before digesting and signing the message. The two supported canonicalizations are simple and nofws. Due to the way MTAs operate, the simple canonicalization is very fragile and prone to failure due to header rewriting and rewrapping. nofws canonicalization should always be used instead of simple. The nofws canonicalization removes all whitespace within the body and the eighth bit of the data before calculating the hash.

digest

Specifies the algorithms that should be used to create the message digest and resulting signature. The only supported mechanism is rsa-sha1.

*`domain`* [ ... ]

The system will automatically find the appropriate key if a top-level key file is defined and the domains use the same selector. If the selectors differ, a domain subconfiguration must be specified. When a message is received, the responsible sender is determined by looking for the domain part of the email address used in the Sender or From header (in that order). That subconfiguration for that domain is used for signing.

headerlist

The configuration directive is optional and instructs Momentum that only the specified headers should be signed in the order specified during digestion. This option can be used to sign only a limited subset of headers. By default, the implementation will extract all appropriate headers, sign them and manufacture a headerlist for use with that message. The final headerlist describing the order and inclusion of headers will be included in the DomainKey-Signature as the h= value.

key

This option is required and specifies the location of the RSA private key file on disk. The key file must be readable by the user that Momentum is running as and must be in Privacy Enhanced Mail (PEM) format.

The file name has two expandable variables that may be used to ease deployment over multiple domains: %{d} expands to the responsible domain and %{s} expands to the selector.

keycache_size

The key cache size expressed as the number of keys. The default value is 2048.

neg_keycache_ttl

In the event that the key isn't already in the cache, the amount of time in seconds before retrieving it again. The default value is 3600.

pos_keycache_ttl

The total time in seconds for items to stay in the cache before fetching them again. The default value is 300.

selector

This option specifies the DomainKeys selector to be used for signing. The selector is required per the DomainKeys specification. Selectors allow for easier key management as multiple keys can be phased in and out over time. When accessing the appropriate public key for a signature, the TXT record for {selector}._domainkey.{domain} is resolved.

sign_condition

Sign condition specifies which validation context variable must exist as a predicate to signing messages. When an SMTP client performs an SMTP AUTH action, the auth_user connection context variable will be set to the username used during authorization. When an SMTP client is allowed to relay through Momentum because of an entry in Relay_Hosts or a relaying declaration in an ESMTP_Listener IP access control list, the can_relay connection context variable is set to "true." Validation context variables are discussed in Validation Context Variables .

In most corporate environments, sign_condition should be auth_user and in large sending architectures where the relaying SMTP clients are implicitly trusted the sign_condition should be can_relay. In highly-structured sending architectures where ecstream injection is the only method, this option can be omitted entirely, with the result that any message for which a key exists will be signed.

domainkeys Runtime Usage

The domainkeys module sets one message context variable:

dk_status

This variable returns the domain key status. It can have one of the following values:

  • good

  • bad

  • bad (key type)

  • bad (no key)

  • bad (key revoked)

  • bad (public key)

  • bad (malformed signature)

  • bad (unsupported query type)

14.29.5.1. Lua Functions

The following domainkeys Lua functions are available:

14.29.5.2. Sieve Functions

The following domainkeys Sieve functions are available:

domainkeys Management Using Console Commands

The domainkeys module can be controlled through the ec_console; the following commands are available:

Note

In version 3.0, non-singleton module commands are issued using Scope_Name:Instance_Name followed by the command. Use the module list command from the system console to determine the scope name or instance name of a module. If a module does not have an instance name it is a singleton.

As of version 3.0, all module-specific commands related to setting or getting module options have been removed. Use the following syntax to set or get module-specific options: config {set | eval | get} Scope_Name [Instance_Name] option [value] . Note that there is no ‘:’ between the Scope_Name and the Instance_Name and that the Instance_Name is not used with singleton modules.

14.29.6.1. dk_sign:dk_sign1 stats

Display statistics relating to domain key signing.

14.29.6.2. dk_sign:dk_sign1 flush keycache

This command flushes all entries from the keycache. If you alter the private key run this command after doing so.

See Also

Was this page helpful?