/src/nss/fuzz/mpi_helper.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | /* Helper functions for MPI fuzzing targets. */ |
6 | | |
7 | | #include "mpi_helper.h" |
8 | | #include <cstdlib> |
9 | | #include <random> |
10 | | |
11 | 1.23k | char *to_char(const uint8_t *x) { |
12 | 1.23k | return reinterpret_cast<char *>(const_cast<unsigned char *>(x)); |
13 | 1.23k | } |
14 | | |
15 | 0 | void print_bn(std::string label, BIGNUM *x) { |
16 | 0 | char *xc = BN_bn2hex(x); |
17 | 0 | std::cout << label << ": " << std::hex << xc << std::endl; |
18 | 0 | OPENSSL_free(xc); |
19 | 0 | } |
20 | | |
21 | | // Check that the two numbers are equal. |
22 | 2.46k | void check_equal(BIGNUM *b, mp_int *m, size_t max_size) { |
23 | 2.46k | char *bnBc = BN_bn2hex(b); |
24 | 2.46k | char mpiMc[max_size]; |
25 | 2.46k | mp_tohex(m, mpiMc); |
26 | 2.46k | std::string bnA(bnBc); |
27 | 2.46k | std::string mpiA(mpiMc); |
28 | 2.46k | OPENSSL_free(bnBc); |
29 | | // We have to strip leading zeros from bignums, ignoring the sign. |
30 | 2.46k | if (bnA.at(0) != '-') { |
31 | 2.46k | bnA.erase(0, std::min(bnA.find_first_not_of('0'), bnA.size() - 1)); |
32 | 2.46k | } else if (bnA.at(1) == '0') { |
33 | 0 | bnA.erase(1, std::min(bnA.find_first_not_of('0', 1) - 1, bnA.size() - 1)); |
34 | 0 | } |
35 | | |
36 | 2.46k | if (mpiA != bnA) { |
37 | 0 | std::cout << "openssl: " << std::hex << bnA << std::endl; |
38 | 0 | std::cout << "nss: " << std::hex << mpiA << std::endl; |
39 | 0 | } |
40 | | |
41 | 2.46k | assert(mpiA == bnA); |
42 | 2.46k | } |
43 | | |
44 | | // Parse data into two numbers for MPI and OpenSSL Bignum. |
45 | | void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B, |
46 | 0 | mp_int *a, mp_int *b) { |
47 | | // Note that b might overlap a. |
48 | 0 | size_t len = (size_t)size / 2; |
49 | 0 | assert(mp_read_raw(a, to_char(data), len) == MP_OKAY); |
50 | 0 | assert(mp_read_raw(b, to_char(data) + len, len) == MP_OKAY); |
51 | | // Force a positive sign. |
52 | | // TODO: add tests for negatives. |
53 | 0 | MP_SIGN(a) = MP_ZPOS; |
54 | 0 | MP_SIGN(b) = MP_ZPOS; |
55 | | |
56 | | // Skip the first byte as it's interpreted as sign by NSS. |
57 | 0 | assert(BN_bin2bn(data + 1, len - 1, A) != nullptr); |
58 | 0 | assert(BN_bin2bn(data + len + 1, len - 1, B) != nullptr); |
59 | | |
60 | 0 | check_equal(A, a, 2 * size + 1); |
61 | 0 | check_equal(B, b, 2 * size + 1); |
62 | 0 | } |
63 | | |
64 | | // Parse data into a number for MPI and OpenSSL Bignum. |
65 | 1.23k | void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a) { |
66 | 1.23k | assert(mp_read_raw(a, to_char(data), size) == MP_OKAY); |
67 | | |
68 | | // Force a positive sign. |
69 | | // TODO: add tests for negatives. |
70 | 1.23k | MP_SIGN(a) = MP_ZPOS; |
71 | | |
72 | | // Skip the first byte as it's interpreted as sign by NSS. |
73 | 1.23k | assert(BN_bin2bn(data + 1, size - 1, A) != nullptr); |
74 | | |
75 | 1.23k | check_equal(A, a, 4 * size + 1); |
76 | 1.23k | } |
77 | | |
78 | | // Take a chunk in the middle of data and use it as modulus. |
79 | | std::tuple<BIGNUM *, mp_int> get_modulus(const uint8_t *data, size_t size, |
80 | 0 | BN_CTX *ctx) { |
81 | 0 | BIGNUM *r1 = BN_CTX_get(ctx); |
82 | 0 | mp_int r2; |
83 | 0 | assert(mp_init(&r2) == MP_OKAY); |
84 | | |
85 | 0 | size_t len = static_cast<size_t>(size / 4); |
86 | 0 | if (len != 0) { |
87 | 0 | assert(mp_read_raw(&r2, to_char(data + len), len) == MP_OKAY); |
88 | 0 | MP_SIGN(&r2) = MP_ZPOS; |
89 | |
|
90 | 0 | assert(BN_bin2bn(data + len + 1, len - 1, r1) != nullptr); |
91 | 0 | check_equal(r1, &r2, 2 * len + 1); |
92 | 0 | } |
93 | | |
94 | | // If we happen to get 0 for the modulus, take a random number. |
95 | 0 | if (mp_cmp_z(&r2) == 0 || len == 0) { |
96 | 0 | mp_zero(&r2); |
97 | 0 | BN_zero(r1); |
98 | 0 | std::mt19937 rng(data[0]); |
99 | 0 | std::uniform_int_distribution<mp_digit> dist(1, MP_DIGIT_MAX); |
100 | 0 | mp_digit x = dist(rng); |
101 | 0 | mp_add_d(&r2, x, &r2); |
102 | 0 | BN_add_word(r1, x); |
103 | 0 | } |
104 | |
|
105 | 0 | return std::make_tuple(r1, r2); |
106 | 0 | } |