#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <limits>
#include <utility>
#include <gtest/gtest.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include "./internal.h"
#include "./rsaz_exp.h"
#include "../../internal.h"
#include "../../test/abi_test.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
#include "../../test/wycheproof_util.h"
static int HexToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) { … }
class BIGNUMFileTest { … };
static testing::AssertionResult AssertBIGNUMSEqual(
const char *operation_expr, const char *expected_expr,
const char *actual_expr, const char *operation, const BIGNUM *expected,
const BIGNUM *actual) { … }
#define EXPECT_BIGNUMS_EQUAL(op, a, b) …
static void TestSum(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestLShift1(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestLShift(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestRShift(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestSquare(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestProduct(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestModMul(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestModSquare(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestModExp(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestExp(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestModSqrt(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestNotModSquare(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestModInv(BIGNUMFileTest *t, BN_CTX *ctx) { … }
static void TestGCD(BIGNUMFileTest *t, BN_CTX *ctx) { … }
class BNTest : public testing::Test { … };
static void RunBNFileTest(FileTest *t, BN_CTX *ctx) { … }
TEST_F(BNTest, ExpTestVectors) { … }
TEST_F(BNTest, GCDTestVectors) { … }
TEST_F(BNTest, ModExpTestVectors) { … }
TEST_F(BNTest, ModInvTestVectors) { … }
TEST_F(BNTest, ModMulTestVectors) { … }
TEST_F(BNTest, ModSqrtTestVectors) { … }
TEST_F(BNTest, ProductTestVectors) { … }
TEST_F(BNTest, QuotientTestVectors) { … }
TEST_F(BNTest, ShiftTestVectors) { … }
TEST_F(BNTest, SumTestVectors) { … }
TEST_F(BNTest, BN2BinPadded) { … }
TEST_F(BNTest, LittleEndian) { … }
static int DecimalToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) { … }
TEST_F(BNTest, Dec2BN) { … }
TEST_F(BNTest, Hex2BN) { … }
static bssl::UniquePtr<BIGNUM> ASCIIToBIGNUM(const char *in) { … }
TEST_F(BNTest, ASC2BN) { … }
struct MPITest { … };
static const MPITest kMPITests[] = …;
TEST_F(BNTest, MPI) { … }
TEST_F(BNTest, Rand) { … }
TEST_F(BNTest, RandRange) { … }
struct ASN1Test { … };
static const ASN1Test kASN1Tests[] = …;
struct ASN1InvalidTest { … };
static const ASN1InvalidTest kASN1InvalidTests[] = …;
TEST_F(BNTest, ASN1) { … }
TEST_F(BNTest, NegativeZero) { … }
TEST_F(BNTest, BadModulus) { … }
TEST_F(BNTest, ExpZeroModOne) { … }
TEST_F(BNTest, SmallPrime) { … }
TEST_F(BNTest, CmpWord) { … }
TEST_F(BNTest, BN2Dec) { … }
TEST_F(BNTest, SetGetU64) { … }
TEST_F(BNTest, Pow2) { … }
static const int kPrimes[] = …;
TEST_F(BNTest, PrimeChecking) { … }
TEST_F(BNTest, MillerRabinIteration) { … }
TEST_F(BNTest, DISABLED_WycheproofPrimality) { … }
TEST_F(BNTest, NumBitsWord) { … }
#if !defined(BORINGSSL_SHARED_LIBRARY)
TEST_F(BNTest, LessThanWords) {
static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000002), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x0000ffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0xfffffffe), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0xffffffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xed17ac85, 0x83339914), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000001),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
};
size_t one_word;
for (one_word = 0; one_word < OPENSSL_ARRAY_SIZE(kTestVectors); one_word++) {
int is_word = 1;
for (size_t i = 1; i < OPENSSL_ARRAY_SIZE(kTestVectors[one_word]); i++) {
if (kTestVectors[one_word][i] != 0) {
is_word = 0;
break;
}
}
if (!is_word) {
break;
}
}
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
SCOPED_TRACE(i);
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
SCOPED_TRACE(j);
EXPECT_EQ(i < j ? 1 : 0,
bn_less_than_words(kTestVectors[i], kTestVectors[j],
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
for (size_t k = 0; k < one_word; k++) {
SCOPED_TRACE(k);
EXPECT_EQ(k <= i && i < j ? 1 : 0,
bn_in_range_words(kTestVectors[i], kTestVectors[k][0],
kTestVectors[j],
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
}
}
}
EXPECT_EQ(0, bn_less_than_words(NULL, NULL, 0));
EXPECT_EQ(0, bn_in_range_words(NULL, 0, NULL, 0));
}
#endif
TEST_F(BNTest, NonMinimal) { … }
TEST_F(BNTest, CountLowZeroBits) { … }
TEST_F(BNTest, WriteIntoNegative) { … }
TEST_F(BNTest, ModSqrtInvalid) { … }
TEST_F(BNTest, MontgomeryLarge) { … }
TEST_F(BNTest, FormatWord) { … }
#if defined(SUPPORTS_ABI_TEST)
TEST_F(BNTest, ArithmeticABI) {
EXPECT_EQ(0u, CHECK_ABI(bn_add_words, nullptr, nullptr, nullptr, 0));
EXPECT_EQ(0u, CHECK_ABI(bn_sub_words, nullptr, nullptr, nullptr, 0));
for (size_t num :
{1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65}) {
SCOPED_TRACE(num);
std::vector<BN_ULONG> a(num, 123456789);
std::vector<BN_ULONG> b(num, static_cast<BN_ULONG>(-1));
std::vector<BN_ULONG> r(num);
CHECK_ABI(bn_add_words, r.data(), a.data(), b.data(), num);
CHECK_ABI(bn_sub_words, r.data(), a.data(), b.data(), num);
CHECK_ABI(bn_mul_words, r.data(), a.data(), num, 42);
CHECK_ABI(bn_mul_add_words, r.data(), a.data(), num, 42);
r.resize(2 * num);
CHECK_ABI(bn_sqr_words, r.data(), a.data(), num);
if (num == 4) {
CHECK_ABI(bn_mul_comba4, r.data(), a.data(), b.data());
CHECK_ABI(bn_sqr_comba4, r.data(), a.data());
}
if (num == 8) {
CHECK_ABI(bn_mul_comba8, r.data(), a.data(), b.data());
CHECK_ABI(bn_sqr_comba8, r.data(), a.data());
}
}
}
#endif
#if defined(OPENSSL_BN_ASM_MONT) && defined(SUPPORTS_ABI_TEST)
TEST_F(BNTest, BNMulMontABI) {
for (size_t words : {4, 5, 6, 7, 8, 16, 32}) {
SCOPED_TRACE(words);
bssl::UniquePtr<BIGNUM> m(BN_new());
ASSERT_TRUE(m);
ASSERT_TRUE(BN_set_bit(m.get(), 0));
ASSERT_TRUE(BN_set_bit(m.get(), words * BN_BITS2 - 1));
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(m.get(), ctx()));
ASSERT_TRUE(mont);
std::vector<BN_ULONG> r(words), a(words), b(words);
a[0] = 1;
b[0] = 42;
#if defined(OPENSSL_X86_64)
if (bn_mulx4x_mont_capable(words)) {
CHECK_ABI(bn_mulx4x_mont, r.data(), a.data(), b.data(), mont->N.d,
mont->n0, words);
CHECK_ABI(bn_mulx4x_mont, r.data(), a.data(), a.data(), mont->N.d,
mont->n0, words);
}
if (bn_mul4x_mont_capable(words)) {
CHECK_ABI(bn_mul4x_mont, r.data(), a.data(), b.data(), mont->N.d,
mont->n0, words);
CHECK_ABI(bn_mul4x_mont, r.data(), a.data(), a.data(), mont->N.d,
mont->n0, words);
}
CHECK_ABI(bn_mul_mont_nohw, r.data(), a.data(), b.data(), mont->N.d,
mont->n0, words);
CHECK_ABI(bn_mul_mont_nohw, r.data(), a.data(), a.data(), mont->N.d,
mont->n0, words);
if (bn_sqr8x_mont_capable(words)) {
CHECK_ABI(bn_sqr8x_mont, r.data(), a.data(), bn_mulx_adx_capable(),
mont->N.d, mont->n0, words);
}
#elif defined(OPENSSL_ARM)
if (bn_mul8x_mont_neon_capable(words)) {
CHECK_ABI(bn_mul8x_mont_neon, r.data(), a.data(), b.data(), mont->N.d,
mont->n0, words);
CHECK_ABI(bn_mul8x_mont_neon, r.data(), a.data(), a.data(), mont->N.d,
mont->n0, words);
}
CHECK_ABI(bn_mul_mont_nohw, r.data(), a.data(), b.data(), mont->N.d,
mont->n0, words);
CHECK_ABI(bn_mul_mont_nohw, r.data(), a.data(), a.data(), mont->N.d,
mont->n0, words);
#else
CHECK_ABI(bn_mul_mont, r.data(), a.data(), b.data(), mont->N.d, mont->n0,
words);
CHECK_ABI(bn_mul_mont, r.data(), a.data(), a.data(), mont->N.d, mont->n0,
words);
#endif
}
}
#endif
#if defined(OPENSSL_BN_ASM_MONT5) && defined(SUPPORTS_ABI_TEST)
TEST_F(BNTest, BNMulMont5ABI) {
for (size_t words : {4, 5, 6, 7, 8, 16, 32}) {
SCOPED_TRACE(words);
bssl::UniquePtr<BIGNUM> m(BN_new());
ASSERT_TRUE(m);
ASSERT_TRUE(BN_set_bit(m.get(), 0));
ASSERT_TRUE(BN_set_bit(m.get(), words * BN_BITS2 - 1));
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(m.get(), ctx()));
ASSERT_TRUE(mont);
std::vector<BN_ULONG> r(words), a(words), b(words), table(words * 32);
a[0] = 1;
b[0] = 42;
bn_mul_mont(r.data(), a.data(), b.data(), mont->N.d, mont->n0, words);
CHECK_ABI(bn_scatter5, r.data(), words, table.data(), 13);
for (size_t i = 0; i < 32; i++) {
bn_mul_mont(r.data(), a.data(), b.data(), mont->N.d, mont->n0, words);
bn_scatter5(r.data(), words, table.data(), i);
}
CHECK_ABI(bn_gather5, r.data(), words, table.data(), 13);
if (bn_mulx4x_mont_gather5_capable(words)) {
CHECK_ABI(bn_mulx4x_mont_gather5, r.data(), r.data(), table.data(), m->d,
mont->n0, words, 13);
CHECK_ABI(bn_mulx4x_mont_gather5, r.data(), a.data(), table.data(), m->d,
mont->n0, words, 13);
}
if (bn_mul4x_mont_gather5_capable(words)) {
CHECK_ABI(bn_mul4x_mont_gather5, r.data(), r.data(), table.data(), m->d,
mont->n0, words, 13);
CHECK_ABI(bn_mul4x_mont_gather5, r.data(), a.data(), table.data(), m->d,
mont->n0, words, 13);
}
CHECK_ABI(bn_mul_mont_gather5_nohw, r.data(), r.data(), table.data(), m->d,
mont->n0, words, 13);
CHECK_ABI(bn_mul_mont_gather5_nohw, r.data(), a.data(), table.data(), m->d,
mont->n0, words, 13);
if (bn_powerx5_capable(words)) {
CHECK_ABI(bn_powerx5, r.data(), r.data(), table.data(), m->d, mont->n0,
words, 13);
CHECK_ABI(bn_powerx5, r.data(), a.data(), table.data(), m->d, mont->n0,
words, 13);
}
if (bn_power5_capable(words)) {
CHECK_ABI(bn_power5_nohw, r.data(), r.data(), table.data(), m->d,
mont->n0, words, 13);
CHECK_ABI(bn_power5_nohw, r.data(), a.data(), table.data(), m->d,
mont->n0, words, 13);
}
}
}
#endif
#if defined(RSAZ_ENABLED) && defined(SUPPORTS_ABI_TEST)
TEST_F(BNTest, RSAZABI) {
if (!rsaz_avx2_capable()) {
return;
}
alignas(64) BN_ULONG table[32 * 18] = {0};
alignas(64) BN_ULONG rsaz1[40], rsaz2[40], rsaz3[40], n_rsaz[40];
BN_ULONG norm[16], n_norm[16];
OPENSSL_memset(norm, 0x42, sizeof(norm));
OPENSSL_memset(n_norm, 0x99, sizeof(n_norm));
bssl::UniquePtr<BIGNUM> n(BN_new());
ASSERT_TRUE(n);
ASSERT_TRUE(bn_set_words(n.get(), n_norm, 16));
bssl::UniquePtr<BN_MONT_CTX> mont(
BN_MONT_CTX_new_for_modulus(n.get(), nullptr));
ASSERT_TRUE(mont);
const BN_ULONG k = mont->n0[0];
CHECK_ABI(rsaz_1024_norm2red_avx2, rsaz1, norm);
CHECK_ABI(rsaz_1024_norm2red_avx2, n_rsaz, n_norm);
CHECK_ABI(rsaz_1024_sqr_avx2, rsaz2, rsaz1, n_rsaz, k, 1);
CHECK_ABI(rsaz_1024_sqr_avx2, rsaz3, rsaz2, n_rsaz, k, 4);
CHECK_ABI(rsaz_1024_mul_avx2, rsaz3, rsaz1, rsaz2, n_rsaz, k);
CHECK_ABI(rsaz_1024_scatter5_avx2, table, rsaz3, 7);
CHECK_ABI(rsaz_1024_gather5_avx2, rsaz1, table, 7);
CHECK_ABI(rsaz_1024_red2norm_avx2, norm, rsaz1);
}
#endif