From 3e808c15788cb273d5f9f065a4c9cf912de83ac6 Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Thu, 18 Mar 2021 17:17:39 +0100 Subject: [PATCH] Drop support for verification of detached cleartext signatures (#1265) (Also, use turnstyle to avoid CI browserstack tasks running in parallel.) --- .github/workflows/browserstack.yml | 12 ++++ src/cleartext.js | 33 +---------- src/openpgp.js | 5 +- test/general/brainpool.js | 88 ++++++++++++------------------ test/general/ecc_nist.js | 80 +++++++++++---------------- 5 files changed, 86 insertions(+), 132 deletions(-) diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index 75e438826..5e3446522 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -14,6 +14,12 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: softprops/turnstyle@v1 + with: + poll-interval-seconds: 30 + abort-after-seconds: 900 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-node@v1 - run: npm ci - run: npm run build-test @@ -28,6 +34,12 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: softprops/turnstyle@v1 + with: + poll-interval-seconds: 30 + abort-after-seconds: 900 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-node@v1 - run: npm ci - run: npm run build-test --lightweight diff --git a/src/cleartext.js b/src/cleartext.js index b51e0a369..a38901af4 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -66,25 +66,10 @@ export class CleartextMessage { * @async */ async sign(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], config = defaultConfig) { - return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, signingKeyIds, date, userIds, config)); - } - - /** - * Sign the cleartext message - * @param {Array} privateKeys - private keys with decrypted secret key data for signing - * @param {Signature} [signature] - Any existing detached signature - * @param {Array} [signingKeyIds] - Array of key IDs to use for signing. Each signingKeyIds[i] corresponds to privateKeys[i] - * @param {Date} [date] - The creation time of the signature that should be created - * @param {Array} [userIds] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] - * @param {Object} [config] - Full configuration, defaults to openpgp.config - * @returns {Signature} New detached signature of message content. - * @async - */ - async signDetached(privateKeys, signature = null, signingKeyIds = [], date = new Date(), userIds = [], config = defaultConfig) { const literalDataPacket = new LiteralDataPacket(); literalDataPacket.setText(this.text); - - return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true, undefined, config)); + const newSignature = new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIds, true, undefined, config)); + return new CleartextMessage(this.text, newSignature); } /** @@ -96,19 +81,7 @@ export class CleartextMessage { * @async */ verify(keys, date = new Date(), config = defaultConfig) { - return this.verifyDetached(this.signature, keys, date, config); - } - - /** - * Verify signatures of cleartext signed message - * @param {Array} keys - Array of keys to verify signatures - * @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time - * @param {Object} [config] - Full configuration, defaults to openpgp.config - * @returns {Array<{keyid: module:type/keyid~Keyid, valid: Boolean}>} List of signer's keyid and validity of signature. - * @async - */ - verifyDetached(signature, keys, date = new Date(), config = defaultConfig) { - const signatureList = signature.packets; + const signatureList = this.signature.packets; const literalDataPacket = new LiteralDataPacket(); // we assume that cleartext signature is generated based on UTF8 cleartext literalDataPacket.setText(this.text); diff --git a/src/openpgp.js b/src/openpgp.js index b646a9d04..9378dd480 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -353,7 +353,7 @@ export function sign({ message, privateKeys, armor = true, streaming = message & config = { ...defaultConfig, ...config }; checkCleartextOrMessage(message); if (message instanceof CleartextMessage && !armor) throw new Error("Can't sign non-armored cleartext message"); - if (message instanceof CleartextMessage && detached) throw new Error("Can't sign detached cleartext message"); + if (message instanceof CleartextMessage && detached) throw new Error("Can't detach-sign a cleartext message"); privateKeys = toArray(privateKeys); fromUserIds = toArray(fromUserIds); return Promise.resolve().then(async function() { @@ -408,12 +408,13 @@ export function verify({ message, publicKeys, format = 'utf8', streaming = messa config = { ...defaultConfig, ...config }; checkCleartextOrMessage(message); if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary"); + if (message instanceof CleartextMessage && signature) throw new Error("Can't verify detached cleartext signature"); publicKeys = toArray(publicKeys); return Promise.resolve().then(async function() { const result = {}; if (message instanceof CleartextMessage) { - result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, config) : await message.verify(publicKeys, date, config); + result.signatures = await message.verify(publicKeys, date, config); } else { result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, streaming, config) : await message.verify(publicKeys, date, streaming, config); } diff --git a/test/general/brainpool.js b/test/general/brainpool.js index 58cdc06b6..5cce0ea86 100644 --- a/test/general/brainpool.js +++ b/test/general/brainpool.js @@ -279,61 +279,43 @@ EJ4QcD/oQ6x1M/8X/iKQCtxZP8RnlrbH7ExkNON5s5g= }); function omnibus() { - it('Omnibus BrainpoolP256r1 Test', function() { - const options = { userIds: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1" }; - return openpgp.generateKey(options).then(function(firstKey) { - const hi = firstKey.key; - const pubHi = hi.toPublic(); + it('Omnibus BrainpoolP256r1 Test', async function() { + const testData = input.createSomeMessage(); + const testData2 = input.createSomeMessage(); - const options = { userIds: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" }; - return openpgp.generateKey(options).then(function(secondKey) { - const bye = secondKey.key; - const pubBye = bye.toPublic(); + const firstKey = await openpgp.generateKey({ userIds: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1" }); + const hi = firstKey.key; + const pubHi = hi.toPublic(); + const secondKey = await openpgp.generateKey({ userIds: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" }); + const bye = secondKey.key; + const pubBye = bye.toPublic(); - const testData = input.createSomeMessage(); - const testData2 = input.createSomeMessage(); - return Promise.all([ - // Signing message - openpgp.sign( - { message: openpgp.CleartextMessage.fromText(testData), privateKeys: hi } - ).then(async signed => { - const msg = await openpgp.readCleartextMessage({ cleartextMessage: signed }); - // Verifying signed message - return Promise.all([ - openpgp.verify( - { message: msg, publicKeys: pubHi } - ).then(output => expect(output.signatures[0].valid).to.be.true), - // Verifying detached signature - openpgp.verify({ - message: openpgp.CleartextMessage.fromText(testData), - publicKeys: pubHi, - signature: msg.signature - }).then(output => expect(output.signatures[0].valid).to.be.true) - ]); - }), - // Encrypting and signing - openpgp.encrypt( - { - message: openpgp.Message.fromText(testData2), - publicKeys: [pubBye], - privateKeys: [hi] - } - ).then(async encrypted => { - const msg = await openpgp.readMessage({ armoredMessage: encrypted }); - // Decrypting and verifying - return openpgp.decrypt( - { - message: msg, - privateKeys: bye, - publicKeys: [pubHi] - } - ).then(output => { - expect(output.data).to.equal(testData2); - expect(output.signatures[0].valid).to.be.true; - }); - }) - ]); - }); + const cleartextMessage = await openpgp.sign({ message: openpgp.CleartextMessage.fromText(testData), privateKeys: hi }); + await openpgp.verify({ + message: await openpgp.readCleartextMessage({ cleartextMessage }), + publicKeys: pubHi + }).then(output => expect(output.signatures[0].valid).to.be.true); + // Verifying detached signature + await openpgp.verify({ + message: openpgp.Message.fromText(util.removeTrailingSpaces(testData)), + publicKeys: pubHi, + signature: (await openpgp.readCleartextMessage({ cleartextMessage })).signature + }).then(output => expect(output.signatures[0].valid).to.be.true); + + // Encrypting and signing + const encrypted = await openpgp.encrypt({ + message: openpgp.Message.fromText(testData2), + publicKeys: [pubBye], + privateKeys: [hi] + }); + // Decrypting and verifying + return openpgp.decrypt({ + message: await openpgp.readMessage({ armoredMessage: encrypted }), + privateKeys: bye, + publicKeys: [pubHi] + }).then(output => { + expect(output.data).to.equal(testData2); + expect(output.signatures[0].valid).to.be.true; }); }); } diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js index e0a686647..7ed0610ab 100644 --- a/test/general/ecc_nist.js +++ b/test/general/ecc_nist.js @@ -3,63 +3,49 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp const chai = require('chai'); chai.use(require('chai-as-promised')); const input = require('./testInputs.js'); +const util = require('../../src/util'); const expect = chai.expect; module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-384,P-521 curves @lightweight', function () { function omnibus() { - it('Omnibus NIST P-256 Test', function () { - const options = { userIds: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }; + it('Omnibus NIST P-256 Test', async function () { const testData = input.createSomeMessage(); const testData2 = input.createSomeMessage(); - return openpgp.generateKey(options).then(function (firstKey) { - const hi = firstKey.key; - const pubHi = hi.toPublic(); - const options = { userIds: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }; - return openpgp.generateKey(options).then(function (secondKey) { - const bye = secondKey.key; - const pubBye = bye.toPublic(); + const firstKey = await openpgp.generateKey({ userIds: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }); + const hi = firstKey.key; + const pubHi = hi.toPublic(); + const secondKey = await openpgp.generateKey({ userIds: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }); + const bye = secondKey.key; + const pubBye = bye.toPublic(); - return Promise.all([ - // Signing message + const cleartextMessage = await openpgp.sign({ message: openpgp.CleartextMessage.fromText(testData), privateKeys: hi }); + await openpgp.verify({ + message: await openpgp.readCleartextMessage({ cleartextMessage }), + publicKeys: pubHi + }).then(output => expect(output.signatures[0].valid).to.be.true); + // Verifying detached signature + await openpgp.verify({ + message: openpgp.Message.fromText(util.removeTrailingSpaces(testData)), + publicKeys: pubHi, + signature: (await openpgp.readCleartextMessage({ cleartextMessage })).signature + }).then(output => expect(output.signatures[0].valid).to.be.true); - openpgp.sign( - { message: openpgp.CleartextMessage.fromText(testData), privateKeys: hi } - ).then(async signed => { - const msg = await openpgp.readCleartextMessage({ cleartextMessage: signed }); - // Verifying signed message - return Promise.all([ - openpgp.verify( - { message: msg, publicKeys: pubHi } - ).then(output => expect(output.signatures[0].valid).to.be.true), - // Verifying detached signature - openpgp.verify({ - message: openpgp.CleartextMessage.fromText(testData), - publicKeys: pubHi, - signature: msg.signature - }).then(output => expect(output.signatures[0].valid).to.be.true) - ]); - }), - // Encrypting and signing - openpgp.encrypt( - { message: openpgp.Message.fromText(testData2), - publicKeys: [pubBye], - privateKeys: [hi] } - ).then(async encrypted => { - const msg = await openpgp.readMessage({ armoredMessage: encrypted }); - // Decrypting and verifying - return openpgp.decrypt( - { message: msg, - privateKeys: bye, - publicKeys: [pubHi] } - ).then(output => { - expect(output.data).to.equal(testData2); - expect(output.signatures[0].valid).to.be.true; - }); - }) - ]); - }); + // Encrypting and signing + const encrypted = await openpgp.encrypt({ + message: openpgp.Message.fromText(testData2), + publicKeys: [pubBye], + privateKeys: [hi] + }); + // Decrypting and verifying + return openpgp.decrypt({ + message: await openpgp.readMessage({ armoredMessage: encrypted }), + privateKeys: bye, + publicKeys: [pubHi] + }).then(output => { + expect(output.data).to.equal(testData2); + expect(output.signatures[0].valid).to.be.true; }); }); }