Skip to content

Commit

Permalink
Updated DKIM signing
Browse files Browse the repository at this point in the history
  • Loading branch information
andris9 committed Aug 9, 2016
1 parent 0ce3db1 commit 5b013f5
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 29 deletions.
90 changes: 63 additions & 27 deletions lib/dkim-relaxed-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,89 @@

// streams through a message body and calculates relaxed body hash

const config = require('config');
const Transform = require('stream').Transform;
const crypto = require('crypto');

class DkimRelaxedBody extends Transform {
constructor(options) {
super(options);
super();
options = options || {};
this.chunkBuffer = [];
this.chunkBufferLen = 0;
this.bodyHash = crypto.createHash(config.dkim.hash);
this.bodyHash = crypto.createHash(options.hash || 'sha1');
this.remainder = '';

this.debug = options.debug;
this._debugBody = options.debug ? [] : false;
}

updateHash(chunk) {
let bodyStr;

if (chunk) {
bodyStr = this.remainder + chunk.toString('binary');
if (bodyStr.length < 1024) {
this.remainder = bodyStr;
return;
// find next remainder
let nextRemainder = '';


// This crux finds and removes the spaces from the last line and the newline characters after the last non-empty line
// If we get another chunk that does not match this description then we can restore the previously processed data
let state = 'file';
for (let i = chunk.length - 1; i >= 0; i--) {
let c = chunk[i];

if (state === 'file' && (c === 0x0A || c === 0x0D)) {
// do nothing, found \n or \r at the end of chunk, stil end of file
} else if (state === 'file' && (c === 0x09 || c === 0x20)) {
// switch to line ending mode, this is the last non-empty line
state = 'line';
} else if (state === 'line' && (c === 0x09 || c === 0x20)) {
// do nothing, found ' ' or \t at the end of line, keep processing the last non-empty line
} else if (state === 'file' || state === 'line') {
// non line/file ending character found, switch to body mode
state = 'body';
if (i === chunk.length - 1) {
// final char is not part of line end or file end, so do nothing
break;
}
}
this.remainder = bodyStr.substr(-1024);
bodyStr = bodyStr.substr(0, bodyStr.length - this.remainder.length);
} else {
// final call
bodyStr = this.remainder;
}

// ignore trailing <CR>
if (bodyStr.length && bodyStr.substr(-1) === '\r') {
bodyStr = bodyStr.substr(0, bodyStr.length - 1);
}
if (i === 0) {
// reached to the beginning of the chunk, check if it is still about the ending
// and if the remainder also matches
if ((state === 'file' && (!this.remainder || /[\r\n]$/.test(this.remainder))) ||
(state === 'line' && (!this.remainder || /[ \t]$/.test(this.remainder)))) {
// keep everything
this.remainder += chunk.toString('binary');
return;
} else if (state === 'line' || state === 'file') {
// process existing remainder as normal line but store the current chunk
nextRemainder = chunk.toString('binary');
chunk = false;
break;
}
}

bodyStr = bodyStr.replace(/\r?\n|\r/g, '\n') // use js line endings
.replace(/[ \t]*$/mg, '') // remove line endings, rtrim
.replace(/[ \t]+/mg, ' '); // single spaces
if (state !== 'body') {
continue;
}

if (!chunk) {
bodyStr = bodyStr.replace(/\n+$/, '\n'); // remove trailing lines for final part
// reached first non ending byte
nextRemainder = chunk.slice(i + 1).toString('binary');
chunk = chunk.slice(0, i + 1);
break;
}

bodyStr = bodyStr.replace(/\n/g, '\r\n'); // restore rfc822 line endings
bodyStr = this.remainder + (chunk ? chunk.toString('binary') : '');
this.remainder = nextRemainder;

bodyStr = bodyStr.replace(/\r?\n/g, '\n') // use js line endings
.replace(/[ \t]*$/mg, '') // remove line endings, rtrim
.replace(/[ \t]+/mg, ' ') // single spaces
.replace(/\n/g, '\r\n'); // restore rfc822 line endings

let bodyChunk = Buffer.from(bodyStr, 'binary');
if (this.debug) {
this._debugBody.push(bodyChunk);
}
this.bodyHash.update(bodyChunk);
}

Expand All @@ -67,9 +105,7 @@ class DkimRelaxedBody extends Transform {

_flush(callback) {
// generate final hash and emit it
this.updateHash();
this.emit('hash', this.bodyHash.digest('base64'));

this.emit('hash', this.bodyHash.digest('base64'), this.debug ? Buffer.concat(this._debugBody) : false);
callback();
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/feeder-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class FeederServer {
});

if (config.dkim.enabled) {
dkimStream = new DkimRelaxedBody();
dkimStream = new DkimRelaxedBody(config.dkim);
dkimStream.on('hash', bodyHash => {
envelope.bodyHash = bodyHash;

Expand Down
1 change: 1 addition & 0 deletions lib/sending-zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ class SendingZone {

// for <[email protected]>
' for <' + delivery.to + '>' +
// (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256)
(delivery.tls ? '\r\n (version=' + delivery.tls.version + ' cipher=' + delivery.tls.name + ')' : '') +

';' +
Expand Down
65 changes: 65 additions & 0 deletions test/dkim-relaxed-body-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

let fs = require('fs');
let DkimRelaxedBody = require('../lib/dkim-relaxed-body');

module.exports['Calculate body hash byte by byte'] = test => {
fs.readFile(__dirname + '/fixtures/message1.eml', 'utf-8', (err, message) => {
test.ifError(err);

message = message.replace(/\r?\n/g, '\r\n');
message = message.split('\r\n\r\n');
message.shift();
message = message.join('\r\n\r\n');

message = Buffer.from(message);

let s = new DkimRelaxedBody({
hash: 'sha256',
debug: true
});

s.on('hash', hash => {
test.equal(hash, 'BPn9yHxMRt2aqIXVxv9wDcV0TlsNua+PdNYnNyAIMLY=');
test.done();
});

let pos = 0;
let stream = () => {
if (pos >= message.length) {
return s.end();
}
let ord = Buffer.from([message[pos++]]);
s.write(ord);
setImmediate(stream);
};
setImmediate(stream);
});
};


module.exports['Calculate body hash byte all at once'] = test => {
fs.readFile(__dirname + '/fixtures/message1.eml', 'utf-8', (err, message) => {
test.ifError(err);

message = message.replace(/\r?\n/g, '\r\n');
message = message.split('\r\n\r\n');
message.shift();
message = message.join('\r\n\r\n');

message = Buffer.from(message);

let s = new DkimRelaxedBody({
hash: 'sha256',
debug: true
});

s.on('hash', hash => {
test.equal(hash, 'BPn9yHxMRt2aqIXVxv9wDcV0TlsNua+PdNYnNyAIMLY=');
test.done();
});

setImmediate(() => s.end(message));
});

};
144 changes: 144 additions & 0 deletions test/fixtures/message1.eml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
Content-Type: multipart/mixed;
boundary="----sinikael-?=_1-14707415696170.021441656324049596"
From: Andris Test <[email protected]>
To: [email protected]
Subject: Nodemailer is unicode friendly =?UTF-8?Q?=E2=9C=94?= 1470741569613
Message-ID: <[email protected]>
X-Mailer: nodemailer (2.5.0; +http://nodemailer.com/; SMTP
(pool)/2.7.0[client:2.8.0])
Date: Tue, 09 Aug 2016 11:19:29 +0000
MIME-Version: 1.0

------sinikael-?=_1-14707415696170.021441656324049596
Content-Type: multipart/alternative;
boundary="----sinikael-?=_2-14707415696170.021441656324049596"
------sinikael-?=_2-14707415696170.021441656324049596
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Hello to myself!
------sinikael-?=_2-14707415696170.021441656324049596
Content-Type: multipart/related; type="text/html";
boundary="----sinikael-?=_4-14707415696170.021441656324049596"
------sinikael-?=_4-14707415696170.021441656324049596
Content-Type: text/html
Content-Transfer-Encoding: 7bit

<p><b>Hello</b> to myself <img src="cid:[email protected]"/></p>
------sinikael-?=_4-14707415696170.021441656324049596
Content-Type: image/png; name=image.png
Content-ID: <[email protected]>
Content-Disposition: attachment; filename=image.png
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lE
QVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQ
AAAAAElFTkSuQmCC
------sinikael-?=_4-14707415696170.021441656324049596--

------sinikael-?=_2-14707415696170.021441656324049596--

------sinikael-?=_1-14707415696170.021441656324049596
Content-Type: text/plain; name=notes.txt
Content-Disposition: attachment; filename=notes.txt
Content-Transfer-Encoding: 7bit
Some notes about this e-mail
------sinikael-?=_1-14707415696170.021441656324049596
Content-Type: application/octet-stream; name=attachment.bin
Content-Disposition: attachment; filename=attachment.bin
Content-Transfer-Encoding: base64
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
------sinikael-?=_1-14707415696170.021441656324049596--
4 changes: 3 additions & 1 deletion test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ let send = () => {
for (let i = 0; i < rcptCount; i++) {
recipients += (i ? ', ' : '') + 'Test #' + (i + 1) + ' <test+' + (i + 1) + '@test' + (++domainCounter % domainCount + 1) + '.tahvel.info>';
}
recipients = '[email protected]';

recipients = '[email protected]';

// Message object
let message = {

Expand Down

0 comments on commit 5b013f5

Please sign in to comment.