Don't hang when signature packet corresponding to one-pass sig is missing

This commit is contained in:
Daniel Huigens 2018-10-04 16:14:44 +02:00
parent 150222bee5
commit 3751731330
3 changed files with 47 additions and 6 deletions

View File

@ -545,7 +545,7 @@ Message.prototype.verify = async function(keys, date=new Date(), streaming) {
if (literalDataList.length !== 1) {
throw new Error('Can only verify message with one literal data packet.');
}
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature);
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse();
const signatureList = msg.packets.filterByTag(enums.packet.signature);
if (onePassSigList.length && !signatureList.length && msg.packets.stream) {
onePassSigList.forEach(onePassSig => {
@ -555,25 +555,28 @@ Message.prototype.verify = async function(keys, date=new Date(), streaming) {
onePassSig.signatureData = stream.fromAsync(async () => (await onePassSig.correspondingSig).signatureData);
onePassSig.hashed = onePassSig.hash(literalDataList[0], undefined, streaming);
});
const verificationObjects = await createVerificationObjects(onePassSigList, literalDataList, keys, date);
msg.packets.stream = stream.transformPair(msg.packets.stream, async (readable, writable) => {
const reader = stream.getReader(readable);
const writer = stream.getWriter(writable);
try {
await stream.readToEnd(stream.transform(readable, signature => {
onePassSigList.pop().correspondingSigResolve(signature);
}));
for (let i = 0; i < onePassSigList.length; i++) {
const { value: signature } = await reader.read();
onePassSigList[i].correspondingSigResolve(signature);
}
await reader.readToEnd();
await writer.ready;
await writer.close();
} catch(e) {
onePassSigList.forEach(onePassSig => {
onePassSig.correspondingSigResolve({
tag: enums.packet.signature,
verify: () => undefined
});
});
await writer.abort(e);
}
});
return verificationObjects.reverse();
return createVerificationObjects(onePassSigList, literalDataList, keys, date);
}
return createVerificationObjects(signatureList, literalDataList, keys, date);
};

View File

@ -142,6 +142,9 @@ OnePassSignature.prototype.calculateTrailer = Signature.prototype.calculateTrail
OnePassSignature.prototype.verify = async function() {
const correspondingSig = await this.correspondingSig;
if (!correspondingSig || correspondingSig.tag !== enums.packet.signature) {
throw new Error('Corresponding signature packet missing');
}
correspondingSig.hashed = this.hashed;
return correspondingSig.verify.apply(correspondingSig, arguments);
};

View File

@ -600,6 +600,41 @@ yYDnCgA=
});
});
it('Streaming verify signed message with missing signature packet', async function() {
const msg_armor =
`-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js v3.1.3
Comment: https://openpgpjs.org
yFgBO8LLzMjE+KDlu0uOgs50xtNRJdzFBYnJqcW6JanFJVE3r9eCuVYKvFxg
hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
=D6TZ
-----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const sMsg = await openpgp.message.readArmored(new ReadableStream({
async pull(controller) {
await new Promise(setTimeout);
controller.enqueue(msg_armor.shift());
if (!msg_armor.length) controller.close();
}
}));
const pubKey = (await openpgp.key.readArmored(pub_key_arm2)).keys[0];
const keyids = sMsg.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
return openpgp.verify({ publicKeys:[pubKey], message:sMsg }).then(async function(cleartextSig) {
expect(cleartextSig).to.exist;
expect(openpgp.util.nativeEOL(openpgp.util.Uint8Array_to_str(await openpgp.stream.readToEnd(cleartextSig.data)))).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1);
await expect(cleartextSig.signatures[0].verified).to.be.rejectedWith('Corresponding signature packet missing');
expect((await cleartextSig.signatures[0].signature).packets.length).to.equal(0);
});
});
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same string cleartext and valid signatures', async function() {
const plaintext = 'short message\nnext line \n한국어/조선말';
const pubKey = (await openpgp.key.readArmored(pub_key_arm2)).keys[0];