mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-11-24 14:35:51 +00:00
Generate cleartext signed messages with consistent LF newlines
Instead of generating CRLF newlines in the signed data and LF newlines in the surrounding armor framing, consistently generate LF newlines.
This commit is contained in:
parent
0a92baf8ba
commit
364eb1ee18
@ -36,8 +36,8 @@ export class CleartextMessage {
|
|||||||
* @param {Signature} signature - The detached signature or an empty signature for unsigned messages
|
* @param {Signature} signature - The detached signature or an empty signature for unsigned messages
|
||||||
*/
|
*/
|
||||||
constructor(text, signature) {
|
constructor(text, signature) {
|
||||||
// remove trailing whitespace and normalize EOL to canonical form <CR><LF>
|
// remove trailing whitespace from each line
|
||||||
this.text = util.removeTrailingSpaces(text).replace(/\r?\n/g, '\r\n');
|
this.text = util.removeTrailingSpaces(text);
|
||||||
if (signature && !(signature instanceof Signature)) {
|
if (signature && !(signature instanceof Signature)) {
|
||||||
throw new Error('Invalid signature input');
|
throw new Error('Invalid signature input');
|
||||||
}
|
}
|
||||||
@ -73,7 +73,8 @@ export class CleartextMessage {
|
|||||||
*/
|
*/
|
||||||
async sign(signingKeys, recipientKeys = [], signature = null, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], notations = [], config = defaultConfig) {
|
async sign(signingKeys, recipientKeys = [], signature = null, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], notations = [], config = defaultConfig) {
|
||||||
const literalDataPacket = new LiteralDataPacket();
|
const literalDataPacket = new LiteralDataPacket();
|
||||||
literalDataPacket.setText(this.text);
|
// normalize EOL to canonical form <CR><LF>
|
||||||
|
literalDataPacket.setText(this.text.replace(/\n/g, '\r\n'));
|
||||||
const newSignature = new Signature(await createSignaturePackets(literalDataPacket, signingKeys, recipientKeys, signature, signingKeyIDs, date, signingUserIDs, recipientUserIDs, notations, true, config));
|
const newSignature = new Signature(await createSignaturePackets(literalDataPacket, signingKeys, recipientKeys, signature, signingKeyIDs, date, signingUserIDs, recipientUserIDs, notations, true, config));
|
||||||
return new CleartextMessage(this.text, newSignature);
|
return new CleartextMessage(this.text, newSignature);
|
||||||
}
|
}
|
||||||
@ -93,8 +94,8 @@ export class CleartextMessage {
|
|||||||
verify(keys, date = new Date(), config = defaultConfig) {
|
verify(keys, date = new Date(), config = defaultConfig) {
|
||||||
const signatureList = this.signature.packets.filterByTag(enums.packet.signature); // drop UnparsablePackets
|
const signatureList = this.signature.packets.filterByTag(enums.packet.signature); // drop UnparsablePackets
|
||||||
const literalDataPacket = new LiteralDataPacket();
|
const literalDataPacket = new LiteralDataPacket();
|
||||||
// we assume that cleartext signature is generated based on UTF8 cleartext
|
// cleartext signatures should be generated over UTF8 cleartext with canonical newlines
|
||||||
literalDataPacket.setText(this.text);
|
literalDataPacket.setText(this.text.replace(/\n/g, '\r\n'));
|
||||||
return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, config);
|
return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,8 +104,7 @@ export class CleartextMessage {
|
|||||||
* @returns {String} Cleartext of message.
|
* @returns {String} Cleartext of message.
|
||||||
*/
|
*/
|
||||||
getText() {
|
getText() {
|
||||||
// normalize end of line to \n
|
return this.text;
|
||||||
return this.text.replace(/\r\n/g, '\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -272,7 +272,7 @@ export function unarmor(input) {
|
|||||||
// Reverse dash-escaping for msg
|
// Reverse dash-escaping for msg
|
||||||
text.push(line.replace(/^- /, ''));
|
text.push(line.replace(/^- /, ''));
|
||||||
} else {
|
} else {
|
||||||
text = text.join('\r\n');
|
text = text.join('\n');
|
||||||
textDone = true;
|
textDone = true;
|
||||||
verifyHeaders(lastHeaders);
|
verifyHeaders(lastHeaders);
|
||||||
lastHeaders = [];
|
lastHeaders = [];
|
||||||
|
|||||||
@ -252,7 +252,7 @@ export default () => describe('ASCII armor', function() {
|
|||||||
it('Do not filter blank lines after header', async function () {
|
it('Do not filter blank lines after header', async function () {
|
||||||
let msg = getArmor(['Hash: SHA1', '']);
|
let msg = getArmor(['Hash: SHA1', '']);
|
||||||
msg = await openpgp.readCleartextMessage({ cleartextMessage: msg });
|
msg = await openpgp.readCleartextMessage({ cleartextMessage: msg });
|
||||||
expect(msg.text).to.equal('\r\nsign this');
|
expect(msg.getText()).to.equal('\nsign this');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Selectively output CRC checksum', async function () {
|
it('Selectively output CRC checksum', async function () {
|
||||||
@ -353,9 +353,39 @@ NJCB6+LWtabSoVIjNVgKwyKqyTLaESNwC2ogZwkdE8qPGiDFEHo4Gg9zuRof
|
|||||||
).to.equal(
|
).to.equal(
|
||||||
pubKey
|
pubKey
|
||||||
.replace('\n-', '-')
|
.replace('\n-', '-')
|
||||||
.replace(/\n\r/g, '\n')
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Armored messages use LF newlines', async function () {
|
||||||
|
const usesLF = armoredData => {
|
||||||
|
return !armoredData.includes('\r');
|
||||||
|
};
|
||||||
|
|
||||||
|
const { privateKey: v4Key } = await openpgp.generateKey({ userIDs: { email: 'v4@armor.test' }, format: 'object' });
|
||||||
|
expect(usesLF(v4Key.armor())).to.be.true;
|
||||||
|
const { privateKey: v6Key } = await openpgp.generateKey({ userIDs: { email: 'v6@armor.test' }, config: { v6Keys: true, aeadProtect: true }, format: 'object' });
|
||||||
|
expect(usesLF(v6Key.armor())).to.be.true;
|
||||||
|
|
||||||
|
const messageWithSEIPDv1 = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: v4Key });
|
||||||
|
expect(usesLF(messageWithSEIPDv1)).to.be.true;
|
||||||
|
const messageWithSEIPDv2 = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: v6Key });
|
||||||
|
expect(usesLF(messageWithSEIPDv2)).to.be.true;
|
||||||
|
|
||||||
|
const signatureV4V6 = await openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: [v4Key, v6Key] });
|
||||||
|
expect(usesLF(signatureV4V6)).to.be.true;
|
||||||
|
const signatureV6 = await openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: v6Key });
|
||||||
|
expect(usesLF(signatureV6)).to.be.true;
|
||||||
|
|
||||||
|
const detachedSignatureV4V6 = await openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: [v4Key, v6Key], detached: true });
|
||||||
|
expect(usesLF(detachedSignatureV4V6)).to.be.true;
|
||||||
|
const detachedSignatureV6 = await openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: v6Key, detached: true });
|
||||||
|
expect(usesLF(detachedSignatureV6)).to.be.true;
|
||||||
|
|
||||||
|
const cleartextSignatureV4V6 = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'test' }), signingKeys: [v4Key, v6Key] });
|
||||||
|
expect(usesLF(cleartextSignatureV4V6)).to.be.true;
|
||||||
|
const cleartextSignatureV6 = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'test' }), signingKeys: v6Key });
|
||||||
|
expect(usesLF(cleartextSignatureV6)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user