Skip to content

Commit 17f7540

Browse files
committed
bug #42416 Invalid DKIM signature (metaer)
This PR was merged into the 5.4 branch. Discussion ---------- Invalid DKIM signature | Q | A | ------------- | --- | Branch? | 5.3 | Bug fix? | yes | New feature? | no | Deprecations? | no | License | MIT How to reproduce: ```php $email = (new Email()) ->from('[email protected]') ->subject('text') ->text('text') ; $addresses = '[email protected],[email protected]' //could be command's or method's argument, that's why we used call_user_func_array below \call_user_func_array([$email, 'to'], explode(',', $addresses)); $email->getHeaders()->addTextHeader('X-Transport', $transport); $privateKeyFilePath = '/private.pem'; $filesystem = new Filesystem(); if ($filesystem->exists($privateKeyFilePath)) { $signer = new DkimSigner("file://$privateKeyFilePath", 'yourdomain.com', 'your-selector'); $email = $signer->sign($email, ['headers_to_ignore' => ['x-transport']]); //symfony/symfony#39354 (comment) } $this->mailer->send($email); ``` How I tested body hash (bh): https://www.appmaildev.com/site/testfile/dkim?lang=en It shows expected body hash (`Expected-Body-Hash`) in DKIM section and received body hash (`bh=`) if fails. ![image](https://user-images.githubusercontent.com/6103208/128579511-ead9fde9-1492-4a6a-8953-2adb99eb251a.png) My solution is based on swiftmailer signer code and DKIM specifications (see links below). After applying patch it works correctly: ![image](https://user-images.githubusercontent.com/6103208/128579683-ba1599f4-956c-49f6-ba94-f69bb8979c8d.png) How swiftmailer signer adds trailing line return: ```php protected function endOfBody() { // Add trailing Line return if last line is non empty if (\strlen($this->bodyCanonLine) > 0) { $this->addToBodyHash("\r\n"); } $this->bodyHash = hash_final($this->bodyHashHandler, true); } ``` Swiftmailer signer works correctly with not empty body. From DKIM signature specifications: - simple canonicalization: https://datatracker.ietf.org/doc/html/rfc6376#section-3.4.3 `If there is no body or no trailing CRLF on the message body, a CRLF is added` - relaxed canonicalization: https://datatracker.ietf.org/doc/html/rfc6376#section-3.4.4 `If the body is non-empty but does not end with a CRLF, a CRLF is added` Other issues related to invalid DKIM signature: #39354, #41935, #42407. But is seems they have another problem, which is connected to templated emails. I have tested dkim signature manually (with gmail) with these cases: canonicalization: simple body: '' canonicalization: simple body: "\r\n" canonicalization: simple body: 'text' canonicalization: relaxed body: '' canonicalization: relaxed body: "\r\n" canonicalization: relaxed body: 'text' ![image](https://user-images.githubusercontent.com/6103208/128577659-1e765fe3-19f7-4ef2-bd59-22064e0d9b73.png) Commits ------- 0cb61f4828 Add trailing Line return if last line is non empty
2 parents ff62d28 + fbe5944 commit 17f7540

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

Crypto/DkimSigner.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,13 @@ private function hashBody(AbstractPart $body, string $bodyCanon, int $maxLength)
203203
hash_update($hash, $canon);
204204
}
205205

206-
if (0 === $length) {
206+
// Add trailing Line return if last line is non empty
207+
if (\strlen($currentLine) > 0) {
208+
hash_update($hash, "\r\n");
209+
$length += \strlen("\r\n");
210+
}
211+
212+
if (!$relaxed && 0 === $length) {
207213
hash_update($hash, "\r\n");
208214
$length = 2;
209215
}

Tests/Crypto/DkimSignerTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,14 @@ public function getCanonicalizeHeaderData()
122122
DkimSigner::CANON_SIMPLE, "\r\n", '', \PHP_INT_MAX,
123123
];
124124
yield 'relaxed_empty' => [
125-
DkimSigner::CANON_RELAXED, "\r\n", '', \PHP_INT_MAX,
125+
DkimSigner::CANON_RELAXED, '', '', \PHP_INT_MAX,
126126
];
127127

128128
yield 'simple_empty_single_ending_CLRF' => [
129129
DkimSigner::CANON_SIMPLE, "\r\n", "\r\n", \PHP_INT_MAX,
130130
];
131131
yield 'relaxed_empty_single_ending_CLRF' => [
132-
DkimSigner::CANON_RELAXED, "\r\n", "\r\n", \PHP_INT_MAX,
132+
DkimSigner::CANON_RELAXED, '', "\r\n", \PHP_INT_MAX,
133133
];
134134

135135
yield 'simple_multiple_ending_CLRF' => [

0 commit comments

Comments
 (0)