diff --git a/src/cleartext.js b/src/cleartext.js index 84252017..a3ce9895 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -29,7 +29,7 @@ import armor from './encoding/armor'; import enums from './enums'; import packet from './packet'; import { Signature } from './signature'; -import { createVerificationObjects } from './message'; +import { createVerificationObjects, createSignaturePackets } from './message'; import { getPreferredHashAlgo } from './key'; /** @@ -80,34 +80,10 @@ CleartextMessage.prototype.sign = async function(privateKeys) { * @return {module:signature~Signature} new detached signature of message content */ CleartextMessage.prototype.signDetached = async function(privateKeys) { - const packetlist = new packet.List(); const literalDataPacket = new packet.Literal(); literalDataPacket.setText(this.text); - await Promise.all(privateKeys.map(async function(privateKey) { - if (privateKey.isPublic()) { - throw new Error('Need private key for signing'); - } - await privateKey.verifyPrimaryUser(); - const signingKeyPacket = privateKey.getSigningKeyPacket(); - if (!signingKeyPacket) { - throw new Error('Could not find valid key packet for signing in key ' + - privateKey.primaryKey.getKeyId().toHex()); - } - const signaturePacket = new packet.Signature(); - signaturePacket.signatureType = enums.signature.text; - signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } - await signaturePacket.sign(signingKeyPacket, literalDataPacket); - return signaturePacket; - })).then(signatureList => { - signatureList.forEach(signaturePacket => packetlist.push(signaturePacket)); - }); - - return new Signature(packetlist); + return new Signature(await createSignaturePackets(literalDataPacket, privateKeys)); }; /** diff --git a/src/message.js b/src/message.js index 1fc0c96c..01838921 100644 --- a/src/message.js +++ b/src/message.js @@ -416,25 +416,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null) { }); packetlist.push(literalDataPacket); - - await Promise.all(privateKeys.map(async function(privateKey) { - const signaturePacket = new packet.Signature(); - const signingKeyPacket = privateKey.getSigningKeyPacket(); - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } - signaturePacket.signatureType = signatureType; - signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); - signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - await signaturePacket.sign(signingKeyPacket, literalDataPacket); - return signaturePacket; - })).then(signatureList => { - signatureList.forEach(signaturePacket => packetlist.push(signaturePacket)); - }); - - if (signature) { - packetlist.concat(existingSigPacketlist); - } + packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature)); return new Message(packetlist); }; @@ -466,24 +448,40 @@ Message.prototype.compress = function(compression) { * @return {module:signature~Signature} new detached signature of message content */ Message.prototype.signDetached = async function(privateKeys=[], signature=null) { - const packetlist = new packet.List(); - const literalDataPacket = this.packets.findPacket(enums.packet.literal); if (!literalDataPacket) { throw new Error('No literal data packet to sign.'); } + return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature)); +}; + +/** + * Create signature packets for the message + * @param {module:packet/literal} the literal data packet to sign + * @param {Array} privateKey private keys with decrypted secret key data for signing + * @param {Signature} signature (optional) any existing detached signature to append + * @return {module:packet/packetlist} list of signature packets + */ +export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null) { + const packetlist = new packet.List(); const literalFormat = enums.write(enums.literal, literalDataPacket.format); const signatureType = literalFormat === enums.literal.binary ? enums.signature.binary : enums.signature.text; await Promise.all(privateKeys.map(async function(privateKey) { - const signaturePacket = new packet.Signature(); + if (privateKey.isPublic()) { + throw new Error('Need private key for signing'); + } await privateKey.verifyPrimaryUser(); const signingKeyPacket = privateKey.getSigningKeyPacket(); + if (!signingKeyPacket) { + throw new Error('Could not find valid key packet for signing in key ' + privateKey.primaryKey.getKeyId().toHex()); + } if (!signingKeyPacket.isDecrypted) { throw new Error('Private key is not decrypted.'); } + const signaturePacket = new packet.Signature(); signaturePacket.signatureType = signatureType; signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); @@ -497,10 +495,8 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null) const existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature); packetlist.concat(existingSigPacketlist); } - - return new Signature(packetlist); -}; - + return packetlist; +} /** * Verify message signatures diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 476f0c11..e45f6c01 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -1279,7 +1279,7 @@ describe('OpenPGP.js public api tests', function() { privateKeys: [privateKey.keys[0], privKeyDE] }; const verifyOpt = { - publicKeys: publicKey.keys + publicKeys: [publicKey.keys[0], privKeyDE.toPublic()] }; return openpgp.sign(signOpt).then(function (signed) { expect(signed.data).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/); @@ -1290,6 +1290,9 @@ describe('OpenPGP.js public api tests', function() { expect(verified.signatures[0].valid).to.be.true; expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex()); expect(verified.signatures[0].signature.packets.length).to.equal(1); + expect(verified.signatures[1].valid).to.be.true; + expect(verified.signatures[1].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex()); + expect(verified.signatures[1].signature.packets.length).to.equal(1); }); });