1
0
mirror of https://github.com/moparisthebest/mail synced 2024-08-13 16:43:47 -04:00

[WO-259] introduce proper signature checking

This commit is contained in:
Felix Hammerl 2014-07-04 17:58:25 +02:00
parent b11161655a
commit 30efac0792
6 changed files with 585 additions and 97 deletions

View File

@ -12,7 +12,7 @@
"dependencies": {
"crypto-lib": "https://github.com/whiteout-io/crypto-lib/tarball/v0.2.0",
"imap-client": "https://github.com/whiteout-io/imap-client/tarball/v0.3.4",
"mailreader": "https://github.com/whiteout-io/mailreader/tarball/v0.3.3",
"mailreader": "https://github.com/whiteout-io/mailreader/tarball/dev/WO-259",
"pgpmailer": "https://github.com/whiteout-io/pgpmailer/tarball/v0.3.5",
"pgpbuilder": "https://github.com/whiteout-io/pgpbuilder/tarball/v0.3.4",
"requirejs": "2.1.14",

View File

@ -296,13 +296,13 @@ define(function(require) {
};
/**
* [decrypt description]
* Decrypts a ciphertext
* @param {String} ciphertext The encrypted PGP message block
* @param {String} publicKeyArmored The public key used to sign the message
* @param {Function} callback(error, plaintext, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
*/
PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
var publicKeys, message, signaturesValid;
var publicKeys, message;
// check keys
if (!this._privateKey) {
@ -334,24 +334,119 @@ define(function(require) {
return;
}
// check if signatures are valid
if (decrypted.signatures.length > 0) {
signaturesValid = true; // signature is correct
for (var i = 0; i < decrypted.signatures.length; i++) {
if (decrypted.signatures[i].valid === false) {
signaturesValid = false; // signature is wrong ... message was tampered with
break;
} else if (decrypted.signatures[i].valid === null) {
signaturesValid = null; // signature not found for the specified public key
break;
}
}
}
// return decrypted plaintext
callback(null, decrypted.text, signaturesValid);
callback(null, decrypted.text, checkSignatureValidity(decrypted.signatures));
}
};
/**
* Verifies a clearsigned message
* @param {String} clearSignedText The clearsigned text, usually from a signed pgp/inline message
* @param {String} publicKeyArmored The public key used to signed the message
* @param {Function} callback(error, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
*/
PGP.prototype.verifyClearSignedMessage = function(clearSignedText, publicKeyArmored, callback) {
var publicKeys,
message;
// check keys
if (!this._privateKey) {
callback(new Error('Error verifying signed PGP message. Keys must be set!'));
return;
}
// read keys and ciphertext message
try {
if (publicKeyArmored) {
// parse public keys if available ...
publicKeys = openpgp.key.readArmored(publicKeyArmored).keys;
} else {
// use own public key to know if signatures are available
publicKeys = [this._publicKey];
}
message = openpgp.cleartext.readArmored(clearSignedText);
} catch (err) {
callback(new Error('Error verifying signed PGP message!'));
return;
}
openpgp.verifyClearSignedMessage(publicKeys, message, function(err, result) {
if (err) {
callback(new Error('Error verifying PGP message!'));
return;
}
callback(null, checkSignatureValidity(result.signatures));
});
};
/**
* Verifies a message with a detached signature
* @param {String} message The signed text, usually from a signed pgp/mime message
* @param {String} pgpSignature The detached signature, usually from a signed pgp/mime message
* @param {String} publicKeyArmored The public key used to signed the message
* @param {Function} callback(error, signaturesValid) signaturesValid is undefined in case there are no signature, null in case there are signatures but the wrong public key or no key was used to verify, true if the signature was successfully verified, or false if the signataure verification failed.
*/
PGP.prototype.verifySignedMessage = function(message, pgpSignature, publicKeyArmored, callback) {
var publicKeys;
// check keys
if (!this._privateKey) {
callback(new Error('Error verifying signed PGP message. Keys must be set!'));
return;
}
// read keys and ciphertext message
try {
if (publicKeyArmored) {
// parse public keys if available ...
publicKeys = openpgp.key.readArmored(publicKeyArmored).keys;
} else {
// use own public key to know if signatures are available
publicKeys = [this._publicKey];
}
} catch (err) {
callback(new Error('Error verifying signed PGP message!'));
return;
}
var signatures;
try {
var msg = openpgp.message.readSignedContent(message, pgpSignature);
signatures = msg.verify(publicKeys);
} catch (err) {
callback(new Error('Error verifying signed PGP message!'));
return;
}
callback(null, checkSignatureValidity(signatures));
};
/**
* Checks signature validity
* @param {Object} decrypted OpenPGP.js Signature array
* @return {undefined|null|true|false}
* If signatures array is empty (the message was not signed), returns undefined
* If you're using the wrong public key, returns null.
* If signatures are invalid, returns false.
* If everything is in order, returns true
*/
function checkSignatureValidity(signatures) {
if (!(signatures || []).length) {
// signatures array is empty (the message was not signed)
return;
}
for (var i = 0; i < signatures.length; i++) {
if (signatures[i].valid !== true) { // null | false
// you're using the wrong public key or signatures are invalid
return signatures[i].valid;
}
}
// everything is in order
return true;
}
return PGP;
});

View File

@ -698,80 +698,83 @@ define(function(require) {
if (message.encrypted) {
// show the encrypted message
message.body = filterBodyParts(message.bodyParts, 'encrypted')[0].content;
done();
return;
return done();
}
// for unencrypted messages, this is the array where the body parts are located
var root = message.bodyParts;
if (message.signed) {
var signedPart = filterBodyParts(message.bodyParts, 'signed')[0];
message.signedMessage = signedPart.signedMessage;
message.signature = signedPart.signature;
// TODO check integrity
// in case of a signed message, you only want to show the signed content and ignore the rest
root = signedPart.content;
// PGP/MIME signed
var signedRoot = filterBodyParts(message.bodyParts, 'signed')[0]; // in case of a signed message, you only want to show the signed content and ignore the rest
message.signedMessage = signedRoot.signedMessage;
message.signature = signedRoot.signature;
root = signedRoot.content;
}
// if the message is plain text and contains pgp/inline, we are only interested in the encrypted
// content, the rest (corporate mail footer, attachments, etc.) is discarded.
var body = _.pluck(filterBodyParts(root, 'text'), 'content').join('\n');
/*
* here's how the pgp/inline regex works:
* - any content before the PGP block will be discarded
* - "-----BEGIN PGP MESSAGE-----" must be at the beginning (and end) of a line
* - "-----END PGP MESSAGE-----" must be at the beginning (and end) of a line
* - the regex must not match a pgp block in a plain text reply or forward of a pgp/inline message.
* (the encryption will break for replies/forward, because "> " corrupts the PGP block with non-radix-64 characters)
* if the message is plain text and contains pgp/inline, we are only interested in the encrypted
* content, the rest (corporate mail footer, attachments, etc.) is discarded.
* "-----BEGIN/END (...)-----" must be at the start/end of a line,
* the regex must not match a pgp block in a plain text reply or forward of a pgp/inline message,
* the encryption will break for replies/forward, because "> " corrupts the PGP block with non-radix-64 characters,
*/
var pgpInlineRegex = /^-{5}BEGIN PGP MESSAGE-{5}$[^>]*^-{5}END PGP MESSAGE-{5}$/im;
var pgpInlineMatch = pgpInlineRegex.exec(body);
var pgpInlineMatch = /^-{5}BEGIN PGP MESSAGE-{5}[\s\S]*-{5}END PGP MESSAGE-{5}$/im.exec(body);
if (pgpInlineMatch) {
// show the plain text content
message.body = pgpInlineMatch[0];
message.body = pgpInlineMatch[0]; // show the plain text content
message.encrypted = true; // signal the ui that we're handling encrypted content
// - replace the bodyParts info with an artificial bodyPart of type "encrypted"
// - _isPgpInline is only used internally to avoid trying to parse non-MIME text with the mailreader
// - set the encrypted flag so we can signal the ui that we're handling encrypted content
message.encrypted = true;
// replace the bodyParts info with an artificial bodyPart of type "encrypted"
message.bodyParts = [{
type: 'encrypted',
content: pgpInlineMatch[0],
_isPgpInline: true
_isPgpInline: true // used internally to avoid trying to parse non-MIME text with the mailreader
}];
done();
return;
return done();
}
/*
* here's how the clear signing regex works:
* - any content before the PGP block will be discarded
* - "-----BEGIN PGP SIGNED MESSAGE-----" must be at the beginning (and end) of a line
* - "-----END PGP SIGNATURE-----" must be at the beginning (and end) of a line
* - the regex must not match a pgp block in a plain text reply or forward of a pgp/signed message.
* (the encryption will break for replies/forward, because "> " corrupts the PGP block with non-radix-64 characters)
* any content before/after the PGP block will be discarded,
* "-----BEGIN/END (...)-----" must be at the start/end of a line,
* after \n\n the signed payload begins,
* the text is followed by a final \n and then the pgp signature begins
* untrusted attachments and html is ignored
*/
var clearSignedRegex = /^-{5}BEGIN PGP SIGNED MESSAGE-{5}[\s\S]*\n{2}([\S\s]*)(-{5}BEGIN PGP SIGNATURE-{5}[\S\s]*-{5}END PGP SIGNATURE-{5})$/im;
var clearSignedMatch = clearSignedRegex.exec(body);
var clearSignedMatch = /^-{5}BEGIN PGP SIGNED MESSAGE-{5}[\s\S]*\n\n([\s\S]*)\n-{5}BEGIN PGP SIGNATURE-{5}[\S\s]*-{5}END PGP SIGNATURE-{5}$/im.exec(body);
if (clearSignedMatch) {
message.clearSignedMessage = clearSignedMatch[0];
// PGP/INLINE signed
message.signed = true;
// TODO check integrity
message.body = clearSignedMatch[1].trim();
} else {
message.body = body;
message.clearSignedMessage = clearSignedMatch[0];
body = clearSignedMatch[1];
}
if (!message.signed) {
// message is not signed, so we're done here
return setBody();
}
// check the signatures for signed messages
self._checkSignatures(message, function(err, signaturesValid) {
if (err) {
return done(err);
}
message.signaturesValid = signaturesValid;
setBody();
});
function setBody() {
message.body = body;
if (!message.clearSignedMessage) {
message.attachments = filterBodyParts(root, 'attachment');
message.html = _.pluck(filterBodyParts(root, 'html'), 'content').join('\n');
inlineExternalImages(message);
}
done();
}
}
function done(err) {
@ -780,6 +783,27 @@ define(function(require) {
}
};
EmailDAO.prototype._checkSignatures = function(message, callback) {
var self = this;
self._keychain.getReceiverPublicKey(message.from[0].address, function(err, senderPublicKey) {
if (err) {
return callback(err);
}
// get the receiver's public key to check the message signature
var senderKey = senderPublicKey ? senderPublicKey.publicKey : undefined;
if (message.clearSignedMessage) {
self._pgp.verifyClearSignedMessage(message.clearSignedMessage, senderKey, callback);
} else if (message.signedMessage && message.signature) {
self._pgp.verifySignedMessage(message.signedMessage, message.signature, senderKey, callback);
} else {
callback(null, undefined);
}
});
};
/**
* Retrieves an attachment matching a body part for a given uid and a folder
*
@ -859,17 +883,48 @@ define(function(require) {
// parse the decrypted raw content in the mailparser
self._mailreader.parse({
bodyParts: [encryptedNode]
}, function(err, parsedBodyParts) {
}, function(err, root) {
if (err) {
showError(err.errMsg || err.message);
return;
}
if (!message.signed) {
// message had no signature in the ciphertext, so there's a little extra effort to be done here
// is there a signed MIME node?
var signedRoot = filterBodyParts(root, 'signed')[0];
if (!signedRoot) {
// no signed MIME node, obviously an unsigned PGP/MIME message
return setBody();
}
// if there is something signed in here, we're only interested in the signed content
message.signedMessage = signedRoot.signedMessage;
message.signature = signedRoot.signature;
root = signedRoot.content;
// check the signatures for encrypted messages
self._checkSignatures(message, function(err, signaturesValid) {
if (err) {
return done(err);
}
message.signed = typeof signaturesValid !== 'undefined';
message.signaturesValid = signaturesValid;
setBody();
});
return;
}
// message had a signature in the ciphertext, so we're done here
setBody();
function setBody() {
// we have successfully interpreted the descrypted message,
// so let's update the views on the message parts
message.body = _.pluck(filterBodyParts(parsedBodyParts, 'text'), 'content').join('\n');
message.html = _.pluck(filterBodyParts(parsedBodyParts, 'html'), 'content').join('\n');
message.attachments = _.reject(filterBodyParts(parsedBodyParts, 'attachment'), function(attmt) {
message.body = _.pluck(filterBodyParts(root, 'text'), 'content').join('\n');
message.html = _.pluck(filterBodyParts(root, 'html'), 'content').join('\n');
message.attachments = _.reject(filterBodyParts(root, 'attachment'), function(attmt) {
// remove the pgp-signature from the attachments
return attmt.mimeType === "application/pgp-signature";
});
@ -879,13 +934,14 @@ define(function(require) {
// we're done here!
done();
}
});
});
});
function showError(msg) {
message.body = msg;
message.decrypted = true; // display error msh in body
message.decrypted = true; // display error msg in body
done();
}

View File

@ -69,11 +69,11 @@ define(function(require) {
raw: "Content-Type: multipart/encrypted; boundary=\"Apple-Mail=_FE60F127-D74F-4377-93CC-56430132A178\"; protocol=\"application/pgp-encrypted\";\r\nSubject: test15\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 \\(1878.2\\))\r\nX-Pgp-Agent: GPGMail (null)\r\nFrom: safewithme <safewithme.testuser@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:25:10 +0200\r\nContent-Transfer-Encoding: 7bit\r\nMessage-Id: <E5A9BAE2-0FC3-4BEC-9208-39C629CF33AB@gmail.com>\r\nContent-Description: OpenPGP encrypted message\r\nTo: safewithme.testuser@gmail.com\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\nThis is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)\r\n--Apple-Mail=_FE60F127-D74F-4377-93CC-56430132A178\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: application/pgp-encrypted\r\nContent-Description: PGP/MIME Versions Identification\r\n\r\nVersion: 1\r\n\r\n--Apple-Mail=_FE60F127-D74F-4377-93CC-56430132A178\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline;\r\n\tfilename=encrypted.asc\r\nContent-Type: application/octet-stream;\r\n\tname=encrypted.asc\r\nContent-Description: OpenPGP encrypted message\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nComment: GPGTools - https://gpgtools.org\r\n\r\nhQEMA9f7k/zfv8I8AQf/U11mVSMI5wFM4gh20M1eF1xx5Gs+JJK7hIqKoW7z127k\r\nqB+QEnPvWqa5vV2+gi22bDeXgVNELN3wb2CAznMM82TnpiSbmLLMSrGtx8BAJsfW\r\n+yxaDMvGMn6JHsGPQ6rij7ar9yGCgw6gGOrCuxzCLSgeajbmEn76lyIOtDxY0KSK\r\nisW0K1iD9SeJJiMnMg/EP0Sf9sUzIZjQNJpoz9S23keAHqij/eNexrdmobLMQamF\r\n9BxforwfewMEBv+/+atTj91nS260RBB2g+S6tv1RNJbZ3zTbqr06lviPTQ5zoWT0\r\n2uUEipYhNp4WTaqHg2KfopfzUIt1M0TJGwSidPWkkcnpb+dDeC1JYd3gy0IejhiJ\r\nOUo67gwaiFiwbKhJUTbBI0ZLV3StxBh6M6MEuabDOiBKDuRSPd3Tk8ZylVYjHA/Z\r\noMFW4cKGHp8t2bVs16DyUuIFFJV4UNtXFoJBGYjq8x2WXFLPXaH//eSgF96AxE1+\r\nG3NwPHu1J0uf5s7LAX669FT/6fNpd7oKsOStmYWVII2smA0RasQjApWXu/ouYFIe\r\nwF1GKRcVzSNjc9lUqVoyhKYDwZ+UBZNgbecJc+szvYWbj1X3cUQkVxAVe9Kvbuuu\r\nBbKBghZkt0o2c/asIPTVcMLFRCYXauLlpNMQqxtdPWzyx/mKPe2r4qo+7Yoq6/zh\r\n1QVsqHfNd3TslOWanH2iOrylPPHCZ5eph+RHkPxE/lYJOqZgZnpcW5wusAyqaPfX\r\niSh8aoHDXa9VT/rMB5wz7EJppv75YLUaHHqnD7oJEMqSlxhDYy62TDWjVAPv2ITF\r\n3z9pfjAXDitGKqpwM2re+vCR0Lg3KMBhE3zL4Z8QPRK4I7Oekb6WiK90TlBc9xdr\r\nhC3dDu+lWPkhU7f1wEiiminVxPQLMNfnBSErwMqC9LSHXuBcnqYWhMgl9auN/oqf\r\nbAyFYTWY+rk+B8sAJU5aTlwC5GavRzCAZFPHCRmOLVrLCD0MPS1x/cBQ/pL/yiID\r\nMFBLuxnb4GC9ZQZA7x63rlHAXtjEj5VDZcEJiJWsHapTksscjC0r2IRADSw/xWUp\r\nil+7Z2ajBNAQShECeIOkA3NLjaykDAMhOcZbg2Lw3V+EcF/kG6DJbvpombySOuys\r\n/EwDC2fVrxiEt7dPWmhlCu7wwyyMX0cjYikAQAGw1Xa5UQhdss3ivAuBSvhmFAhh\r\nyMvU8Lxtd01NT/hHMNcYUo/zs0dUZxibfI8zvRemGwLxy0pIHoi+77Lv6ejtkQlK\r\nlIAWew6Slyk2sFoDq/U/f+AEIodsNrHw2uljkzfw3tFUrm204s8L0woN3nSXuzLZ\r\nmGn56Ep7tk+K88eTCz5lW5gc3AyGlr1YK6/iC3wwre8P72kblwDKOKBrHogMo/Ed\r\n9cpldxBtLBbMohJ29N0V9fQ=\r\n=cI14\r\n-----END PGP MESSAGE-----\r\n\r\n--Apple-Mail=_FE60F127-D74F-4377-93CC-56430132A178--",
uid: 804
}, {
description: "Apple Mail (no attachment): Encrypted and signed",
description: "Apple Mail (no attachment - PGP/MIME): Encrypted and signed",
raw: "Content-Type: multipart/encrypted; boundary=\"Apple-Mail=_2E255D9C-89D7-4F15-81B9-0821710B1B04\"; protocol=\"application/pgp-encrypted\";\r\nSubject: test12\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 \\(1878.2\\))\r\nX-Pgp-Agent: GPGMail (null)\r\nFrom: safewithme <safewithme.testuser@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:22:54 +0200\r\nContent-Transfer-Encoding: 7bit\r\nMessage-Id: <1995DC5D-366B-427A-8420-C0E6F93FCAE6@gmail.com>\r\nContent-Description: OpenPGP encrypted message\r\nTo: safewithme.testuser@gmail.com\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\nThis is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)\r\n--Apple-Mail=_2E255D9C-89D7-4F15-81B9-0821710B1B04\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: application/pgp-encrypted\r\nContent-Description: PGP/MIME Versions Identification\r\n\r\nVersion: 1\r\n\r\n--Apple-Mail=_2E255D9C-89D7-4F15-81B9-0821710B1B04\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline;\r\n\tfilename=encrypted.asc\r\nContent-Type: application/octet-stream;\r\n\tname=encrypted.asc\r\nContent-Description: OpenPGP encrypted message\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nComment: GPGTools - https://gpgtools.org\r\n\r\nhQEMA9f7k/zfv8I8AQf/SN6kzGCE5Ht0OHBofUocR3CaADSI1ricHiWLzk74FT+6\r\nB7wZcqNR2wI35nwYR2qGjJdLHQP321b6viA0SH5w2drDnfuOAvdGDv/9dK0X4c2z\r\n4WZLu7AndKQ9HlpwYTaXguplfBx77QjwaS43x8otIQgI/D9dQ+kIlDgzj4hm4TBn\r\nh171NaXKs3cw93v1h9lM66kzkta30A3sORdtAPNQ7bEYKYlQhCa4KHXXclRdjccQ\r\nfnAx5oBGycbpRvgn88VkmUl7+THNoCtFDvh1gG/XTGaxPH0XWYv5D9ojH9NyPD8s\r\nE2rwU93cMsuesIQcxBCax3DjoWrPp1qAsd4o0JP28snpZZVwIxigO5CE05nkUyYS\r\nHBettFNr9JL2eZox4+FRmY0NV8R0CqSqo+cYy6yu5UlZtJbN4+4Uk6xfXE9ApyWG\r\nt+BFIx9QpiuXFr4z/iFZ/QJ2i8f+teQyFDGA33Kr0y+PD1AZcyUy8m9eWhZHebl2\r\ntEqWqNINHoPr27My8+tG7HDBWmyBPuTyGEwdg93N6psb124NSZOe8pfYLPSyWFnb\r\nQ4bIw8hGfoPkzqjE4tDZ7YtFLZJvlSxyQViTxeFJ3A6wOq+3bebIvmRqV6mTdbi4\r\nNiqFNA3aSjUid1z8L7MbtpPVSdwmwXUrpRiM5Rr17CqcaPnmRUlxSSMucX5PLqQv\r\nKu1PEPzvyqE+Hqnaxi2gMaYj0+TRUAKXLJrjlWDRpIKp3K8Ic5dFdA8KUHqRBz7N\r\nUh/LOBPPWZNriT9vNrPdvjuiGiRcL3WGU4bu301U4g6gpUEHKNEcbXfyuCz6Iwh6\r\nhKfKiBLTHT//jr5TQKzs0cwyPCsOmG08bbgrnj59KoF6apuIXrw9RRvYVumChRx3\r\nvZIPlOF7g/2ncF1kHq+ChVu0zO0syti9efIV7vbpgZ385AdnRUHH3Eqk0lnYB3JK\r\nFuktWoFZB7VppOp8up9mznX4E5RRGJBAIdj61soZ4bHNSZeBbDECiwxW37xRTtd9\r\nUi/FVZzbGC1+gxbITJYSeWvAB9hmDHiO5fbCdohb3Wn8Z8dWb4FE/tx/TVpwmLat\r\n0uaHlteA6QLVPbQT1EaKyZhsNW9uqJ2LTEtyfe0JfNAXduF6phEyA2ZRBS8b82Jb\r\najK/8pFjqkm25q2aTPkFeVzWMYL/1w9EEPbFuqVXmD153NElebL4odAPE3ZCHpZs\r\nxgbcLw6zAYnQgNal8papOHrghs37iej++gBrzDbAf6Mj09wqTv7xESxpqH9hhSEs\r\nqcoEg2l5U9pSZ3oHq9z783EONSfDXQAl0RE=\r\n=Wsnw\r\n-----END PGP MESSAGE-----\r\n\r\n--Apple-Mail=_2E255D9C-89D7-4F15-81B9-0821710B1B04--",
uid: 805
}, {
description: "Apple Mail (no attachment): Encrypted",
description: "Apple Mail (no attachment - PGP/MIME): Encrypted",
raw: "Content-Type: multipart/encrypted; boundary=\"Apple-Mail=_930898CD-0C01-4F0E-8769-2B6F056DC2CD\"; protocol=\"application/pgp-encrypted\";\r\nSubject: test13\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 \\(1878.2\\))\r\nX-Pgp-Agent: GPGMail (null)\r\nFrom: safewithme <safewithme.testuser@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:23:32 +0200\r\nContent-Transfer-Encoding: 7bit\r\nMessage-Id: <0AF825EB-5923-4F11-B189-A3D8032A6D6C@gmail.com>\r\nContent-Description: OpenPGP encrypted message\r\nTo: safewithme.testuser@gmail.com\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\nThis is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)\r\n--Apple-Mail=_930898CD-0C01-4F0E-8769-2B6F056DC2CD\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: application/pgp-encrypted\r\nContent-Description: PGP/MIME Versions Identification\r\n\r\nVersion: 1\r\n\r\n--Apple-Mail=_930898CD-0C01-4F0E-8769-2B6F056DC2CD\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline;\r\n\tfilename=encrypted.asc\r\nContent-Type: application/octet-stream;\r\n\tname=encrypted.asc\r\nContent-Description: OpenPGP encrypted message\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nComment: GPGTools - https://gpgtools.org\r\n\r\nhQEMA9f7k/zfv8I8AQf/WaCFHXTlBnLbqis/zjpRP7gcOvS8uUT3D77RO8Tbuu/6\r\nrh9AtSf78QLF3ogkDB5jlGkfQOxrPbMMyE9CzC8UPRZy5xdbGsUbv7z3biFfVX8P\r\nBmZSyAXTTduf4ewrp6cy7Mbm/wxSGnSMWW6ut30276izXJsw+SywMhg7dWojJyYs\r\nLWNhs5qQWHDoJdB6j/3T++gtpdE2Tv+hrzXrhskBf/rf3XfZmvi7UmFk0lVGpVXP\r\nyuX0iyyfaj8cV2ubycR79NKUlBp76HSZFBsDEY1Zbb/GJaHG/5lHbixf9klFbdoL\r\nGPF51IbQypL1dlYPffvGz/u3M5ctBvoUK4jgLYWOsMlnbIzD5WpmjmL5e3+cwcJj\r\noCbbtyYBJSuzY/4tmx5DRVAnoN0hWo3nLTfVNweMtKd1jms4FookhVZchxtuJkjy\r\nxPjygCncmf3PNmGARKFxZ05PvHlSPhGQ1YcqDRRpXRU+Cj78OHtbaA==\r\n=Ckmq\r\n-----END PGP MESSAGE-----\r\n\r\n--Apple-Mail=_930898CD-0C01-4F0E-8769-2B6F056DC2CD--",
uid: 806
}, {
@ -81,7 +81,7 @@ define(function(require) {
raw: "From: safewithme <safewithme.testuser@gmail.com>\r\nContent-Type: multipart/signed; boundary=\"Apple-Mail=_D557BC30-CF1E-41FD-8932-E73ED2C124EA\"; protocol=\"application/pgp-signature\"; micalg=pgp-sha512\r\nSubject: test17\r\nMessage-Id: <6B942730-FFE4-476C-980C-FF1ABA0740BD@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:26:11 +0200\r\nTo: safewithme.testuser@gmail.com\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 \\(1878.2\\))\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\n\r\n--Apple-Mail=_D557BC30-CF1E-41FD-8932-E73ED2C124EA\r\nContent-Type: multipart/mixed;\r\n\tboundary=\"Apple-Mail=_6461D724-7906-49CB-BA38-D66A4E146EC3\"\r\n\r\n\r\n--Apple-Mail=_6461D724-7906-49CB-BA38-D66A4E146EC3\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain;\r\n\tcharset=us-ascii\r\n\r\ntest17\r\n\r\n--Apple-Mail=_6461D724-7906-49CB-BA38-D66A4E146EC3\r\nContent-Disposition: attachment;\r\n\tfilename=test.bin\r\nContent-Type: application/macbinary;\r\n\tx-unix-mode=0644;\r\n\tname=\"test.bin\"\r\nContent-Transfer-Encoding: 7bit\r\n\r\ntestattachment\r\n--Apple-Mail=_6461D724-7906-49CB-BA38-D66A4E146EC3\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain;\r\n\tcharset=us-ascii\r\n\r\n\r\n\r\n--Apple-Mail=_6461D724-7906-49CB-BA38-D66A4E146EC3--\r\n\r\n--Apple-Mail=_D557BC30-CF1E-41FD-8932-E73ED2C124EA\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: attachment;\r\n\tfilename=signature.asc\r\nContent-Type: application/pgp-signature;\r\n\tname=signature.asc\r\nContent-Description: Message signed with OpenPGP using GPGMail\r\n\r\n-----BEGIN PGP SIGNATURE-----\r\nComment: GPGTools - https://gpgtools.org\r\n\r\niQEcBAEBCgAGBQJTqH9TAAoJENf7k/zfv8I8ygYH/j6ICLJaxBLNhUvBxuXlZHse\r\nH1Rfg/rtF1UCJdqHRrefIYDTVUu1jiTjH1DKXJdujD+mNGhDUqBkF8vn+Hmu86H4\r\n/E9trGeygCkYZNdug1HINI4+fezGa3D28uDkPeN9LlDZBKBVXuEx+EAGBgJLaPbH\r\n7vdlqDqbwlXCU2JO6uGr4sqcTS0UMZaC0VLhBQyXelGQurjoD8XvamBnt5oRxtEc\r\nvftg7s9FKdErNC3mPoUkhFeQKXUiHACH/TzFUdXTh0K7y2ZXQFVmEg/+jjmoFX4D\r\nKPIvjrlM6FqDwo067tIT+S4WJ5MdcDcZRbyS6QkBuMVbugWeUokf/f8zgHQPnHA=\r\n=pJiW\r\n-----END PGP SIGNATURE-----\r\n\r\n--Apple-Mail=_D557BC30-CF1E-41FD-8932-E73ED2C124EA--",
uid: 807
}, {
description: "Apple Mail (no attachment): Signed",
description: "Apple Mail (no attachment - PGP/MIME): Signed",
raw: "From: safewithme <safewithme.testuser@gmail.com>\r\nContent-Type: multipart/signed; boundary=\"Apple-Mail=_D32A0631-70E5-46E7-8204-7A7D5EF145B1\"; protocol=\"application/pgp-signature\"; micalg=pgp-sha512\r\nSubject: test14\r\nMessage-Id: <ED2509B2-8CA2-4D38-B039-8E37A675FB26@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:24:23 +0200\r\nTo: safewithme.testuser@gmail.com\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 \\(1878.2\\))\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\n\r\n--Apple-Mail=_D32A0631-70E5-46E7-8204-7A7D5EF145B1\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain;\r\n\tcharset=us-ascii\r\n\r\ntest14\r\n\r\n--Apple-Mail=_D32A0631-70E5-46E7-8204-7A7D5EF145B1\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: attachment;\r\n\tfilename=signature.asc\r\nContent-Type: application/pgp-signature;\r\n\tname=signature.asc\r\nContent-Description: Message signed with OpenPGP using GPGMail\r\n\r\n-----BEGIN PGP SIGNATURE-----\r\nComment: GPGTools - https://gpgtools.org\r\n\r\niQEcBAEBCgAGBQJTqH7nAAoJENf7k/zfv8I8crcH/1h2LEOiAddU7tXokMxfA+FT\r\nSPezAU3eUSzlDLIjq+6pFlFXmH+IVQcxx7dbiHekLtDiIweII58KOAHYodadO4Gg\r\ni/wist5rGpysHX1djQ6D/pqvxr8jEwxQ0tyvEkcDzMXcGolUZLQTDRHaCpgJAFrM\r\n525YHJ1UxAzlojq+/92EzI8JdqH+KT56BGCiBHFj6QlWF1OXV4L+mNk1zRMyESjI\r\n0LPYFYrUtBopy/0DvrqAkFFOOS6j6XjPa2Finofv49LqOc4ntpOSs0DwrDPb5Nn3\r\nMlDvsT80Bf+RfQdc8PzTAyN5Puv+XjDET407jVUsfKwEv/aUHRZnNXWAR2G+9xE=\r\n=CGVw\r\n-----END PGP SIGNATURE-----\r\n\r\n--Apple-Mail=_D32A0631-70E5-46E7-8204-7A7D5EF145B1--",
uid: 808
}, {
@ -93,11 +93,11 @@ define(function(require) {
raw: "Message-ID: <53A87DC2.6010102@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:19:30 +0200\r\nFrom: Andris Testbox2 <safewithme.testuser@gmail.com>\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.2.0\r\nMIME-Version: 1.0\r\nTo: safewithme <safewithme.testuser@gmail.com>\r\nSubject: test9\r\nX-Enigmail-Version: 1.6\r\nContent-Type: multipart/encrypted;\r\n protocol=\"application/pgp-encrypted\";\r\n boundary=\"N184DqJgpX0F6MPTPjS0P6IxMgfbap3qD\"\r\n\r\nThis is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)\r\n--N184DqJgpX0F6MPTPjS0P6IxMgfbap3qD\r\nContent-Type: application/pgp-encrypted\r\nContent-Description: PGP/MIME version identification\r\n\r\nVersion: 1\r\n\r\n--N184DqJgpX0F6MPTPjS0P6IxMgfbap3qD\r\nContent-Type: application/octet-stream; name=\"encrypted.asc\"\r\nContent-Description: OpenPGP encrypted message\r\nContent-Disposition: inline; filename=\"encrypted.asc\"\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nVersion: GnuPG v1.4.13 (Darwin)\r\nComment: GPGTools - https://gpgtools.org\r\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\r\n\r\nhQEMA9f7k/zfv8I8AQf5AX+nmpkoDAn7MHFwQZ9ENIOtYRRTY1aakavO0oVuiOWm\r\nerJO+/4ORrtSapkZjp9cnE0Kwuo44fkmbObt+JquHVg4Bcxee3IpViTOx1dV+IPr\r\n/R5zcPp3myk9hqwkpwlCPOUVXmD8YQeLQQfiM90E0+ldF9q1Q4UKW/usmaJQBwWd\r\nWrR9KURfBrh1eqIO927YXIInnhlCl0ZiYwghCeJ7nrfHF7a3ftHuSMJhkywNKGWH\r\nhL7FghCwpmVuHyneB8lJVGz4txwnW51kK05Il46Uab1y9jSutUN+5IVWmRx6m+zt\r\n7aj3Cyd8rAzc9LdP0XEPOe1+cht9GTXXMdj+Kk5758npNB32pMfQ8YSOcIU1luyk\r\nKWE6yG5+7ZWFXrbdXVjXRKXMN31c4Hw0Ccv1kO/viAvthAU3hFZM0cBp+PtiOrxS\r\nynBBi7r2o3xb8NTGGYRq/P0H9Odemj2x6OGbIXS40ApTAGKeNNhHpF5HwaAWuMul\r\n2Pnjdt8x34PiKd/L/TOSAtmQZqkQ3xmYOMpP5XKiCYTBeMMM46Gz4rbTnrJawW5X\r\n8nxvQjJmDzcAByS9bJSNh0a6vF+JbTNbTH7kIjqPUm57zyie2+uBCjg5dIeqZt4l\r\nF85Ai+chMwtUNZ50tEfPhk1opf+HsJ8OfrNEOiA8xCQNL3ZUPnaHkhLAd8bh05zI\r\nyzJOBLwSrFpCMZWkPm1PK6J99M6JH5MJyZxvdQfH/YyhCdqiyCUQc1lObdPBLN/A\r\n/Lb1xUnqppA7yvr6RpWQ+EAUVohknGRhqdL/PxOcCv9GY2DW0dHxUdYbyBzoFj6h\r\nhmzaCIUmhjDGLi4qCxLdn46IKKFtEncMBGgrIQTgDGHXyUaUlEVtWs3I6aRkgYbz\r\no2t3UytJxyMUevCpSBADlHO0Rd1q0MyEsmGKKYoyJSt1NX4C6pmEl3kVJoyvkQWb\r\nbgFBG0KYkx5+UtBGlubYrP2MS2xRQ+6hHCJtIFOfQHcWlUg4jy8mZNVjV+S+zvbV\r\nGjIhjdmvFAvp/sgcwTGmYbh4LpUP/pI+jmIh3Gg8l1PDlh95uSzKJ770m2U8W7ws\r\nNbgG3RdxD0ZocJkeYslvHKid3kf2LIKeH1ADJj/t6rfD/4k31iQeGcNASnDNsel3\r\njbp8HJ9LSm0h0xeWCiOLqa/c6ysXLravA7nBC1XHKE3u4tcIjcZEYt6Z\r\n=qwkL\r\n-----END PGP MESSAGE-----\r\n\r\n--N184DqJgpX0F6MPTPjS0P6IxMgfbap3qD--",
uid: 810
}, {
description: "Thunderbird (no attachment): Encrypted and signed",
description: "Thunderbird (no attachment - PGP/INLINE): Encrypted and signed",
raw: "Message-ID: <53A8796A.6000502@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:00:58 +0200\r\nFrom: Andris Testbox2 <safewithme.testuser@gmail.com>\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.2.0\r\nMIME-Version: 1.0\r\nTo: safewithme.testuser@gmail.com\r\nSubject: test4\r\nX-Enigmail-Version: 1.6\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nCharset: ISO-8859-1\r\nVersion: GnuPG v1.4.13 (Darwin)\r\nComment: GPGTools - https://gpgtools.org\r\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\r\n\r\nhQEMA9f7k/zfv8I8AQf8CCwYxQuhh9kAd4Vz8nUP8YLScfexq8juAawc5bsq3sf5\r\nMl1E6zzM8d0M8ultmL+Y2RRYX82/kEvc1c3bWNJNSagwqxlD54dToXTraGkE+hbF\r\nlMnsAq/jpcsXH0G9oFPwMi5NMWKbZQIUdsi3Iszx8x1WEWcV9XE4C0xg0LfN66vr\r\n1ykTTcg+wv4XmxvljvgA+VT6HvS1jqE/NrfseDtQJNIs42sfylgJF0neOfkrjrn/\r\nDljslmd1WgbDjbAk+hzT+8zmRfCLK2GhRtsRskdGGSzDiYhAc1qLU6GtVuhig088\r\nF3Gk1Sqgnffi1/X16j2sN5URjteaXnvHIJwGypuoLsnAjmQyh0vVs8hVb4jZw+aR\r\n8atbrYPLCN8VnIRK+4E9v45aGef3U8Dul3FXx06s6UZVGTaPHOFIkFJhfA4Vswh5\r\n6n7A5kAhGx9VgChOyjaGpBdpFuhsD1fpixhVlTCAmIanJwYi5Cvz2nfN8QOIamsc\r\ndM0bE0utru2YCmmzVgVjDr4xtM7tAPfresDnEXt/eqRiIFntT/tD8yke4/vTMS3s\r\nJVMhFrlm14BohvRnaF0sUeFiMSbDL1ox8pmtRUdIFY3mhq+R9XUpFb7ktOd6husG\r\nthMDtT+1Tb7/W2rHFx7nJIQtjKbgM79/Pson+O2LzX6fY7qeQKnUX9dBb15t5e94\r\n78yazU5T1JmMHA+Szzu6OMy3eHkkOqxsst62nMXgrgGk7NhUNl+3oP5k/aT6iqA2\r\n3deWy5YfwtC0hRHWnT6zweJJohOVwrQQJ9oxTSi3iJ0=3D\r\n=3D9EeZ\r\n-----END PGP MESSAGE-----\r\n\r\n",
uid: 811
}, {
description: "Thunderbird (no attachment): Encrypted",
description: "Thunderbird (no attachment - PGP/INLINE): Encrypted",
raw: "Message-ID: <53A87AD7.9090109@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:07:03 +0200\r\nFrom: Andris Testbox2 <safewithme.testuser@gmail.com>\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.2.0\r\nMIME-Version: 1.0\r\nTo: safewithme.testuser@gmail.com\r\nSubject: test5\r\nX-Enigmail-Version: 1.6\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nCharset: ISO-8859-1\r\nVersion: GnuPG v1.4.13 (Darwin)\r\nComment: GPGTools - https://gpgtools.org\r\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\r\n\r\nhQEMA9f7k/zfv8I8AQf+KmR4WIpBMlhm7HFxWEEmRAezEaKWX1X9oDCMBMC/WTPa\r\nzegDeysvFsh7SvLDZngm+hPDxCWIh+h/6EZaWGuQBJKcyglTncZEA3T5vz+IRJoP\r\ngFUVZ9YLaT58DAzLOpg8noNAEp0+E+cfDsVvhBI8Hzx7VRt1/msO+RWWEZOnD1xw\r\nD5iJ0AfONzAcfHc0jJosz8/iUkWBexBwtG+dm4mdyE+X6g30zHY6afa5/E7LvfXd\r\nZUFr+pgHa1eQYKtqtyeZPrli0zSHtFMOdr8eDkp89/MZgQbbYHEaLTjWUzDsogDT\r\n3FzTbm4t4fPolEHgZFnDwCrqPTRZAN999zscD12CiMkdTc0iVy4mH50QgeF/m/w7\r\n7ewbgh38TN8YbXvaA6A=3D\r\n=3Di2Il\r\n-----END PGP MESSAGE-----\r\n\r\n",
uid: 812
}, {
@ -109,9 +109,13 @@ define(function(require) {
raw: "Message-ID: <53A87E4B.50702@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:21:47 +0200\r\nFrom: Andris Testbox2 <safewithme.testuser@gmail.com>\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.2.0\r\nMIME-Version: 1.0\r\nTo: safewithme <safewithme.testuser@gmail.com>\r\nSubject: test11\r\nX-Enigmail-Version: 1.6\r\nContent-Type: multipart/signed; micalg=pgp-sha512;\r\n protocol=\"application/pgp-signature\";\r\n boundary=\"LldNQubkCiWQwPKXrfghi6DLbotCLEBuX\"\r\n\r\nThis is an OpenPGP/MIME signed message (RFC 4880 and 3156)\r\n--LldNQubkCiWQwPKXrfghi6DLbotCLEBuX\r\nContent-Type: multipart/mixed;\r\n boundary=\"------------070307080002050009010403\"\r\n\r\nThis is a multi-part message in MIME format.\r\n--------------070307080002050009010403\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\ntest11\r\n\r\n--------------070307080002050009010403\r\nContent-Type: application/macbinary;\r\n name=\"test.bin\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"test.bin\"\r\n\r\ndGVzdGF0dGFjaG1lbnQ=\r\n--------------070307080002050009010403--\r\n\r\n--LldNQubkCiWQwPKXrfghi6DLbotCLEBuX\r\nContent-Type: application/pgp-signature; name=\"signature.asc\"\r\nContent-Description: OpenPGP digital signature\r\nContent-Disposition: attachment; filename=\"signature.asc\"\r\n\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: GnuPG v1.4.13 (Darwin)\r\nComment: GPGTools - https://gpgtools.org\r\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\r\n\r\niQEcBAEBCgAGBQJTqH5OAAoJENf7k/zfv8I8oFoH/R6EFTw2CYUQoOKSAQstWIHp\r\nfVVseLOkFbByUV5eLuGVBNI3DM4GQ6C7dGntKAn34a1iTGcAIZH+fIhaZ2WtNdtA\r\nR+Ijn8xDjbF/BWvcTBOaRvgw9b8viPxhkVYa3PioHYz6krt/LmFqFdp/phWZcqR4\r\njzWMX55h4FOw3YBNGiz2NuIg+iGrFRWPYgd8NVUmJKReZHs8C/6HGz7F4/A24k6Y\r\n7xms9D6Er+MhspSl+1dlRdHjtXiRqC5Ld1hi2KBKc6YzgOLpVw5l9sffbnH+aRG4\r\ndH+2J5U3elqBDK1i3GyG8ixLSB0FGW9+lhYNosZne2xy8SbQKdgsnTBnWSGevP0=\r\n=xiih\r\n-----END PGP SIGNATURE-----\r\n\r\n--LldNQubkCiWQwPKXrfghi6DLbotCLEBuX--",
uid: 814
}, {
description: "Thunderbird (no attachment): Signed",
description: "Thunderbird (no attachment - PGP/INLINE): Signed",
raw: "Message-ID: <53A87B12.9010706@gmail.com>\r\nDate: Mon, 23 Jun 2014 21:08:02 +0200\r\nFrom: Andris Testbox2 <safewithme.testuser@gmail.com>\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.2.0\r\nMIME-Version: 1.0\r\nTo: safewithme.testuser@gmail.com\r\nSubject: test6\r\nX-Enigmail-Version: 1.6\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Transfer-Encoding: 7bit\r\n\r\n\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: SHA512\r\n\r\ntest6\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: GnuPG v1.4.13 (Darwin)\r\nComment: GPGTools - https://gpgtools.org\r\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\r\n\r\niQEcBAEBCgAGBQJTqHsSAAoJENf7k/zfv8I8wz4H/RWo1qJvvJtMl7GyqGGbaByX\r\n/D7/yWJzMdE0Y7J/tHIexQ/sZnmcDlHG0mtJKgI7EOh2EyV+r+78vF71Mlc+bg8g\r\n3B4TKyp0QU1Pb6SETG//FtKrU7SnkjKujHvRMpzcOcm0ZLBDpmftyWLvp9Dg3KOF\r\n5sMBGpJRn1pqX2DxXZtc1rYOmSAaxFI5jewPws0DCDkLDGp9gLyusNeDHkmAT4AG\r\nDqsDPQvW0R4Sy7aQFT7GjrdnCiLyikynkocUpR95fDnjHJ6Xbyj2Yj9/ofewPQ//\r\nMq39sIYbcqlDBAhsOlii3ekdzLS4xEOkvtFoD4pufyLj3pYY60FG4bPygcccYkI=\r\n=IkRV\r\n-----END PGP SIGNATURE-----\r\n",
uid: 815
}, {
description: "Mailvelope (no attachment - PGP/INLINE): encrypted and signed",
raw: "MIME-Version: 1.0\r\nReceived: by 10.195.18.8 with HTTP; Fri, 4 Jul 2014 06:58:43 -0700 (PDT)\r\nDate: Fri, 4 Jul 2014 15:58:43 +0200\r\nDelivered-To: safewithme.testuser@gmail.com\r\nMessage-ID: <CAAGARGwr94CXUuC_brPCMu58KtTgOJwr9V1jHafjKkPx3Xn0dg@mail.gmail.com>\r\nSubject: \r\nFrom: safewithme testuser <safewithme.testuser@gmail.com>\r\nTo: safewithme testuser <safewithme.testuser@gmail.com>\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nVersion: Mailvelope v0.9.0\r\nComment: Email security by Mailvelope - https://www.mailvelope.com\r\n\r\nwcBMA9f7k/zfv8I8AQf9F/Gm4HqJ/RlU2w+qIbJ4Va2PFR04OITlZIuUAWms\r\nPhPo4cGFbgxQnBzD7goswvNLXfEo4Q6/wxqT/wuwLGQdQJDoEduQxO5p77c1\r\n+dw/sa+pcr4jdwjebjV45NODVGDxgSF+YIwwKN3XXF6VqcisLLYBONYTHIU8\r\nKdTYR+R8SXSpMGISLUyyeY3Jaw5Et8cEoo0a1z8Fx04Ycv2Gw9Io0NVEqxYR\r\n86HUCLsOSARZC1aJ6hf9wheB528o0wuM6ESJ1LWnMWudyrkMjAiW6AiH89G8\r\npykTuYvc/GH3q7eEKNtY5khuZwi2Z7VJFrTeaEt4cb6HxlUlECudYw79uAHu\r\nt9JGATfaNeUpZV2xLEPBhsW5VrY4nDpbWVLp9stAKNFEiH6Ai/rgNwJ2A9Xr\r\nnWAji8YlIOOdO1iNVaYEQWEW1s5Hw5rYB83LKg==\r\n=ungD\r\n-----END PGP MESSAGE-----\r\n",
uid: 816
}];
imapFolders = {
@ -471,7 +475,7 @@ define(function(require) {
};
});
it.skip('should parse Apple Mail (attachment - PGP/MIME): Encrypted and signed', function(done) {
it('should parse Apple Mail (attachment - PGP/MIME): Encrypted and signed', function(done) {
emailDao.onIncomingMessage = function(messages) {
emailDao.getBody({
folder: currentFolder,
@ -494,7 +498,7 @@ define(function(require) {
};
});
it.skip('should parse Apple Mail (no attachment): Encrypted and signed', function(done) {
it('should parse Apple Mail (no attachment): Encrypted and signed', function(done) {
emailDao.onIncomingMessage = function(messages) {
emailDao.getBody({
folder: currentFolder,
@ -554,7 +558,7 @@ define(function(require) {
expect(err).to.not.exist;
expect(message.encrypted).to.be.false;
expect(message.signed).to.be.true;
//TODO (check plaintext signatures): expect(message.signaturesValid).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.attachments.length).to.equal(1);
expect(message.body).to.equal('test17\n');
done();
@ -577,7 +581,7 @@ define(function(require) {
expect(err).to.not.exist;
expect(message.encrypted).to.be.false;
expect(message.signed).to.be.true;
//TODO (check plaintext signatures): expect(message.signaturesValid).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.attachments.length).to.equal(0);
expect(message.body).to.equal('test14');
done();
@ -715,7 +719,7 @@ define(function(require) {
expect(err).to.not.exist;
expect(message.encrypted).to.be.false;
expect(message.signed).to.be.true;
//TODO (check plaintext signatures): expect(message.signaturesValid).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.attachments.length).to.equal(1);
expect(message.body).to.equal('test11');
done();
@ -724,7 +728,7 @@ define(function(require) {
};
});
it('should parse Thunderbird (no attachment): Signed w/ PGP/inline', function(done) {
it('should parse Thunderbird (no attachment): Signed w/ PGP/INLINE', function(done) {
emailDao.onIncomingMessage = function(messages) {
emailDao.getBody({
folder: currentFolder,
@ -738,7 +742,7 @@ define(function(require) {
expect(err).to.not.exist;
expect(message.encrypted).to.be.false;
expect(message.signed).to.be.true;
//TODO (check plaintext signatures): expect(message.signaturesValid).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.attachments.length).to.equal(0);
expect(message.body).to.equal('test6');
done();
@ -746,13 +750,33 @@ define(function(require) {
});
};
});
it('should parse Mailvelope: encrypted (unsigned) w/PGP/INLINE', function(done) {
emailDao.onIncomingMessage = function(messages) {
emailDao.getBody({
folder: currentFolder,
message: messages[22]
}, function(err, message) {
expect(err).to.not.exist;
emailDao.decryptBody({
message: message,
folder: currentFolder
}, function(err) {
expect(err).to.not.exist;
expect(message.encrypted).to.be.true;
expect(message.signed).to.be.false;
expect(message.signaturesValid).to.be.undefined;
expect(message.attachments.length).to.equal(0);
expect(message.body).to.equal('this is a test');
done();
});
});
};
});
});
});
describe('SMTP Tests', function() {
// phantomjs is just sooo slow
it('should send a plaintext message', function(done) {
sinon.stub(smtpServer, 'onmail', function(mail) {
expect(mail.from).to.equal(testAccount.user);

View File

@ -909,6 +909,62 @@ define(function(require) {
expect(message.loadingBody).to.be.true;
});
it('should read a signed pgp/mime from the device', function(done) {
var message, signed, pt, signedMimeTree, signature;
pt = 'bender is great!';
signed = 'omg signed text';
signedMimeTree = 'trallalalalala';
signature = 'ugauga';
message = {
uid: uid,
signed: true,
from: [{
address: 'asdasdasd'
}]
};
localListStub.withArgs({
folder: inboxFolder,
uid: uid
}).yieldsAsync(null, [{
bodyParts: [{
type: 'text',
content: pt
}, {
type: 'signed',
content: [{
type: 'text',
content: signed
}],
signedMessage: signedMimeTree,
signature: signature
}]
}]);
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true);
dao.getBody({
message: message,
folder: inboxFolder
}, function(err, msg) {
expect(err).to.not.exist;
expect(msg).to.equal(message);
expect(msg.body).to.equal(signed);
expect(message.signed).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.loadingBody).to.be.false;
expect(localListStub.calledOnce).to.be.true;
expect(pgpStub.verifySignedMessage.calledOnce).to.be.true;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
done();
});
expect(message.loadingBody).to.be.true;
});
it('should read a pgp/inline from the device', function(done) {
var message, ct, pt;
@ -951,6 +1007,47 @@ define(function(require) {
expect(message.loadingBody).to.be.true;
});
it('should read a signed pgp/inline from the device', function(done) {
var message, pt;
pt = '-----BEGIN PGP SIGNED MESSAGE-----\n\ntest6\n-----BEGIN PGP SIGNATURE----------END PGP SIGNATURE-----';
message = {
uid: uid,
from: [{
address: 'asdasdasd'
}]
};
localListStub.yieldsAsync(null, [{
bodyParts: [{
type: 'text',
content: pt
}]
}]);
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.verifyClearSignedMessage.withArgs(pt, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true);
dao.getBody({
message: message,
folder: inboxFolder
}, function(err, msg) {
expect(err).to.not.exist;
expect(msg).to.equal(message);
expect(msg.body).to.equal('test6');
expect(message.signed).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.loadingBody).to.be.false;
expect(localListStub.calledOnce).to.be.true;
expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
done();
});
expect(message.loadingBody).to.be.true;
});
it('should stream from imap and set plain text body', function(done) {
var message, body, uid;
@ -1260,6 +1357,8 @@ define(function(require) {
expect(error).to.not.exist;
expect(msg).to.equal(message);
expect(message.decrypted).to.be.true;
expect(message.signed).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.body).to.equal(parsed);
expect(message.decryptingBody).to.be.false;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
@ -1272,6 +1371,71 @@ define(function(require) {
expect(message.decryptingBody).to.be.true;
});
it('decrypt a pgp/mime message with inner signature', function(done) {
var message, ct, pt, parsed, signed, signedMimeTree, signature;
pt = 'bender is great';
ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----';
signedMimeTree = 'trallalalalala';
signature = 'ugauga';
signed = 'omg signed text';
parsed = 'bender! bender! bender!';
message = {
from: [{
address: 'asdasdasd'
}],
body: ct,
encrypted: true,
bodyParts: [{
type: 'encrypted',
content: ct
}]
};
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, undefined);
pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true);
parseStub.withArgs({
bodyParts: [{
type: 'encrypted',
content: ct,
raw: pt
}]
}).yieldsAsync(null, [{
type: 'encrypted',
content: [{
type: 'signed',
content: [{
type: 'text',
content: signed
}],
signedMessage: signedMimeTree,
signature: signature
}]
}]);
dao.decryptBody({
message: message
}, function(error, msg) {
expect(error).to.not.exist;
expect(msg).to.equal(message);
expect(message.decrypted).to.be.true;
expect(message.body).to.equal(signed);
expect(message.signed).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(message.decryptingBody).to.be.false;
expect(keychainStub.getReceiverPublicKey.calledTwice).to.be.true;
expect(pgpStub.decrypt.calledOnce).to.be.true;
expect(pgpStub.verifySignedMessage.calledOnce).to.be.true;
expect(parseStub.calledOnce).to.be.true;
done();
});
expect(message.decryptingBody).to.be.true;
});
it('decrypt a pgp/inline message', function(done) {
var message, ct, pt;
@ -1302,6 +1466,8 @@ define(function(require) {
expect(message.decrypted).to.be.true;
expect(message.body).to.equal(pt);
expect(message.decryptingBody).to.be.false;
expect(message.signed).to.be.true;
expect(message.signaturesValid).to.be.true;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(pgpStub.decrypt.calledOnce).to.be.true;
expect(parseStub.called).to.be.false;
@ -1608,6 +1774,90 @@ define(function(require) {
describe('internal API', function() {
describe('#_checkSignatures', function() {
it('should check signatures in clearsigned message', function(done) {
var message = {
from: [{
address: 'asdasdasd'
}],
clearSignedMessage: 'trallalalalala'
};
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.verifyClearSignedMessage.withArgs(message.clearSignedMessage, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true);
dao._checkSignatures(message, function(error, signaturesValid) {
expect(error).to.not.exist;
expect(signaturesValid).to.be.true;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true;
done();
});
});
it('should check signatures in pgp/mime signed message', function(done) {
var message = {
from: [{
address: 'asdasdasd'
}],
signedMessage: 'trallalalalala',
signature: 'ugauga'
};
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.verifySignedMessage.withArgs(message.signedMessage, message.signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true);
dao._checkSignatures(message, function(error, signaturesValid) {
expect(error).to.not.exist;
expect(signaturesValid).to.be.true;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(pgpStub.verifySignedMessage.calledOnce).to.be.true;
done();
});
});
it('should error while checking signatures', function(done) {
var message = {
from: [{
address: 'asdasdasd'
}],
signedMessage: 'trallalalalala',
signature: 'ugauga'
};
keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey);
pgpStub.verifySignedMessage.yieldsAsync(new Error());
dao._checkSignatures(message, function(error, signaturesValid) {
expect(error).to.exist;
expect(signaturesValid).to.not.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(pgpStub.verifySignedMessage.calledOnce).to.be.true;
done();
});
});
it('should error while fetching public key', function(done) {
var message = {
from: [{
address: 'asdasdasd'
}],
signedMessage: 'trallalalalala',
signature: 'ugauga'
};
keychainStub.getReceiverPublicKey.yieldsAsync(new Error());
dao._checkSignatures(message, function(error, signaturesValid) {
expect(error).to.exist;
expect(signaturesValid).to.not.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(pgpStub.verifySignedMessage.called).to.be.false;
done();
});
});
});
describe('#_initFoldersFromDisk', function() {
beforeEach(function() {
sinon.stub(dao, 'refreshFolder');

View File

@ -203,6 +203,7 @@ define(function(require) {
'> \n' +
'> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' +
'> > secret 3';
var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
beforeEach(function(done) {
pgp.importKeys({
@ -297,7 +298,6 @@ define(function(require) {
describe('Decrypt and verify', function() {
var ciphertext;
var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
beforeEach(function(done) {
pgp.encrypt(message, [pubkey], function(err, ct) {
@ -355,7 +355,70 @@ define(function(require) {
});
});
describe('Verify clearsigned message', function() {
var clearsigned;
beforeEach(function() {
clearsigned = openpgp.signClearMessage(pgp._privateKey, 'this is a clearsigned message');
});
it('should work', function(done) {
pgp.verifyClearSignedMessage(clearsigned, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifyClearSignedMessage(clearsigned.replace('clearsigned', 'invalid'), pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it.skip('should be null for wrong public key', function(done) {
pgp.verifyClearSignedMessage(clearsigned, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
});
});
});
describe('Verify detached signature', function() {
var signedMessage, signature;
beforeEach(function() {
signedMessage = 'this is a signed message';
var clearsigned = openpgp.signClearMessage(pgp._privateKey, signedMessage);
var signatureHeader = '-----BEGIN PGP SIGNATURE-----';
signature = signatureHeader + clearsigned.split(signatureHeader).pop();
});
it('should work', function(done) {
pgp.verifySignedMessage(signedMessage, signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifySignedMessage(signedMessage.replace('signed', 'invalid'), signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it('should be null for wrong public key', function(done) {
pgp.verifySignedMessage(signedMessage, signature, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
});
});
});
});
});
});