From 7f8c553d7f4db0a6ce727f2986d41bf8fe8ec4bf Mon Sep 17 00:00:00 2001 From: Steven Valdez Date: Tue, 3 Oct 2017 13:14:18 -0400 Subject: [PATCH] Add BN fuzzer. Change-Id: I09396e34d09a71bed40eefece1eae90ba2b5086f Reviewed-on: https://boringssl-review.googlesource.com/21024 Reviewed-by: David Benjamin Commit-Queue: Steven Valdez CQ-Verified: CQ bot account: commit-bot@chromium.org --- fuzz/CMakeLists.txt | 18 +++++++ fuzz/bn_div.cc | 69 ++++++++++++++++++++++++++ fuzz/bn_mod_exp.cc | 115 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 fuzz/bn_div.cc create mode 100644 fuzz/bn_mod_exp.cc diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 5eff3d9b..eddb38c5 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -2,6 +2,24 @@ include_directories(../include) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-prototypes") +add_executable( + bn_mod_exp + + bn_mod_exp.cc +) + +target_link_libraries(bn_mod_exp Fuzzer) +target_link_libraries(bn_mod_exp crypto) + +add_executable( + bn_div + + bn_div.cc +) + +target_link_libraries(bn_div Fuzzer) +target_link_libraries(bn_div crypto) + add_executable( privkey diff --git a/fuzz/bn_div.cc b/fuzz/bn_div.cc new file mode 100644 index 00000000..8994826e --- /dev/null +++ b/fuzz/bn_div.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2017, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#define CHECK(expr) \ + do { \ + if (!(expr)) { \ + printf("%s failed\n", #expr); \ + abort(); \ + } \ + } while (false) + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + CBS cbs, child0, child1; + uint8_t sign0, sign1; + CBS_init(&cbs, buf, len); + if (!CBS_get_u8_length_prefixed(&cbs, &child0) || + !CBS_get_u8(&child0, &sign0) || + CBS_len(&child0) == 0 || + !CBS_get_u8_length_prefixed(&cbs, &child1) || + !CBS_get_u8(&child1, &sign1) || + CBS_len(&child1) == 0) { + return 0; + } + + bssl::UniquePtr numerator( + BN_bin2bn(CBS_data(&child0), CBS_len(&child0), nullptr)); + BN_set_negative(numerator.get(), sign0 % 2); + bssl::UniquePtr divisor( + BN_bin2bn(CBS_data(&child1), CBS_len(&child1), nullptr)); + BN_set_negative(divisor.get(), sign1 % 2); + + if (BN_is_zero(divisor.get())) { + return 0; + } + + bssl::UniquePtr ctx(BN_CTX_new()); + bssl::UniquePtr result(BN_new()); + bssl::UniquePtr remainder(BN_new()); + CHECK(ctx); + CHECK(result); + CHECK(remainder); + + + CHECK(BN_div(result.get(), remainder.get(), numerator.get(), divisor.get(), + ctx.get())); + CHECK(BN_ucmp(remainder.get(), divisor.get()) < 0); + + // Check that result*divisor+remainder = numerator. + CHECK(BN_mul(result.get(), result.get(), divisor.get(), ctx.get())); + CHECK(BN_add(result.get(), result.get(), remainder.get())); + CHECK(BN_cmp(result.get(), numerator.get()) == 0); + + return 0; +} diff --git a/fuzz/bn_mod_exp.cc b/fuzz/bn_mod_exp.cc new file mode 100644 index 00000000..e38236d0 --- /dev/null +++ b/fuzz/bn_mod_exp.cc @@ -0,0 +1,115 @@ +/* Copyright (c) 2017, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#define CHECK(expr) \ + do { \ + if (!(expr)) { \ + printf("%s failed\n", #expr); \ + abort(); \ + } \ + } while (false) + +// Basic implementation of mod_exp using square and multiple method. +int mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx) { + if (BN_is_one(m)) { + BN_zero(r); + return 1; + } + + bssl::UniquePtr exp(BN_dup(p)); + bssl::UniquePtr base(BN_new()); + if (!exp || !base) { + return 0; + } + if (!BN_one(r) || !BN_nnmod(base.get(), a, m, ctx)) { + return 0; + } + + while (!BN_is_zero(exp.get())) { + if (BN_is_odd(exp.get())) { + if (!BN_mul(r, r, base.get(), ctx) || !BN_nnmod(r, r, m, ctx)) { + return 0; + } + } + if (!BN_rshift1(exp.get(), exp.get()) || + !BN_mul(base.get(), base.get(), base.get(), ctx) || + !BN_nnmod(base.get(), base.get(), m, ctx)) { + return 0; + } + } + + return 1; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + CBS cbs, child0, child1, child2; + uint8_t sign; + CBS_init(&cbs, buf, len); + if (!CBS_get_u8_length_prefixed(&cbs, &child0) || + !CBS_get_u8(&child0, &sign) || + CBS_len(&child0) == 0 || + !CBS_get_u8_length_prefixed(&cbs, &child1) || + CBS_len(&child1) == 0 || + !CBS_get_u8_length_prefixed(&cbs, &child2) || + CBS_len(&child2) == 0) { + return 0; + } + bssl::UniquePtr base( + BN_bin2bn(CBS_data(&child0), CBS_len(&child0), nullptr)); + BN_set_negative(base.get(), sign % 2); + bssl::UniquePtr power( + BN_bin2bn(CBS_data(&child1), CBS_len(&child1), nullptr)); + bssl::UniquePtr modulus( + BN_bin2bn(CBS_data(&child2), CBS_len(&child2), nullptr)); + + if (BN_is_zero(modulus.get())) { + return 0; + } + + bssl::UniquePtr ctx(BN_CTX_new()); + bssl::UniquePtr mont(BN_MONT_CTX_new()); + bssl::UniquePtr result(BN_new()); + bssl::UniquePtr expected(BN_new()); + CHECK(ctx); + CHECK(mont); + CHECK(result); + CHECK(expected); + + CHECK(mod_exp(expected.get(), base.get(), power.get(), modulus.get(), + ctx.get())); + CHECK(BN_mod_exp(result.get(), base.get(), power.get(), modulus.get(), + ctx.get())); + CHECK(BN_cmp(result.get(), expected.get()) == 0); + + if (BN_is_odd(modulus.get())) { + CHECK(BN_MONT_CTX_set(mont.get(), modulus.get(), ctx.get())); + CHECK(BN_mod_exp_mont(result.get(), base.get(), power.get(), modulus.get(), + ctx.get(), mont.get())); + CHECK(BN_cmp(result.get(), expected.get()) == 0); + CHECK(BN_mod_exp_mont_consttime(result.get(), base.get(), power.get(), + modulus.get(), ctx.get(), mont.get())); + CHECK(BN_cmp(result.get(), expected.get()) == 0); + } + + uint8_t *data = (uint8_t *)OPENSSL_malloc(BN_num_bytes(result.get())); + BN_bn2bin(result.get(), data); + OPENSSL_free(data); + + return 0; +}