summaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorFranziskus Kiefer <franziskuskiefer@gmail.com>2017-02-08 11:17:15 +0100
committerFranziskus Kiefer <franziskuskiefer@gmail.com>2017-02-08 11:17:15 +0100
commit0b281a3b0744b6c477aa1cbbde00d8910581f236 (patch)
treedfd20406072399d3af0ef7c170927f4f0266a53f /fuzz
parent353a1a1cbca51f6fd056f5f4d0d5e2d49e65134b (diff)
downloadnss-hg-0b281a3b0744b6c477aa1cbbde00d8910581f236.tar.gz
Bug 1334106 - split mpi target, r=ttaubert
Differential Revision: https://nss-review.dev.mozaws.net/D189
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/fuzz.gyp157
-rw-r--r--fuzz/mpi_add_target.cc42
-rw-r--r--fuzz/mpi_addmod_target.cc27
-rw-r--r--fuzz/mpi_div_target.cc36
-rw-r--r--fuzz/mpi_expmod_target.cc27
-rw-r--r--fuzz/mpi_helper.cc100
-rw-r--r--fuzz/mpi_helper.h60
-rw-r--r--fuzz/mpi_mod_target.cc36
-rw-r--r--fuzz/mpi_mulmod_target.cc27
-rw-r--r--fuzz/mpi_sqr_target.cc53
-rw-r--r--fuzz/mpi_sqrmod_target.cc51
-rw-r--r--fuzz/mpi_sub_target.cc42
-rw-r--r--fuzz/mpi_submod_target.cc27
-rw-r--r--fuzz/mpi_target.cc177
14 files changed, 667 insertions, 195 deletions
diff --git a/fuzz/fuzz.gyp b/fuzz/fuzz.gyp
index 6c9e0abc1..18b3aa365 100644
--- a/fuzz/fuzz.gyp
+++ b/fuzz/fuzz.gyp
@@ -66,6 +66,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',
'sources': [
@@ -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 <cstdlib>
+#include <random>
+
+char *to_char(const uint8_t *x) {
+ return reinterpret_cast<char *>(const_cast<unsigned char *>(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<BIGNUM *, mp_int> 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_t>(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<mp_digit> 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 <iostream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "hasht.h"
+#include "mpi.h"
+
+#include <openssl/bn.h>
+
+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<BIGNUM *, mp_int> 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 <algorithm>
-#include <iostream>
-#include <string>
-
-#include "hasht.h"
-#include "mpi.h"
-#include "shared.h"
-
-#include <openssl/bn.h>
-
-#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<char *>(const_cast<unsigned char *>(data)),
- len) == MP_OKAY);
- assert(mp_read_raw(
- &b,
- reinterpret_cast<char *>(const_cast<unsigned 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, 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;
-}