DKIM email security standard was designed to make sure messages were not altered or compromised in transit between sender and receiver. It uses public-key cryptography to sign email with
private key before it’s sent from server. Recipient server can then use
public key published on domain’s DNS to verify the source of the message, and that the body of the message hasn’t changed. Once hash is verified, message passes DKIM check and is considered authentic.
DKIM – DomainKeys Identified Mail
>> DKIM email security standard/protocol enables the signing of emails in such a way that it is possible to verify who sent the mail through cryptographic signature. Hash is created from an email segment, and then encrypted with a private key held by the original sender. That encrypted DKIM signature is sent along with the original email to the receiver. Receiver (mailbox provider) will lookup the domain DNS to find DKIM public key, which will be used to decrypt the DKIM signature into its original hash. Mail provider (receiver) is also hashing the selected elements and comparing it with the decrypted hash.
Keypair = Anything encrypted with one key from a keypair can ONLY be decrypted using the other key
If we make public key public, anyone can decrypt and read encrypted data but nobody could modify it (in transit). They need the private key to encrypt their own modified copy. Signature doesn’t encrypt data, just a hash sum od the data. Steps:
- A = a hash sum of your copy of the data
- B = decrypt signature using domain/DNS/DKIM public key to reveal the hash sum (of the received email)
- if A==B, your copy is unmodified
Hash sums are one way, irreproducible.
The process of setting up DKIM can be difficult. It requires generating a public and private key pair and correctly placing the public key in your DNS records, and the private key within the email exchange server.
For example, given the signature:
DKIM-Signature: v=1; a=rsa-sha256; d=example.net; s=brisbane; c=relaxed/simple; q=dns/txt; l=1234; t=1117574938; x=1118006938; h=from:to:subject:date:keywords:keywords; bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=; b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ VoG4ZHRNiYzR
A verifier queries the TXT record type of brisbane._domainkey.example.net:
# dig -t TXT <selector>._domainkey.<domain> +short
Some tags from the example above:
a– signing algorithm
s– selector (which public key used; a domain can have many)
c– canonicalization algorithm(s) for header and body (how to handle header case sensitivity, whitespace, CRLF, etc.)
q– default query method
l– the length of the canonicalized part of the body that has been signed
t– signature timestamp
x– its expire time
h– list of signed header fields, repeated for fields that occur multiple times.
bh– hash sum of canonicalized message body. It’s used to quickly check if a message fails DKIM (avoiding DoS attack)
b– signature of data (includes headers and body)
DKIM defines two canonicalization algorithms for the body of the message,
- simple – does very little: it just strips any blank lines at the end of the body
- relaxed – strips those blank lines, and then replaces any run of white space or tabs with a single space
DKIM also defines two canonicalization algorithms for the headers of the message. They’re also called
relaxed, despite doing quite different things:
- simple header canonicalization makes no changes, so the headers must be byte for byte identical to match.
- relaxed header canonicalization converts all header names to lower case, unfolds header so each is a single line, replaces any run of white space with single space and removes anytrailing whitespace on each line.
The possible results for your DKIM test:
pass: ‘The message was signed, the signature or signatures were acceptable, and the signature(s) passed verification tests.’
fail: ‘The message was signed and the signature or signatures were acceptable, but they failed the verification test(s).’
The message is signed and signature is formed correctly, but it didn’t match the signature of the sending server. Potential indication that the message was altered somewhere along the way.
none: ‘The message was not signed’
Message without DKIM signature.
policy: ‘The message was signed but the signature or signatures were not acceptable.’
Message is signed and correctly formed, but it didn’t meet the policy requirements on the recipient side.
neutral: ‘The message was signed but the signature or signatures contained syntax errors or were not otherwise able to be processed.’
Signed message but not formed correctly. Probably a configuration error on sender side.
temperror: ‘The message could not be verified due to some error that is likely transient in nature, such as a temporary inability to retrieve a public key. A later attempt may produce a final result.’
Indication of a short-term problem verifying the signature. Retry. Repeated problems may be a sign of some DNS related failure.
permerror: ‘The message could not be verified due to some error that is unrecoverable, such as a required header field being absent. A later attempt is unlikely to produce a final result.’
The signature (or some segement) was missing within the recieved message. Indication of badly formed header or that it was modified after being sent.
There are weaknesses. On some servers (misconfigured ones) end-users can effectively be spoofed by messages that pass all tests in DKIM. If you “prepend” second From: field in the header, seen by the users. By default DKIM doesn’t sign or check signatures on most parts of the envelope (message header elements), but the sender can specify that they are signed with an “h=From” in the DKIM-Signatures header.
Consider this scrap of message header:
From: Donald Trump <firstname.lastname@example.org> From: Bad guy <email@example.com> Reply-To: Bad guy<firstname.lastname@example.org> Subject: "White house" To: "Someone" <email@example.com>
Both fields may be included in the signature, and the end user may see a verified DKIM message coming from firstname.lastname@example.org. Because DKIM only signs a specified parts of the message, the message can be forwarded on by an intermediary that inserts the extra fields, and the signature will still match. This is called a replay attack.
There is a great article you should check: “Breaking DKIM – on purpose and by chance“. I’ll include some sumarized info here.
Vague DKIM Standard
The only requirement in the standard is that ‘From’ must be included. Apart from that, everything else is vague (5.4. Determine the header fields to sign):
“The choice of which header fields to sign is non-obvious…signing fields present in the message such as Date, Subject, Reply-To, Sender, and all MIME header fields are highly advised.”
The predecessor Section 5.5 of the RFC 4871 defines those fields a bit more clearly (as what SHOULD be signed). Apart from which header fields should be signed, it’s even worse on how to protect against extra header fields added later ( 8.15. Attacks Involving Extra Header Fields ). Recipient is responsible for dealing with this problem. One mentioned solution is by “oversigning”:
“A header field name need only be listed once more than the actual number of that header field in a message at the time of signing in order to prevent any further additions.“
Many mail providers include Subject line in the signature, but very small number of them is protected against additional subject header with oversigning. With multiple subject lines in an email, some providers (like Gmail, Thunderbird, AOL) display only the first subject line while DKIM signature covers only the last one. Knowing that, an attacker could change subject without affecting the validity of DKIM.
DKIM-Signature: v=1; h=from:to:cc:subject:content-type; ... From: <email@example.com> To: firstname.lastname@example.org Subject: Regular subject Content-type: multipart/mixed; boundary=foo Date: Wed, 20 July 2018 17:55:18 +0200 --foo Content-type: text/plain some text --foo--
With this email, we have a valid signature, subject and body. If we add header fields at the top:
Subject: NEW Subject Content-type: multipart/mixed; boundary=bar DKIM-Signature: v=1; h=from:to:cc:subject:content-type; ... From: <email@example.com> ...
We’ll still have a valid DKIM, with different subject and no body (due to different boundary being set).
The length part of the DKIM is problematic. Usually, whole body is covered, but some misconfigured servers limit DKIM signature to cover just some portion of it. On the example below, body hash covers a segment of the email, covering fields with the signature but not protecting them from oversigning (adding another fields).
DKIM-Signature: v=1; l=1850; d=dhl.com; s=20180901... h=date:from:to:message-id:subject:mime-version... Date: Thu, 24 Sep 2xxx 19:08:23 +0800 (MYT) Date: Thu, 14 Jan 2xxx 19:08:23 +0800 (MYT) From: Customer Support <firstname.lastname@example.org> To: email@example.com To: firstname.lastname@example.org Message-ID: <9953648784.9145749...> Message-ID: <1453648784.9145749.145276.....> Subject: Regular Subject MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=BAD Content-Type: multipart/mixed; boundary=----=_Part_9145747_2082645767.1452769703900 ------=_Part_9145747_2082645767.1452769703900 Content-type: text/plain Real Message ------=_Part_9145747_2082645767.1452769703900 --BAD Content-type: text/plain Faked Message --BAD--
Everything before the newly specified boundary=BAD will be ignored (treated as MIME preamble). Signatures are valid (SPF, DKIM and DMARC).
For prevention, check this Check RDC 6376 – Misuse of Body Length Limits :
“Use of the “l=” tag might allow display of fraudulent content without appropriate warning to end users… using the “l=” tag enables attacks in which an intermediary
with malicious intent can modify a message to include content that solely benefits the attacker… To avoid this attack, Signers should be extremely wary of using this
tag, and Assessors might wish to ignore signatures that use the tag.”
To work on:
Check RFC 4871 : DomainKeys Identified Mail (DKIM) Signatures)
Check RFC 5322 : Internet Message Format
Check RFC 5585 : DomainKeys Identified Mail (DKIM) Service Overview
Check RFC 5672 : DomainKeys Identified Mail (DKIM) Signatures — Update
Check RFC 6376 : DomainKeys Identified Mail (DKIM) Signatures