diff --git a/.gitignore b/.gitignore index 5781473f..2085d61f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ node_modules/ npm* test/lib/ -test/typescript/definitions.js dist/ openpgp.store/ coverage +test/fuzz/reports diff --git a/package.json b/package.json index 0db451bc..459783d4 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "prepare": "npm run build", "test": "mocha --timeout 120000 test/unittests.js", "test-type-definitions": "node --loader ts-node/esm test/typescript/definitions.ts", + "fuzz": "jazzer test/fuzz/$TARGET.cjs -- -artifact_prefix=test/fuzz/reports/", + "fuzz-coverage": "jazzer test/fuzz/$TARGET.cjs --coverage --cov_dir=test/fuzz/coverage -- -artifact_prefix=test/fuzz/reports/", "benchmark-time": "node test/benchmarks/time.js", "benchmark-memory-usage": "node test/benchmarks/memory_usage.js", "start": "http-server", diff --git a/test/fuzz/createCleartextMessage.cjs b/test/fuzz/createCleartextMessage.cjs new file mode 100644 index 00000000..c2941db2 --- /dev/null +++ b/test/fuzz/createCleartextMessage.cjs @@ -0,0 +1,15 @@ +const { FuzzedDataProvider } = require('@jazzer.js/core'); + +const MAX_MESSAGE_LENGTH = 9000; +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const data = new FuzzedDataProvider(inputData); + const text = data.bufToPrintableString(inputData, 2, MAX_MESSAGE_LENGTH, 'utf-8'); + return openpgp.default.createCleartextMessage({ text }); + }); + +}; + diff --git a/test/fuzz/createMessageBinary.cjs b/test/fuzz/createMessageBinary.cjs new file mode 100644 index 00000000..7774a057 --- /dev/null +++ b/test/fuzz/createMessageBinary.cjs @@ -0,0 +1,9 @@ +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + return openpgp.default.createMessage({ binary: new Uint8Array(inputData) }); + }); +}; + diff --git a/test/fuzz/createMessageText.cjs b/test/fuzz/createMessageText.cjs new file mode 100644 index 00000000..77d62446 --- /dev/null +++ b/test/fuzz/createMessageText.cjs @@ -0,0 +1,13 @@ +const { FuzzedDataProvider } = require('@jazzer.js/core'); + +const MAX_MESSAGE_LENGTH = 9000; + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const data = new FuzzedDataProvider(inputData); + return openpgp.default.createMessage({ text: data.consumeString(MAX_MESSAGE_LENGTH, 'utf-8') }); + }); +}; diff --git a/test/fuzz/generateKey.cjs b/test/fuzz/generateKey.cjs new file mode 100644 index 00000000..4dd9660f --- /dev/null +++ b/test/fuzz/generateKey.cjs @@ -0,0 +1,25 @@ +const { FuzzedDataProvider } = require('@jazzer.js/core'); + +const MAX_NAME_LENGTH = 30; +const MAX_COMMENT_LENGTH = 500; + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const data = new FuzzedDataProvider(inputData); + const asciiString = data.consumeString(MAX_COMMENT_LENGTH); + const utf8String = data.consumeString(MAX_NAME_LENGTH, 'utf-8'); + + return openpgp.default.generateKey({ userIDs: [ + { name: utf8String }, + { email: utf8String }, + { comment: asciiString }, + { name: utf8String, email: utf8String, comment: asciiString } + ], + passphrase: asciiString, + format: 'object' }); + }); +}; + diff --git a/test/fuzz/readKeyArmored.cjs b/test/fuzz/readKeyArmored.cjs new file mode 100644 index 00000000..51b40388 --- /dev/null +++ b/test/fuzz/readKeyArmored.cjs @@ -0,0 +1,27 @@ +const { FuzzedDataProvider } = require('@jazzer.js/core'); + +const ignored = ['Misformed armored text']; +const MAX_MESSAGE_LENGTH = 9000; + +function ignoredError(error) { + return ignored.some(message => error.message.includes(message)); +} + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const data = new FuzzedDataProvider(inputData); + const fuzzedText = data.consumeString(MAX_MESSAGE_LENGTH, 'utf-8'); + const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- ${fuzzedText} -----END PGP PRIVATE KEY BLOCK-----`; + + return openpgp.default.readKey({ armoredKey }) + .catch(error => { + if (error.message && !ignoredError(error)) { + throw error; + } + }); + }); +}; + diff --git a/test/fuzz/readKeyBinary.cjs b/test/fuzz/readKeyBinary.cjs new file mode 100644 index 00000000..bd4102b5 --- /dev/null +++ b/test/fuzz/readKeyBinary.cjs @@ -0,0 +1,22 @@ +const ignored = ['This message / key probably does not conform to a valid OpenPGP format']; + +function ignoredError(error) { + return ignored.some(message => error.message.includes(message)); +} + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const binaryKey = new Uint8Array(`-----BEGIN PGP PRIVATE KEY BLOCK----- ${inputData} -----END PGP PRIVATE KEY BLOCK-----`); + + return openpgp.default.readKey({ binaryKey }) + .catch(error => { + if (error.message && !ignoredError(error)) { + throw error; + } + }); + }); +}; + diff --git a/test/fuzz/readMessageBinary.cjs b/test/fuzz/readMessageBinary.cjs new file mode 100644 index 00000000..38cd97ed --- /dev/null +++ b/test/fuzz/readMessageBinary.cjs @@ -0,0 +1,22 @@ +const ignored = ['This message / key probably does not conform to a valid OpenPGP format']; + +function ignoredError(error) { + return ignored.some(message => error.message.includes(message)); +} + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const binaryMessage = new Uint8Array(`-----BEGIN PGP MESSAGE----- ${inputData} -----END PGP MESSAGE-----`); + + return openpgp.default.readMessage({ binaryMessage }) + .catch(error => { + if (error.message && !ignoredError(error)) { + throw error; + } + }); + }); +}; + diff --git a/test/fuzz/readMessageText.cjs b/test/fuzz/readMessageText.cjs new file mode 100644 index 00000000..072832b1 --- /dev/null +++ b/test/fuzz/readMessageText.cjs @@ -0,0 +1,27 @@ +const { FuzzedDataProvider } = require('@jazzer.js/core'); + +const ignored = ['Misformed armored text']; +const MAX_MESSAGE_LENGTH = 9000; + +function ignoredError(error) { + return ignored.some(message => error.message.includes(message)); +} + +/** + * @param { Buffer } inputData + */ +module.exports.fuzz = function(inputData) { + import('../initOpenpgp.js').then(openpgp => { + const data = new FuzzedDataProvider(inputData); + const fuzzedText = data.consumeString(MAX_MESSAGE_LENGTH, 'utf-8'); + const armoredMessage = `-----BEGIN PGP MESSAGE----- ${fuzzedText} -----END PGP MESSAGE-----`; + + return openpgp.default.readMessage({ armoredMessage }) + .catch(error => { + if (error.message && !ignoredError(error)) { + throw error; + } + }); + }); +}; +