blob: bbcabd428b34aed1cbb73c341d55c3a4d0a17a01 [file]
// Copyright 2020 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <array>
#include <string>
#include <openssl/aead.h>
#include <openssl/base.h>
#include <openssl/cipher.h>
#include <openssl/crypto.h>
#include <openssl/mem.h>
#include <gtest/gtest.h>
#include "internal.h"
BSSL_NAMESPACE_BEGIN
namespace {
// Test that OPENSSL_VERSION_NUMBER and OPENSSL_VERSION_TEXT are consistent.
// Node.js parses the version out of OPENSSL_VERSION_TEXT instead of using
// OPENSSL_VERSION_NUMBER.
TEST(CryptoTest, Version) {
char expected[512];
snprintf(expected, sizeof(expected), "OpenSSL %d.%d.%d ",
OPENSSL_VERSION_NUMBER >> 28, (OPENSSL_VERSION_NUMBER >> 20) & 0xff,
(OPENSSL_VERSION_NUMBER >> 12) & 0xff);
EXPECT_EQ(expected,
std::string(OPENSSL_VERSION_TEXT).substr(0, strlen(expected)));
}
TEST(CryptoTest, Strndup) {
UniquePtr<char> str(OPENSSL_strndup(nullptr, 0));
EXPECT_TRUE(str);
EXPECT_STREQ("", str.get());
}
TEST(CryptoTest, ByteSwap) {
EXPECT_EQ(0x04030201u, CRYPTO_bswap4(0x01020304u));
EXPECT_EQ(UINT64_C(0x0807060504030201),
CRYPTO_bswap8(UINT64_C(0x0102030405060708)));
}
TEST(CryptoTest, BitWidth) {
EXPECT_EQ(CRYPTO_bit_width(0), 0);
EXPECT_EQ(CRYPTO_bit_width(1), 1);
EXPECT_EQ(CRYPTO_bit_width(2), 2);
EXPECT_EQ(CRYPTO_bit_width(3), 2);
EXPECT_EQ(CRYPTO_bit_width(4), 3);
EXPECT_EQ(CRYPTO_bit_width(5), 3);
EXPECT_EQ(CRYPTO_bit_width(6), 3);
EXPECT_EQ(CRYPTO_bit_width(7), 3);
EXPECT_EQ(CRYPTO_bit_width(8), 4);
EXPECT_EQ(CRYPTO_bit_width(~uint64_t{0}), 64);
EXPECT_EQ(CRYPTO_bit_width(~uint64_t{0} - 1), 64);
}
TEST(CryptoTest, Popcount) {
EXPECT_EQ(CRYPTO_popcount(0), 0);
EXPECT_EQ(CRYPTO_popcount(1), 1);
EXPECT_EQ(CRYPTO_popcount(2), 1);
EXPECT_EQ(CRYPTO_popcount(3), 2);
EXPECT_EQ(CRYPTO_popcount(4), 1);
EXPECT_EQ(CRYPTO_popcount(5), 2);
EXPECT_EQ(CRYPTO_popcount(6), 2);
EXPECT_EQ(CRYPTO_popcount(7), 3);
EXPECT_EQ(CRYPTO_popcount(8), 1);
EXPECT_EQ(CRYPTO_popcount(~uint64_t{0}), 64);
EXPECT_EQ(CRYPTO_popcount(~uint64_t{0} - 1), 63);
}
TEST(CryptoTest, BitCeil) {
EXPECT_EQ(CRYPTO_bit_ceil(0), 1u);
EXPECT_EQ(CRYPTO_bit_ceil(1), 1u);
EXPECT_EQ(CRYPTO_bit_ceil(2), 2u);
EXPECT_EQ(CRYPTO_bit_ceil(3), 4u);
EXPECT_EQ(CRYPTO_bit_ceil(4), 4u);
EXPECT_EQ(CRYPTO_bit_ceil(5), 8u);
EXPECT_EQ(CRYPTO_bit_ceil(6), 8u);
EXPECT_EQ(CRYPTO_bit_ceil(7), 8u);
EXPECT_EQ(CRYPTO_bit_ceil(8), 8u);
EXPECT_EQ(CRYPTO_bit_ceil(9), 16u);
}
TEST(CryptoTest, BitFloor) {
EXPECT_EQ(CRYPTO_bit_floor(0), 0u);
EXPECT_EQ(CRYPTO_bit_floor(1), 1u);
EXPECT_EQ(CRYPTO_bit_floor(2), 2u);
EXPECT_EQ(CRYPTO_bit_floor(3), 2u);
EXPECT_EQ(CRYPTO_bit_floor(4), 4u);
EXPECT_EQ(CRYPTO_bit_floor(5), 4u);
EXPECT_EQ(CRYPTO_bit_floor(6), 4u);
EXPECT_EQ(CRYPTO_bit_floor(7), 4u);
EXPECT_EQ(CRYPTO_bit_floor(8), 8u);
EXPECT_EQ(CRYPTO_bit_floor(9), 8u);
}
TEST(CryptoTest, HasSingleBit) {
EXPECT_FALSE(CRYPTO_has_single_bit(0));
EXPECT_TRUE(CRYPTO_has_single_bit(1));
EXPECT_TRUE(CRYPTO_has_single_bit(2));
EXPECT_FALSE(CRYPTO_has_single_bit(3));
EXPECT_TRUE(CRYPTO_has_single_bit(4));
EXPECT_FALSE(CRYPTO_has_single_bit(5));
EXPECT_FALSE(CRYPTO_has_single_bit(6));
EXPECT_FALSE(CRYPTO_has_single_bit(7));
EXPECT_TRUE(CRYPTO_has_single_bit(8));
EXPECT_FALSE(CRYPTO_has_single_bit(~uint64_t{0}));
EXPECT_TRUE(CRYPTO_has_single_bit(uint64_t{1} << 63));
}
#if defined(BORINGSSL_FIPS_COUNTERS)
using CounterArray = size_t[fips_counter_max + 1];
static void read_all_counters(CounterArray counters) {
for (int counter = 0; counter <= fips_counter_max; counter++) {
counters[counter] = FIPS_read_counter(static_cast<fips_counter_t>(counter));
}
}
static void expect_counter_delta_is_zero_except_for_a_one_at(
CounterArray before, CounterArray after, fips_counter_t position) {
for (int counter = 0; counter <= fips_counter_max; counter++) {
const size_t expected_delta = counter == position ? 1 : 0;
EXPECT_EQ(after[counter], before[counter] + expected_delta) << counter;
}
}
TEST(CryptoTest, FIPSCountersEVP) {
constexpr struct {
const EVP_CIPHER *(*cipher)();
fips_counter_t counter;
} kTests[] = {
{
EVP_aes_128_gcm,
fips_counter_evp_aes_128_gcm,
},
{
EVP_aes_256_gcm,
fips_counter_evp_aes_256_gcm,
},
{
EVP_aes_128_ctr,
fips_counter_evp_aes_128_ctr,
},
{
EVP_aes_256_ctr,
fips_counter_evp_aes_256_ctr,
},
};
uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
uint8_t iv[EVP_MAX_IV_LENGTH] = {1};
CounterArray before, after;
for (const auto &test : kTests) {
read_all_counters(before);
ScopedEVP_CIPHER_CTX ctx;
ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), test.cipher(), /*engine=*/nullptr,
key, iv));
read_all_counters(after);
expect_counter_delta_is_zero_except_for_a_one_at(before, after,
test.counter);
}
}
TEST(CryptoTest, FIPSCountersEVP_AEAD) {
constexpr struct {
const EVP_AEAD *(*aead)();
unsigned key_len;
fips_counter_t counter;
} kTests[] = {
{
EVP_aead_aes_128_gcm,
16,
fips_counter_evp_aes_128_gcm,
},
{
EVP_aead_aes_256_gcm,
32,
fips_counter_evp_aes_256_gcm,
},
};
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH] = {0};
CounterArray before, after;
for (const auto &test : kTests) {
ASSERT_LE(test.key_len, sizeof(key));
read_all_counters(before);
ScopedEVP_AEAD_CTX ctx;
ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), test.aead(), key, test.key_len,
EVP_AEAD_DEFAULT_TAG_LENGTH,
/*engine=*/nullptr));
read_all_counters(after);
expect_counter_delta_is_zero_except_for_a_one_at(before, after,
test.counter);
}
}
#endif // BORINGSSL_FIPS_COUNTERS
TEST(Crypto, QueryAlgorithmStatus) {
#if defined(BORINGSSL_FIPS)
const bool is_fips_build = true;
#else
const bool is_fips_build = false;
#endif
EXPECT_EQ(FIPS_query_algorithm_status("AES-GCM"), is_fips_build);
EXPECT_EQ(FIPS_query_algorithm_status("AES-ECB"), is_fips_build);
EXPECT_FALSE(FIPS_query_algorithm_status("FakeEncrypt"));
EXPECT_FALSE(FIPS_query_algorithm_status(""));
}
#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
TEST(Crypto, OnDemandIntegrityTest) { BORINGSSL_integrity_test(); }
#endif
OPENSSL_DEPRECATED static void DeprecatedFunction() {}
OPENSSL_BEGIN_ALLOW_DEPRECATED
TEST(CryptoTest, DeprecatedFunction) {
// This is deprecated, but should not trigger any warnings.
DeprecatedFunction();
}
OPENSSL_END_ALLOW_DEPRECATED
TEST(CryptoTest, Cleanup) {
bool cleaned_up = false;
{
Cleanup cleanup = [&] {
EXPECT_FALSE(cleaned_up); // Cleanup should run exactly once.
cleaned_up = true;
};
EXPECT_FALSE(cleaned_up); // Cleanup should not run yet.
}
EXPECT_TRUE(cleaned_up); // Cleanup should have run.
}
#if (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) && \
!defined(OPENSSL_NO_ASM) && !defined(BORINGSSL_SHARED_LIBRARY)
TEST(Crypto, CPUIDEnvVariable) {
const struct {
std::array<uint32_t, 4> in;
const char *env;
std::array<uint32_t, 4> out;
} kTests[] = {
// It should be possible to disable RDRAND with OPENSSL_ia32cap_P.
{{0x12345678, 0xffffffff, 0x12345678, 0x12345678},
"~0x4000000000000000",
{0x12345678, 0xbfffffff, 0x12345678, 0x12345678}},
// Disable RDRAND in decimal and also all post-AVX extensions. RR does
// this, though they probably meant to just disable RDRAND.
{{0x12345678, 0xffffffff, 0x12345678, 0x12345678},
"~4611686018427387904:0",
{0x12345678, 0xbfffffff, 0x00000000, 0x00000000}},
// Set the bitmasks to something else.
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"0x8877665544332211:0x1122334455667788",
{0x44332211, 0x88776655, 0x55667788, 0x11223344}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"1",
{0x00000001, 0x00000000, 0x12345678, 0x12345678}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"1:2",
{0x00000001, 0x00000000, 0x00000002, 0x00000000}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"0:0",
{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
// Enable bits.
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"|0xf0f0f0f0f0f0f0f0:|0x0f0f0f0f0f0f0f0f",
{0xf2f4f6f8, 0xf2f4f6f8, 0x1f3f5f7f, 0x1f3f5f7f}},
// Clear bits.
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"~0xf0f0f0f0f0f0f0f0:~0x0f0f0f0f0f0f0f0f",
{0x02040608, 0x02040608, 0x10305070, 0x10305070}},
// Syntax errors are silently ignored.
// TODO(davidben): We should also test something like " 1: 2", but that
// currently fails because `strtoull` skips leading spaces.
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"nope",
{0x12345678, 0x12345678, 0x12345678, 0x12345678}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"1nope:2nope",
{0x12345678, 0x12345678, 0x12345678, 0x12345678}},
// Overflows are caught and silently ignored.
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"0x10000000000000000:0x10000000000000000",
{0x12345678, 0x12345678, 0x12345678, 0x12345678}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"~0x1ffffffffffffffff:~0x1ffffffffffffffff",
{0x12345678, 0x12345678, 0x12345678, 0x12345678}},
{{0x12345678, 0x12345678, 0x12345678, 0x12345678},
"|0x1ffffffffffffffff:|0x1ffffffffffffffff",
{0x12345678, 0x12345678, 0x12345678, 0x12345678}},
};
for (const auto &t : kTests) {
SCOPED_TRACE(t.env);
std::array<uint32_t, 4> cap = t.in;
OPENSSL_adjust_ia32cap(cap.data(), t.env);
EXPECT_EQ(cap, t.out);
}
}
#endif
} // namespace
BSSL_NAMESPACE_END