From 0b281a3b0744b6c477aa1cbbde00d8910581f236 Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Wed, 8 Feb 2017 11:17:15 +0100 Subject: Bug 1334106 - split mpi target, r=ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D189 --- fuzz/fuzz.gyp | 157 +++++++++++++++++++++++++++++++++++----- fuzz/mpi_add_target.cc | 42 +++++++++++ fuzz/mpi_addmod_target.cc | 27 +++++++ fuzz/mpi_div_target.cc | 36 ++++++++++ fuzz/mpi_expmod_target.cc | 27 +++++++ fuzz/mpi_helper.cc | 100 ++++++++++++++++++++++++++ fuzz/mpi_helper.h | 60 ++++++++++++++++ fuzz/mpi_mod_target.cc | 36 ++++++++++ fuzz/mpi_mulmod_target.cc | 27 +++++++ fuzz/mpi_sqr_target.cc | 53 ++++++++++++++ fuzz/mpi_sqrmod_target.cc | 51 +++++++++++++ fuzz/mpi_sub_target.cc | 42 +++++++++++ fuzz/mpi_submod_target.cc | 27 +++++++ fuzz/mpi_target.cc | 177 ---------------------------------------------- 14 files changed, 667 insertions(+), 195 deletions(-) create mode 100644 fuzz/mpi_add_target.cc create mode 100644 fuzz/mpi_addmod_target.cc create mode 100644 fuzz/mpi_div_target.cc create mode 100644 fuzz/mpi_expmod_target.cc create mode 100644 fuzz/mpi_helper.cc create mode 100644 fuzz/mpi_helper.h create mode 100644 fuzz/mpi_mod_target.cc create mode 100644 fuzz/mpi_mulmod_target.cc create mode 100644 fuzz/mpi_sqr_target.cc create mode 100644 fuzz/mpi_sqrmod_target.cc create mode 100644 fuzz/mpi_sub_target.cc create mode 100644 fuzz/mpi_submod_target.cc delete mode 100644 fuzz/mpi_target.cc (limited to 'fuzz') diff --git a/fuzz/fuzz.gyp b/fuzz/fuzz.gyp index 6c9e0abc1..18b3aa365 100644 --- a/fuzz/fuzz.gyp +++ b/fuzz/fuzz.gyp @@ -65,6 +65,33 @@ }] ], }, + { + 'target_name': 'nssfuzz-mpi-base', + 'type': 'none', + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'fuzz_base', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(DEPTH)/lib/freebl/mpi', + ], + 'sources': [ + 'mpi_helper.cc', + ], + 'conditions': [ + [ 'fuzz_oss==1', { + 'libraries': [ + '/usr/lib/x86_64-linux-gnu/libcrypto.a', + ], + }, { + 'libraries': [ + '-lcrypto', + ], + }], + ], + }, + }, { 'target_name': 'nssfuzz-pkcs8', 'type': 'executable', @@ -101,39 +128,124 @@ ], }, { - 'target_name': 'nssfuzz-mpi', + 'target_name': 'nssfuzz-certDN', 'type': 'executable', 'sources': [ - 'mpi_target.cc', + 'certDN_target.cc', ], 'dependencies': [ '<(DEPTH)/exports.gyp:nss_exports', 'fuzz_base', ], - 'conditions': [ - [ 'fuzz_oss==1', { - 'libraries': [ - '/usr/lib/x86_64-linux-gnu/libcrypto.a', - ], - }, { - 'libraries': [ - '-lcrypto', - ], - }], + }, + { + 'target_name': 'nssfuzz-mpi-add', + 'type': 'executable', + 'sources': [ + 'mpi_add_target.cc', ], - 'include_dirs': [ - '<(DEPTH)/lib/freebl/mpi', + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', ], }, { - 'target_name': 'nssfuzz-certDN', + 'target_name': 'nssfuzz-mpi-sub', 'type': 'executable', 'sources': [ - 'certDN_target.cc', + 'mpi_sub_target.cc', ], 'dependencies': [ '<(DEPTH)/exports.gyp:nss_exports', - 'fuzz_base', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-sqr', + 'type': 'executable', + 'sources': [ + 'mpi_sqr_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-div', + 'type': 'executable', + 'sources': [ + 'mpi_div_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-mod', + 'type': 'executable', + 'sources': [ + 'mpi_mod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-sqrmod', + 'type': 'executable', + 'sources': [ + 'mpi_sqrmod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-addmod', + 'type': 'executable', + 'sources': [ + 'mpi_addmod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-submod', + 'type': 'executable', + 'sources': [ + 'mpi_submod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-mulmod', + 'type': 'executable', + 'sources': [ + 'mpi_mulmod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', + ], + }, + { + 'target_name': 'nssfuzz-mpi-expmod', + 'type': 'executable', + 'sources': [ + 'mpi_expmod_target.cc', + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + 'nssfuzz-mpi-base', ], }, { @@ -148,7 +260,16 @@ 'conditions': [ ['OS=="linux"', { 'dependencies': [ - 'nssfuzz-mpi', + 'nssfuzz-mpi-add', + 'nssfuzz-mpi-addmod', + 'nssfuzz-mpi-div', + 'nssfuzz-mpi-expmod', + 'nssfuzz-mpi-mod', + 'nssfuzz-mpi-mulmod', + 'nssfuzz-mpi-sqr', + 'nssfuzz-mpi-sqrmod', + 'nssfuzz-mpi-sub', + 'nssfuzz-mpi-submod', ], }], ], diff --git a/fuzz/mpi_add_target.cc b/fuzz/mpi_add_target.cc new file mode 100644 index 000000000..2c5247aa9 --- /dev/null +++ b/fuzz/mpi_add_target.cc @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + // Compare with OpenSSL addition + assert(mp_add(&a, &b, &c) == MP_OKAY); + (void)BN_add(C, A, B); + check_equal(C, &c, max_size); + + // Check a + b == a - -b + mp_neg(&b, &b); + assert(mp_sub(&a, &b, &r) == MP_OKAY); + bool eq = mp_cmp(&r, &c) == 0; + if (!eq) { + char rC[max_size], cC[max_size], aC[max_size], bC[max_size]; + mp_tohex(&r, rC); + mp_tohex(&c, cC); + mp_tohex(&a, aC); + mp_tohex(&b, bC); + std::cout << "a = " << std::hex << aC << std::endl; + std::cout << "-b = " << std::hex << bC << std::endl; + std::cout << "a + b = " << std::hex << cC << std::endl; + std::cout << "a - -b = " << std::hex << rC << std::endl; + } + assert(eq); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_addmod_target.cc b/fuzz/mpi_addmod_target.cc new file mode 100644 index 000000000..efa817983 --- /dev/null +++ b/fuzz/mpi_addmod_target.cc @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + auto modulus = get_modulus(data, size, ctx); + // Compare with OpenSSL add mod + m1 = &std::get<1>(modulus); + assert(mp_addmod(&a, &b, m1, &c) == MP_OKAY); + (void)BN_mod_add(C, A, B, std::get<0>(modulus), ctx); + check_equal(C, &c, max_size); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_div_target.cc b/fuzz/mpi_div_target.cc new file mode 100644 index 000000000..bee3f46d1 --- /dev/null +++ b/fuzz/mpi_div_target.cc @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + // We can't divide by 0. + if (mp_cmp_z(&b) == 0) { + CLEANUP_AND_RETURN + } + + // Compare with OpenSSL division + assert(mp_div(&a, &b, &c, &r) == MP_OKAY); + BN_div(C, R, A, B, ctx); + check_equal(C, &c, max_size); + check_equal(R, &r, max_size); + + // Check c * b + r == a + assert(mp_mul(&c, &b, &c) == MP_OKAY); + assert(mp_add(&c, &r, &c) == MP_OKAY); + assert(mp_cmp(&c, &a) == 0); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_expmod_target.cc b/fuzz/mpi_expmod_target.cc new file mode 100644 index 000000000..bc30169b1 --- /dev/null +++ b/fuzz/mpi_expmod_target.cc @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + auto modulus = get_modulus(data, size, ctx); + // Compare with OpenSSL exp mod + m1 = &std::get<1>(modulus); + assert(mp_exptmod(&a, &b, m1, &c) == MP_OKAY); + (void)BN_mod_exp(C, A, B, std::get<0>(modulus), ctx); + check_equal(C, &c, 2 * max_size); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_helper.cc b/fuzz/mpi_helper.cc new file mode 100644 index 000000000..65cf4b9cd --- /dev/null +++ b/fuzz/mpi_helper.cc @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Helper functions for MPI fuzzing targets. */ + +#include "mpi_helper.h" +#include +#include + +char *to_char(const uint8_t *x) { + return reinterpret_cast(const_cast(x)); +} + +// Check that the two numbers are equal. +void check_equal(BIGNUM *b, mp_int *m, size_t max_size) { + char *bnBc = BN_bn2hex(b); + char mpiMc[max_size]; + mp_tohex(m, mpiMc); + std::string bnA(bnBc); + std::string mpiA(mpiMc); + OPENSSL_free(bnBc); + // We have to strip leading zeros from bignums, ignoring the sign. + if (bnA.at(0) != '-') { + bnA.erase(0, std::min(bnA.find_first_not_of('0'), bnA.size() - 1)); + } else if (bnA.at(1) == '0') { + bnA.erase(1, std::min(bnA.find_first_not_of('0', 1) - 1, bnA.size() - 1)); + } + + if (mpiA != bnA) { + std::cout << "openssl: " << std::hex << bnA << std::endl; + std::cout << "nss: " << std::hex << mpiA << std::endl; + } + + assert(mpiA == bnA); +} + +// Parse data into two numbers for MPI and OpenSSL Bignum. +void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B, + mp_int *a, mp_int *b) { + // Note that b might overlap a. + size_t len = (size_t)size / 2; + assert(mp_read_raw(a, to_char(data), len) == MP_OKAY); + assert(mp_read_raw(b, to_char(data) + len, len) == MP_OKAY); + // Force a positive sign. + // TODO: add tests for negatives. + MP_SIGN(a) = MP_ZPOS; + MP_SIGN(b) = MP_ZPOS; + + // Skip the first byte as it's interpreted as sign by NSS. + assert(BN_bin2bn(data + 1, len - 1, A) != nullptr); + assert(BN_bin2bn(data + len + 1, len - 1, B) != nullptr); + + check_equal(A, a, 2 * size + 1); + check_equal(B, b, 2 * size + 1); +} + +// Parse data into a number for MPI and OpenSSL Bignum. +void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a) { + assert(mp_read_raw(a, to_char(data), size) == MP_OKAY); + + // Force a positive sign. + // TODO: add tests for negatives. + MP_SIGN(a) = MP_ZPOS; + + // Skip the first byte as it's interpreted as sign by NSS. + assert(BN_bin2bn(data + 1, size - 1, A) != nullptr); + + check_equal(A, a, 4 * size + 1); +} + +// Take a chunk in the middle of data and use it as modulus. +std::tuple get_modulus(const uint8_t *data, size_t size, + BN_CTX *ctx) { + BIGNUM *r1 = BN_CTX_get(ctx); + mp_int r2; + assert(mp_init(&r2) == MP_OKAY); + + size_t len = static_cast(size / 4); + if (len != 0) { + assert(mp_read_raw(&r2, to_char(data + len), len) == MP_OKAY); + MP_SIGN(&r2) = MP_ZPOS; + + assert(BN_bin2bn(data + len + 1, len - 1, r1) != nullptr); + check_equal(r1, &r2, 2 * len + 1); + } + + // If we happen to get 0 for the modulus, take a random number. + if (mp_cmp_z(&r2) == 0 || len == 0) { + mp_zero(&r2); + BN_zero(r1); + std::mt19937 rng(data[0]); + std::uniform_int_distribution dist(1, MP_DIGIT_MAX); + mp_digit x = dist(rng); + mp_add_d(&r2, x, &r2); + BN_add_word(r1, x); + } + + return std::make_tuple(r1, r2); +} diff --git a/fuzz/mpi_helper.h b/fuzz/mpi_helper.h new file mode 100644 index 000000000..8775b533f --- /dev/null +++ b/fuzz/mpi_helper.h @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Helper functions for MPI fuzzing targets. */ + +#ifndef mpi_helper_h__ +#define mpi_helper_h__ + +#include +#include +#include +#include + +#include "hasht.h" +#include "mpi.h" + +#include + +void check_equal(BIGNUM *b, mp_int *m, size_t max_size); +void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B, + mp_int *a, mp_int *b); +void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a); +std::tuple get_modulus(const uint8_t *data, size_t size, + BN_CTX *ctx); + +// Initialise MPI and BN variables +// XXX: Also silence unused variable warnings for R. +#define INIT_NUMBERS \ + mp_int a, b, c, r; \ + mp_int *m1 = nullptr; \ + BN_CTX *ctx = BN_CTX_new(); \ + BN_CTX_start(ctx); \ + BIGNUM *A = BN_CTX_get(ctx); \ + BIGNUM *B = BN_CTX_get(ctx); \ + BIGNUM *C = BN_CTX_get(ctx); \ + BIGNUM *R = BN_CTX_get(ctx); \ + assert(mp_init(&a) == MP_OKAY); \ + assert(mp_init(&b) == MP_OKAY); \ + assert(mp_init(&c) == MP_OKAY); \ + assert(mp_init(&r) == MP_OKAY); \ + size_t max_size = 2 * size + 1; \ + parse_input(data, size, A, B, &a, &b); \ + do { \ + (void)(R); \ + } while (0); + +#define CLEANUP_AND_RETURN \ + mp_clear(&a); \ + mp_clear(&b); \ + mp_clear(&c); \ + mp_clear(&r); \ + if (m1) { \ + mp_clear(m1); \ + } \ + BN_CTX_end(ctx); \ + BN_CTX_free(ctx); \ + return 0; + +#endif // mpi_helper_h__ diff --git a/fuzz/mpi_mod_target.cc b/fuzz/mpi_mod_target.cc new file mode 100644 index 000000000..2be1bf081 --- /dev/null +++ b/fuzz/mpi_mod_target.cc @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + // We can't divide by 0. + if (mp_cmp_z(&b) == 0) { + CLEANUP_AND_RETURN + } + + // Compare with OpenSSL mod + assert(mp_mod(&a, &b, &c) == MP_OKAY); + (void)BN_mod(C, A, B, ctx); + check_equal(C, &c, max_size); + + // Check a mod b = a - floor(a / b) * b + assert(mp_div(&a, &b, &r, nullptr) == MP_OKAY); + assert(mp_mul(&r, &b, &r) == MP_OKAY); + assert(mp_sub(&a, &r, &r) == MP_OKAY); + assert(mp_cmp(&c, &r) == 0); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_mulmod_target.cc b/fuzz/mpi_mulmod_target.cc new file mode 100644 index 000000000..7bd4261fa --- /dev/null +++ b/fuzz/mpi_mulmod_target.cc @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + auto modulus = get_modulus(data, size, ctx); + // Compare with OpenSSL mul mod + m1 = &std::get<1>(modulus); + assert(mp_mulmod(&a, &b, m1, &c) == MP_OKAY); + (void)BN_mod_mul(C, A, B, std::get<0>(modulus), ctx); + check_equal(C, &c, max_size); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_sqr_target.cc b/fuzz/mpi_sqr_target.cc new file mode 100644 index 000000000..1b8504085 --- /dev/null +++ b/fuzz/mpi_sqr_target.cc @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 2 to get an integers from Data. + if (size < 2) { + return 0; + } + mp_int a, c, r; + BN_CTX *ctx = BN_CTX_new(); + BN_CTX_start(ctx); + BIGNUM *A = BN_CTX_get(ctx); + BIGNUM *C = BN_CTX_get(ctx); + assert(mp_init(&a) == MP_OKAY); + assert(mp_init(&c) == MP_OKAY); + assert(mp_init(&r) == MP_OKAY); + size_t max_size = 4 * size + 1; + parse_input(data, size, A, &a); + + // Compare with OpenSSL sqr + assert(mp_sqr(&a, &c) == MP_OKAY); + (void)BN_sqr(C, A, ctx); + check_equal(C, &c, max_size); + + // Check a * a == a**2 + assert(mp_mul(&a, &a, &r) == MP_OKAY); + bool eq = mp_cmp(&r, &c) == 0; + if (!eq) { + char rC[max_size], cC[max_size], aC[max_size]; + mp_tohex(&r, rC); + mp_tohex(&c, cC); + mp_tohex(&a, aC); + std::cout << "a = " << std::hex << aC << std::endl; + std::cout << "a * a = " << std::hex << cC << std::endl; + std::cout << "a ** 2 = " << std::hex << rC << std::endl; + } + assert(eq); + mp_clear(&a); + mp_clear(&c); + mp_clear(&r); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return 0; +} diff --git a/fuzz/mpi_sqrmod_target.cc b/fuzz/mpi_sqrmod_target.cc new file mode 100644 index 000000000..d3886dacd --- /dev/null +++ b/fuzz/mpi_sqrmod_target.cc @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + mp_int a, b, c; + BN_CTX *ctx = BN_CTX_new(); + BN_CTX_start(ctx); + BIGNUM *A = BN_CTX_get(ctx); + BIGNUM *B = BN_CTX_get(ctx); + BIGNUM *C = BN_CTX_get(ctx); + assert(mp_init(&a) == MP_OKAY); + assert(mp_init(&b) == MP_OKAY); + assert(mp_init(&c) == MP_OKAY); + size_t max_size = 4 * size + 1; + parse_input(data, size, A, &a); + + // We can't divide by 0. + if (mp_cmp_z(&b) == 0) { + mp_clear(&a); + mp_clear(&b); + mp_clear(&c); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return 0; + } + + // Compare with OpenSSL square mod + assert(mp_sqrmod(&a, &b, &c) == MP_OKAY); + (void)BN_mod_sqr(C, A, B, ctx); + check_equal(C, &c, max_size); + + mp_clear(&a); + mp_clear(&b); + mp_clear(&c); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return 0; +} diff --git a/fuzz/mpi_sub_target.cc b/fuzz/mpi_sub_target.cc new file mode 100644 index 000000000..1c8a4e90d --- /dev/null +++ b/fuzz/mpi_sub_target.cc @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + // Compare with OpenSSL subtraction + assert(mp_sub(&a, &b, &c) == MP_OKAY); + (void)BN_sub(C, A, B); + check_equal(C, &c, max_size); + + // Check a - b == a + -b + mp_neg(&b, &b); + assert(mp_add(&a, &b, &r) == MP_OKAY); + bool eq = mp_cmp(&r, &c) == 0; + if (!eq) { + char rC[max_size], cC[max_size], aC[max_size], bC[max_size]; + mp_tohex(&r, rC); + mp_tohex(&c, cC); + mp_tohex(&a, aC); + mp_tohex(&b, bC); + std::cout << "a = " << std::hex << aC << std::endl; + std::cout << "-b = " << std::hex << bC << std::endl; + std::cout << "a - b = " << std::hex << cC << std::endl; + std::cout << "a + -b = " << std::hex << rC << std::endl; + } + assert(eq); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_submod_target.cc b/fuzz/mpi_submod_target.cc new file mode 100644 index 000000000..d44faceda --- /dev/null +++ b/fuzz/mpi_submod_target.cc @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This target fuzzes NSS mpi against openssl bignum. + * It therefore requires openssl to be installed. + */ + +#include "mpi_helper.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // We require at least size 3 to get two integers from Data. + if (size < 3) { + return 0; + } + INIT_NUMBERS + + auto modulus = get_modulus(data, size, ctx); + // Compare with OpenSSL sub mod + m1 = &std::get<1>(modulus); + assert(mp_submod(&a, &b, m1, &c) == MP_OKAY); + (void)BN_mod_sub(C, A, B, std::get<0>(modulus), ctx); + check_equal(C, &c, 2 * max_size); + + CLEANUP_AND_RETURN +} diff --git a/fuzz/mpi_target.cc b/fuzz/mpi_target.cc deleted file mode 100644 index 9dbe15e7c..000000000 --- a/fuzz/mpi_target.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * This target fuzzes NSS mpi against openssl bignum. - * It therefore requires openssl to be installed. - */ - -#include -#include -#include - -#include "hasht.h" -#include "mpi.h" -#include "shared.h" - -#include - -#define CLEAR_NUMS \ - mp_zero(&c); \ - BN_zero(C); \ - mp_zero(&r); \ - BN_zero(R); - -// Check that the two numbers are equal. -void check_equal(BIGNUM *b, mp_int *m, size_t max_size) { - char *bnBc = BN_bn2hex(b); - char mpiMc[max_size]; - mp_tohex(m, mpiMc); - std::string bnA(bnBc); - std::string mpiA(mpiMc); - OPENSSL_free(bnBc); - // We have to strip leading zeros from bignums, ignoring the sign. - if (bnA.at(0) != '-') { - bnA.erase(0, std::min(bnA.find_first_not_of('0'), bnA.size() - 1)); - } else if (bnA.at(1) == '0') { - bnA.erase(1, std::min(bnA.find_first_not_of('0', 1) - 1, bnA.size() - 1)); - } - - if (mpiA != bnA) { - std::cout << "openssl: " << std::hex << bnA << std::endl; - std::cout << "nss: " << std::hex << mpiA << std::endl; - } - - assert(mpiA == bnA); -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - // We require at least size 3 to get two integers from Data. - if (size <= 3) { - return 0; - } - size_t max_size = 2 * size + 1; - - mp_int a, b, c, r; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *A = BN_CTX_get(ctx); - BIGNUM *B = BN_CTX_get(ctx); - BIGNUM *C = BN_CTX_get(ctx); - BIGNUM *R = BN_CTX_get(ctx); - assert(mp_init(&a) == MP_OKAY); - assert(mp_init(&b) == MP_OKAY); - assert(mp_init(&c) == MP_OKAY); - assert(mp_init(&r) == MP_OKAY); - - // Note that b might overlap a. - size_t len = (size_t)size / 2; - assert(mp_read_raw( - &a, reinterpret_cast(const_cast(data)), - len) == MP_OKAY); - assert(mp_read_raw( - &b, - reinterpret_cast(const_cast(data)) + len, - len) == MP_OKAY); - // Force a positive sign. - // TODO: add tests for negatives. - MP_SIGN(&a) = MP_ZPOS; - MP_SIGN(&b) = MP_ZPOS; - - // Skip the first byte as it's interpreted as sign by NSS. - assert(BN_bin2bn(data + 1, len - 1, A) != nullptr); - assert(BN_bin2bn(data + len + 1, len - 1, B) != nullptr); - - check_equal(A, &a, max_size); - check_equal(B, &b, max_size); - - // Addition - assert(mp_add(&a, &b, &c) == MP_OKAY); - (void)BN_add(C, A, B); - check_equal(C, &c, max_size); - - // Subtraction - CLEAR_NUMS - assert(mp_sub(&a, &b, &c) == MP_OKAY); - (void)BN_sub(C, A, B); - check_equal(C, &c, max_size); - - // Sqr - CLEAR_NUMS - assert(mp_sqr(&a, &c) == MP_OKAY); - (void)BN_sqr(C, A, ctx); - check_equal(C, &c, max_size); - - // We can't divide by 0. - if (mp_cmp_z(&b) != 0) { - CLEAR_NUMS - assert(mp_div(&a, &b, &c, &r) == MP_OKAY); - BN_div(C, R, A, B, ctx); - check_equal(C, &c, max_size); - check_equal(R, &r, max_size); - - // Modulo - CLEAR_NUMS - assert(mp_mod(&a, &b, &c) == MP_OKAY); - (void)BN_mod(C, A, B, ctx); - check_equal(C, &c, max_size); - - // Mod sqr - CLEAR_NUMS - assert(mp_sqrmod(&a, &b, &c) == MP_OKAY); - (void)BN_mod_sqr(C, A, B, ctx); - check_equal(C, &c, max_size); - } - - // Mod add - CLEAR_NUMS - mp_add(&a, &b, &r); - (void)BN_add(R, A, B); - assert(mp_addmod(&a, &b, &r, &c) == MP_OKAY); - (void)BN_mod_add(C, A, B, R, ctx); - check_equal(C, &c, max_size); - - // Mod sub - CLEAR_NUMS - mp_add(&a, &b, &r); - (void)BN_add(R, A, B); - assert(mp_submod(&a, &b, &r, &c) == MP_OKAY); - (void)BN_mod_sub(C, A, B, R, ctx); - check_equal(C, &c, max_size); - - // Mod mul - CLEAR_NUMS - mp_add(&a, &b, &r); - (void)BN_add(R, A, B); - assert(mp_mulmod(&a, &b, &r, &c) == MP_OKAY); - (void)BN_mod_mul(C, A, B, R, ctx); - check_equal(C, &c, max_size); - - // Mod exp - // NOTE: This must be the last test as we change b! - CLEAR_NUMS - mp_add(&a, &b, &r); - mp_add_d(&r, 1, &r); // NSS doesn't allow 0 as modulus here. - size_t num = MP_USED(&b) * MP_DIGIT_BIT; - mp_div_2d(&b, num, &b, nullptr); // make the exponent smaller, larger - // exponents need too much memory - MP_USED(&b) = 1; - (void)BN_add(R, A, B); - BN_add_word(R, 1); - BN_rshift(B, B, num); - check_equal(B, &b, max_size); - assert(mp_exptmod(&a, &b, &r, &c) == MP_OKAY); - (void)BN_mod_exp(C, A, B, R, ctx); - check_equal(C, &c, max_size); - - mp_clear(&a); - mp_clear(&b); - mp_clear(&c); - mp_clear(&r); - - BN_CTX_end(ctx); - BN_CTX_free(ctx); - - return 0; -} -- cgit v1.2.1