Skip to content

Commit

Permalink
Drop support for verification of detached cleartext signatures (#1265)
Browse files Browse the repository at this point in the history
(Also, use turnstyle to avoid CI browserstack tasks running in parallel.)
  • Loading branch information
larabr committed Mar 18, 2021
1 parent eba791e commit 3e808c1
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 132 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/browserstack.yml
Expand Up @@ -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
Expand All @@ -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
Expand Down
33 changes: 3 additions & 30 deletions src/cleartext.js
Expand Up @@ -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<Key>} privateKeys - private keys with decrypted secret key data for signing
* @param {Signature} [signature] - Any existing detached signature
* @param {Array<module:type/keyid~Keyid>} [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);
}

/**
Expand All @@ -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<Key>} 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);
Expand Down
5 changes: 3 additions & 2 deletions src/openpgp.js
Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
}
Expand Down
88 changes: 35 additions & 53 deletions test/general/brainpool.js
Expand Up @@ -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;
});
});
}
Expand Down
80 changes: 33 additions & 47 deletions test/general/ecc_nist.js
Expand Up @@ -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;
});
});
}
Expand Down

0 comments on commit 3e808c1

Please sign in to comment.