diff --git a/src/message.js b/src/message.js index c40ce8d8..9405dd42 100644 --- a/src/message.js +++ b/src/message.js @@ -554,8 +554,9 @@ Message.prototype.verify = async function(keys, date=new Date(), streaming) { const signatureList = msg.packets.filterByTag(enums.packet.signature); if (onePassSigList.length && !signatureList.length && msg.packets.stream) { onePassSigList.forEach(onePassSig => { - onePassSig.correspondingSig = new Promise(resolve => { + onePassSig.correspondingSig = new Promise((resolve, reject) => { onePassSig.correspondingSigResolve = resolve; + onePassSig.correspondingSigReject = reject; }); onePassSig.signatureData = stream.fromAsync(async () => (await onePassSig.correspondingSig).signatureData); onePassSig.hashed = onePassSig.hash(literalDataList[0], undefined, streaming); @@ -573,10 +574,7 @@ Message.prototype.verify = async function(keys, date=new Date(), streaming) { await writer.close(); } catch(e) { onePassSigList.forEach(onePassSig => { - onePassSig.correspondingSigResolve({ - tag: enums.packet.signature, - verify: () => undefined - }); + onePassSig.correspondingSigReject(e); }); await writer.abort(e); } @@ -636,6 +634,13 @@ async function createVerificationObject(signature, literalDataList, keys, date=n return new Signature(packetlist); }); + // Mark potential promise rejections as "handled". This is needed because in + // some cases, we reject them before the user has a reasonable chance to + // handle them (e.g. `await readToEnd(result.data); await result.verified` and + // the data stream errors). + verifiedSig.signature.catch(() => {}); + verifiedSig.verified.catch(() => {}); + return verifiedSig; } diff --git a/src/packet/one_pass_signature.js b/src/packet/one_pass_signature.js index de49a3da..9c61b013 100644 --- a/src/packet/one_pass_signature.js +++ b/src/packet/one_pass_signature.js @@ -85,13 +85,13 @@ OnePassSignature.prototype.read = function (bytes) { // A one-octet signature type. Signature types are described in // Section 5.2.1. - this.signatureType = enums.read(enums.signature, bytes[mypos++]); + this.signatureType = bytes[mypos++]; // A one-octet number describing the hash algorithm used. - this.hashAlgorithm = enums.read(enums.hash, bytes[mypos++]); + this.hashAlgorithm = bytes[mypos++]; // A one-octet number describing the public-key algorithm used. - this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[mypos++]); + this.publicKeyAlgorithm = bytes[mypos++]; // An eight-octet number holding the Key ID of the signing key. this.issuerKeyId = new type_keyid(); @@ -145,6 +145,14 @@ OnePassSignature.prototype.verify = async function() { if (!correspondingSig || correspondingSig.tag !== enums.packet.signature) { throw new Error('Corresponding signature packet missing'); } + if ( + correspondingSig.signatureType !== this.signatureType || + correspondingSig.hashAlgorithm !== this.hashAlgorithm || + correspondingSig.publicKeyAlgorithm !== this.publicKeyAlgorithm || + !correspondingSig.issuerKeyId.equals(this.issuerKeyId) + ) { + throw new Error('Corresponding signature packet does not match one-pass signature packet'); + } correspondingSig.hashed = this.hashed; return correspondingSig.verify.apply(correspondingSig, arguments); }; diff --git a/test/general/streaming.js b/test/general/streaming.js index d1decf6e..046c510d 100644 --- a/test/general/streaming.js +++ b/test/general/streaming.js @@ -534,7 +534,7 @@ function tests() { await openpgp.stream.cancel(verified.data, new Error('canceled by test')); expect(canceled).to.be.true; expect(verified.signatures).to.exist.and.have.length(1); - expect(await verified.signatures[0].verified).to.be.undefined; + await expect(verified.signatures[0].verified).to.be.rejectedWith('canceled'); } finally { openpgp.config.aead_protect = aead_protectValue; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteValue;