Skip to content

Commit

Permalink
Rename config.tolerant to config.ignoreUnsupportedPackets, add `c…
Browse files Browse the repository at this point in the history
…onfig.ignoreMalformedPackets` (#1386)

Configuration options related to parsing have been changed to make it possible
to try to read messages containing malformed packets. Changes:
- rename `config.tolerant` to `config.ignoreUnsupportedPackets`. This still
defaults to `true`.
- Add `config.ignoreMalformedPackets` to ignore packets that fail to parse
(when possible). This option was not available before and it defaults to `false`.
  • Loading branch information
larabr committed Jul 23, 2021
1 parent 3cd61ff commit 4b6189b
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 23 deletions.
3 changes: 2 additions & 1 deletion openpgp.d.ts
Expand Up @@ -321,7 +321,8 @@ interface Config {
minRSABits: number;
passwordCollisionCheck: boolean;
revocationsExpire: boolean;
tolerant: boolean;
ignoreUnsupportedPackets: boolean;
ignoreMalformedPackets: boolean;
versionString: string;
commentString: string;
allowInsecureDecryptionWithSigningKeys: boolean;
Expand Down
10 changes: 7 additions & 3 deletions src/config/config.js
Expand Up @@ -136,10 +136,14 @@ export default {
minBytesForWebCrypto: 1000,
/**
* @memberof module:config
* @property {Boolean} tolerant Ignore unsupported/unrecognizable packets instead of throwing an error
* @property {Boolean} ignoreUnsupportedPackets Ignore unsupported/unrecognizable packets on parsing instead of throwing an error
*/
tolerant: true,

ignoreUnsupportedPackets: true,
/**
* @memberof module:config
* @property {Boolean} ignoreMalformedPackets Ignore malformed packets on parsing instead of throwing an error
*/
ignoreMalformedPackets: false,
/**
* @memberof module:config
* @property {Boolean} showVersion Whether to include {@link module:config/config.versionString} in armored messages
Expand Down
5 changes: 3 additions & 2 deletions src/packet/packetlist.js
Expand Up @@ -82,8 +82,9 @@ class PacketList extends Array {
await packet.read(parsed.packet, config);
await writer.write(packet);
} catch (e) {
const isTolerableError = config.tolerant && e instanceof UnsupportedError;
if (!isTolerableError || supportsStreaming(parsed.tag)) {
const throwUnsupportedError = !config.ignoreUnsupportedPackets && e instanceof UnsupportedError;
const throwMalformedError = !config.ignoreMalformedPackets && !(e instanceof UnsupportedError);
if (throwUnsupportedError || throwMalformedError || supportsStreaming(parsed.tag)) {
// The packets that support streaming are the ones that contain message data.
// Those are also the ones we want to be more strict about and throw on parse errors
// (since we likely cannot process the message without these packets anyway).
Expand Down
12 changes: 6 additions & 6 deletions test/general/config.js
Expand Up @@ -8,11 +8,11 @@ module.exports = () => describe('Custom configuration', function() {
const message = await openpgp.readMessage({ armoredMessage });
message.packets.findPacket(openpgp.SymEncryptedSessionKeyPacket.tag).version = 1; // unsupported SKESK version

const config = { tolerant: true };
const config = { ignoreUnsupportedPackets: true };
const parsedMessage = await openpgp.readMessage({ armoredMessage: message.armor(), config });
expect(parsedMessage.packets.length).to.equal(1);

config.tolerant = false;
config.ignoreUnsupportedPackets = false;
await expect(
openpgp.readMessage({ armoredMessage: message.armor(), config })
).to.be.rejectedWith(/Version 1 of the SKESK packet is unsupported/);
Expand All @@ -30,11 +30,11 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
const signature = await openpgp.readSignature({ armoredSignature });
signature.packets[0].signatureData[0] = 1; // set unsupported signature version

const config = { tolerant: true };
const config = { ignoreUnsupportedPackets: true };
const parsedSignature = await openpgp.readSignature({ armoredSignature: signature.armor(), config });
expect(parsedSignature.packets.length).to.equal(0);

config.tolerant = false;
config.ignoreUnsupportedPackets = false;
await expect(
openpgp.readSignature({ armoredSignature: signature.armor(), config })
).to.be.rejectedWith(/Version 1 of the signature packet is unsupported/);
Expand All @@ -43,10 +43,10 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z
it('openpgp.readKey', async function() {
const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs:[{ name:'test', email:'test@a.it' }] });
await expect(
openpgp.readKey({ armoredKey, config: { tolerant: false, maxUserIDLength: 2 } })
openpgp.readKey({ armoredKey, config: { ignoreUnsupportedPackets: false, maxUserIDLength: 2 } })
).to.be.rejectedWith(/User ID string is too long/);
await expect(
openpgp.readKey({ armoredKey, config: { tolerant: true, maxUserIDLength: 2 } })
openpgp.readKey({ armoredKey, config: { ignoreUnsupportedPackets: true, maxUserIDLength: 2 } })
).to.be.rejectedWith(/User ID string is too long/);
});

Expand Down
21 changes: 10 additions & 11 deletions test/general/packet.js
Expand Up @@ -950,7 +950,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
});

describe('PacketList parsing', function () {
it('Ignores unknown packet version with tolerant mode enabled', async function() {
it('Ignores unknown packet version with `config.ignoreUnsupportedPackets` enabled', async function() {
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
iQFKBAEBCgA0FiEEdOyNPagqedqiXfEMa6Ve2Dq64bsFAlszXwQWHHRlc3Qtd2tk
Expand All @@ -968,11 +968,11 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
signaturePacket.signatureData[0] = 1;
packets.push(signaturePacket);
const bytes = packets.write();
const parsed = await openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, tolerant: true });
const parsed = await openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: true });
expect(parsed.length).to.equal(0);
});

it('Throws on unknown packet version with tolerant mode disabled', async function() {
it('Throws on unknown packet version with `config.ignoreUnsupportedPackets` disabled', async function() {
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
iQFKBAEBCgA0FiEEdOyNPagqedqiXfEMa6Ve2Dq64bsFAlszXwQWHHRlc3Qtd2tk
Expand All @@ -991,28 +991,27 @@ kePFjAnu9cpynKXu3usf8+FuBw2zLsg1Id1n7ttxoAte416KjBN9lFBt8mcu
packets.push(signaturePacket);
const bytes = packets.write();
await expect(
openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, tolerant: false })
openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, ignoreUnsupportedPackets: false })
).to.be.rejectedWith(/Version 1 of the signature packet is unsupported/);
});

it('Throws on disallowed packet even with tolerant mode enabled', async function() {
const packets = new openpgp.PacketList();
packets.push(new openpgp.LiteralDataPacket());
const bytes = packets.write();
await expect(openpgp.PacketList.fromBinary(bytes, {}, { ...openpgp.config, tolerant: false })).to.be.rejectedWith(/Packet not allowed in this context/);
await expect(openpgp.PacketList.fromBinary(bytes, {}, { ...openpgp.config, tolerant: true })).to.be.rejectedWith(/Packet not allowed in this context/);
await expect(openpgp.PacketList.fromBinary(bytes, {}, { ...openpgp.config, ignoreUnsupportedPackets: false, ignoreMalformedPackets: false })).to.be.rejectedWith(/Packet not allowed in this context/);
await expect(openpgp.PacketList.fromBinary(bytes, {}, { ...openpgp.config, ignoreUnsupportedPackets: true, ignoreMalformedPackets: true })).to.be.rejectedWith(/Packet not allowed in this context/);
});

it('Throws on parsing errors even with tolerant mode enabled', async function () {
it('Throws on parsing errors `config.ignoreMalformedPackets` disabled', async function () {
const packets = new openpgp.PacketList();
packets.push(openpgp.UserIDPacket.fromObject({ name:'test', email:'test@a.it' }));
const bytes = packets.write();
await expect(
openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, maxUserIDLength: 2, tolerant: false })
).to.be.rejectedWith(/User ID string is too long/);
await expect(
openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, maxUserIDLength: 2, tolerant: true })
openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, maxUserIDLength: 2, ignoreMalformedPackets: false })
).to.be.rejectedWith(/User ID string is too long/);
const parsed = await openpgp.PacketList.fromBinary(bytes, allAllowedPackets, { ...openpgp.config, maxUserIDLength: 2, ignoreMalformedPackets: true });
expect(parsed.length).to.equal(0);
});
});
});

0 comments on commit 4b6189b

Please sign in to comment.