diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index f402caf9..28b6c3a6 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -108,7 +108,6 @@ add_subdirectory(rsa_extra) add_subdirectory(ec_extra) add_subdirectory(ecdh) add_subdirectory(ecdsa_extra) -add_subdirectory(hmac_extra) # Level 3 add_subdirectory(cmac) @@ -232,13 +231,15 @@ add_executable( bio/bio_test.cc bytestring/bytestring_test.cc chacha/chacha_test.cc - cipher_extra/aead_extra_test.cc + cipher_extra/aead_test.cc + cipher_extra/cipher_test.cc cmac/cmac_test.cc compiler_test.cc constant_time_test.cc curve25519/ed25519_test.cc curve25519/spake25519_test.cc curve25519/x25519_test.cc + ecdh/ecdh_test.cc dh/dh_test.cc digest_extra/digest_test.cc dsa/dsa_test.cc @@ -247,9 +248,12 @@ add_executable( evp/pbkdf_test.cc fipsmodule/aes/aes_test.cc fipsmodule/ec/ec_test.cc + fipsmodule/modes/gcm_test.cc fipsmodule/rand/ctrdrbg_test.cc hkdf/hkdf_test.cc + hmac_extra/hmac_test.cc lhash/lhash_test.cc + poly1305/poly1305_test.cc pool/pool_test.cc refcount_test.cc rsa_extra/rsa_test.cc diff --git a/crypto/cipher_extra/CMakeLists.txt b/crypto/cipher_extra/CMakeLists.txt index 698161cb..8af36301 100644 --- a/crypto/cipher_extra/CMakeLists.txt +++ b/crypto/cipher_extra/CMakeLists.txt @@ -31,23 +31,5 @@ add_library( ${CIPHER_ARCH_SOURCES} ) -add_executable( - cipher_test - - cipher_test.cc - $ -) - -add_executable( - aead_test - - aead_test.cc - $ -) - perlasm(aes128gcmsiv-x86_64.${ASM_EXT} asm/aes128gcmsiv-x86_64.pl) perlasm(chacha20_poly1305_x86_64.${ASM_EXT} asm/chacha20_poly1305_x86_64.pl) - -target_link_libraries(cipher_test crypto) -target_link_libraries(aead_test crypto) -add_dependencies(all_tests cipher_test aead_test) diff --git a/crypto/cipher_extra/aead_extra_test.cc b/crypto/cipher_extra/aead_extra_test.cc deleted file mode 100644 index 073b3d6d..00000000 --- a/crypto/cipher_extra/aead_extra_test.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* 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 -#include - - -// Test that EVP_aead_aes_128_gcm and EVP_aead_aes_256_gcm reject empty nonces. -// AES-GCM is not defined for those. -// -// TODO(davidben): Fold this into aead_test.cc, once it is converted to GTest. -TEST(AEADTest, AESGCMEmptyNonce) { - static const uint8_t kZeros[32] = {0}; - - // Test AES-128-GCM. - uint8_t buf[16]; - size_t len; - bssl::ScopedEVP_AEAD_CTX ctx; - ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_gcm(), kZeros, 16, - EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); - - EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf), - nullptr /* nonce */, 0, nullptr /* in */, 0, - nullptr /* ad */, 0)); - uint32_t err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); - EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - - EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf), - nullptr /* nonce */, 0, kZeros /* in */, - sizeof(kZeros), nullptr /* ad */, 0)); - err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); - EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - - // Test AES-256-GCM. - ctx.Reset(); - ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(), kZeros, 32, - EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); - - EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf), - nullptr /* nonce */, 0, nullptr /* in */, 0, - nullptr /* ad */, 0)); - err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); - EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - - EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf), - nullptr /* nonce */, 0, kZeros /* in */, - sizeof(kZeros), nullptr /* ad */, 0)); - err = ERR_get_error(); - EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); - EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); -} diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc index 2edbe83a..24702ce9 100644 --- a/crypto/cipher_extra/aead_test.cc +++ b/crypto/cipher_extra/aead_test.cc @@ -12,31 +12,95 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include +#include + #include -#include +#include #include #include "../internal.h" #include "../test/file_test.h" +#include "../test/test_util.h" -#if defined(OPENSSL_SMALL) -const EVP_AEAD* EVP_aead_aes_128_gcm_siv(void) { - return nullptr; -} -const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) { - return nullptr; -} +struct KnownAEAD { + const char name[40]; + const EVP_AEAD *(*func)(void); + const char *test_vectors; + // limited_implementation indicates that tests that assume a generic AEAD + // interface should not be performed. For example, the key-wrap AEADs only + // handle inputs that are a multiple of eight bytes in length and the + // SSLv3/TLS AEADs have the concept of “direction”. + bool limited_implementation; + // truncated_tags is true if the AEAD supports truncating tags to arbitrary + // lengths. + bool truncated_tags; +}; + +static const struct KnownAEAD kAEADs[] = { + {"AES_128_GCM", EVP_aead_aes_128_gcm, "aes_128_gcm_tests.txt", false, true}, + {"AES_128_GCM_NIST", EVP_aead_aes_128_gcm, "nist_cavp/aes_128_gcm.txt", + false, true}, + {"AES_256_GCM", EVP_aead_aes_256_gcm, "aes_256_gcm_tests.txt", false, true}, + {"AES_256_GCM_NIST", EVP_aead_aes_256_gcm, "nist_cavp/aes_256_gcm.txt", + false, true}, +#if !defined(OPENSSL_SMALL) + {"AES_128_GCM_SIV", EVP_aead_aes_128_gcm_siv, "aes_128_gcm_siv_tests.txt", + false, false}, + {"AES_256_GCM_SIV", EVP_aead_aes_256_gcm_siv, "aes_256_gcm_siv_tests.txt", + false, false}, #endif + {"ChaCha20Poly1305", EVP_aead_chacha20_poly1305, + "chacha20_poly1305_tests.txt", false, true}, + {"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls, + "aes_128_cbc_sha1_tls_tests.txt", true, false}, + {"AES_128_CBC_SHA1_TLSImplicitIV", + EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, + "aes_128_cbc_sha1_tls_implicit_iv_tests.txt", true, false}, + {"AES_128_CBC_SHA256_TLS", EVP_aead_aes_128_cbc_sha256_tls, + "aes_128_cbc_sha256_tls_tests.txt", true, false}, + {"AES_256_CBC_SHA1_TLS", EVP_aead_aes_256_cbc_sha1_tls, + "aes_256_cbc_sha1_tls_tests.txt", true, false}, + {"AES_256_CBC_SHA1_TLSImplicitIV", + EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, + "aes_256_cbc_sha1_tls_implicit_iv_tests.txt", true, false}, + {"AES_256_CBC_SHA256_TLS", EVP_aead_aes_256_cbc_sha256_tls, + "aes_256_cbc_sha256_tls_tests.txt", true, false}, + {"AES_256_CBC_SHA384_TLS", EVP_aead_aes_256_cbc_sha384_tls, + "aes_256_cbc_sha384_tls_tests.txt", true, false}, + {"DES_EDE3_CBC_SHA1_TLS", EVP_aead_des_ede3_cbc_sha1_tls, + "des_ede3_cbc_sha1_tls_tests.txt", true, false}, + {"DES_EDE3_CBC_SHA1_TLSImplicitIV", + EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, + "des_ede3_cbc_sha1_tls_implicit_iv_tests.txt", true, false}, + {"AES_128_CBC_SHA1_SSL3", EVP_aead_aes_128_cbc_sha1_ssl3, + "aes_128_cbc_sha1_ssl3_tests.txt", true, false}, + {"AES_256_CBC_SHA1_SSL3", EVP_aead_aes_256_cbc_sha1_ssl3, + "aes_256_cbc_sha1_ssl3_tests.txt", true, false}, + {"DES_EDE3_CBC_SHA1_SSL3", EVP_aead_des_ede3_cbc_sha1_ssl3, + "des_ede3_cbc_sha1_ssl3_tests.txt", true, false}, + {"AES_128_CTR_HMAC_SHA256", EVP_aead_aes_128_ctr_hmac_sha256, + "aes_128_ctr_hmac_sha256.txt", false, true}, + {"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256, + "aes_256_ctr_hmac_sha256.txt", false, true}, +}; -// This program tests an AEAD against a series of test vectors from a file, -// using the FileTest format. As an example, here's a valid test case: +class PerAEADTest : public testing::TestWithParam { + public: + const EVP_AEAD *aead() { return GetParam().func(); } +}; + +INSTANTIATE_TEST_CASE_P(, PerAEADTest, testing::ValuesIn(kAEADs), + [](const testing::TestParamInfo ¶ms) + -> std::string { return params.param.name; }); + +// Tests an AEAD against a series of test vectors from a file, using the +// FileTest format. As an example, here's a valid test case: // // KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4 // NONCE: 978105dfce667bf4 @@ -44,177 +108,134 @@ const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) { // AD: b654574932 // CT: 5294265a60 // TAG: 1d45758621762e061368e68868e2f929 +TEST_P(PerAEADTest, TestVector) { + std::string test_vectors = "crypto/cipher_extra/test/"; + test_vectors += GetParam().test_vectors; + FileTestGTest(test_vectors.c_str(), [&](FileTest *t) { + std::vector key, nonce, in, ad, ct, tag; + ASSERT_TRUE(t->GetBytes(&key, "KEY")); + ASSERT_TRUE(t->GetBytes(&nonce, "NONCE")); + ASSERT_TRUE(t->GetBytes(&in, "IN")); + ASSERT_TRUE(t->GetBytes(&ad, "AD")); + ASSERT_TRUE(t->GetBytes(&ct, "CT")); + ASSERT_TRUE(t->GetBytes(&tag, "TAG")); -static bool TestAEAD(FileTest *t, void *arg) { - const EVP_AEAD *aead = reinterpret_cast(arg); + bssl::ScopedEVP_AEAD_CTX ctx; + ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction( + ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_seal)); - std::vector key, nonce, in, ad, ct, tag; - if (!t->GetBytes(&key, "KEY") || - !t->GetBytes(&nonce, "NONCE") || - !t->GetBytes(&in, "IN") || - !t->GetBytes(&ad, "AD") || - !t->GetBytes(&ct, "CT") || - !t->GetBytes(&tag, "TAG")) { - return false; - } + std::vector out(in.size() + EVP_AEAD_max_overhead(aead())); + if (!t->HasAttribute("NO_SEAL")) { + size_t out_len; + ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), + nonce.data(), nonce.size(), in.data(), + in.size(), ad.data(), ad.size())); + out.resize(out_len); - bssl::ScopedEVP_AEAD_CTX ctx; - if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), - tag.size(), evp_aead_seal)) { - t->PrintLine("Failed to init AEAD."); - return false; - } - - std::vector out(in.size() + EVP_AEAD_max_overhead(aead)); - if (!t->HasAttribute("NO_SEAL")) { - size_t out_len; - if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), - nonce.data(), nonce.size(), in.data(), in.size(), - ad.data(), ad.size())) { - t->PrintLine("Failed to run AEAD."); - return false; + ASSERT_EQ(out.size(), ct.size() + tag.size()); + EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size())); + EXPECT_EQ(Bytes(tag), Bytes(out.data() + ct.size(), tag.size())); + } else { + out.resize(ct.size() + tag.size()); + OPENSSL_memcpy(out.data(), ct.data(), ct.size()); + OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size()); } - out.resize(out_len); - if (out.size() != ct.size() + tag.size()) { - t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len, - (unsigned)(ct.size() + tag.size())); - return false; - } - if (!t->ExpectBytesEqual(ct.data(), ct.size(), out.data(), ct.size()) || - !t->ExpectBytesEqual(tag.data(), tag.size(), out.data() + ct.size(), - tag.size())) { - return false; - } - } else { - out.resize(ct.size() + tag.size()); - OPENSSL_memcpy(out.data(), ct.data(), ct.size()); - OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size()); - } + // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be + // reset after each operation. + ctx.Reset(); + ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction( + ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open)); - // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be - // reset after each operation. - ctx.Reset(); - if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), - tag.size(), evp_aead_open)) { - t->PrintLine("Failed to init AEAD."); - return false; - } - - std::vector out2(out.size()); - size_t out2_len; - int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), - nonce.data(), nonce.size(), out.data(), - out.size(), ad.data(), ad.size()); - if (t->HasAttribute("FAILS")) { - if (ret) { - t->PrintLine("Decrypted bad data."); - return false; + std::vector out2(out.size()); + size_t out2_len; + int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), + nonce.data(), nonce.size(), out.data(), + out.size(), ad.data(), ad.size()); + if (t->HasAttribute("FAILS")) { + ASSERT_FALSE(ret) << "Decrypted bad data."; + ERR_clear_error(); + return; } + + ASSERT_TRUE(ret) << "Failed to decrypt."; + out2.resize(out2_len); + EXPECT_EQ(Bytes(in), Bytes(out2)); + + // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be + // reset after each operation. + ctx.Reset(); + ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction( + ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open)); + + // Garbage at the end isn't ignored. + out.push_back(0); + out2.resize(out.size()); + EXPECT_FALSE(EVP_AEAD_CTX_open( + ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(), + nonce.size(), out.data(), out.size(), ad.data(), ad.size())) + << "Decrypted bad data with trailing garbage."; ERR_clear_error(); - return true; - } - if (!ret) { - t->PrintLine("Failed to decrypt."); - return false; - } - out2.resize(out2_len); - if (!t->ExpectBytesEqual(in.data(), in.size(), out2.data(), out2.size())) { - return false; - } + // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be + // reset after each operation. + ctx.Reset(); + ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction( + ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open)); - // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be - // reset after each operation. - ctx.Reset(); - if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), - tag.size(), evp_aead_open)) { - t->PrintLine("Failed to init AEAD."); - return false; - } - - // Garbage at the end isn't ignored. - out.push_back(0); - out2.resize(out.size()); - if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), - nonce.data(), nonce.size(), out.data(), out.size(), - ad.data(), ad.size())) { - t->PrintLine("Decrypted bad data with trailing garbage."); - return false; - } - ERR_clear_error(); - - // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be - // reset after each operation. - ctx.Reset(); - if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), - tag.size(), evp_aead_open)) { - t->PrintLine("Failed to init AEAD."); - return false; - } - - // Verify integrity is checked. - out[0] ^= 0x80; - out.resize(out.size() - 1); - out2.resize(out.size()); - if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(), - nonce.data(), nonce.size(), out.data(), out.size(), - ad.data(), ad.size())) { - t->PrintLine("Decrypted bad data with corrupted byte."); - return false; - } - ERR_clear_error(); - - return true; + // Verify integrity is checked. + out[0] ^= 0x80; + out.resize(out.size() - 1); + out2.resize(out.size()); + EXPECT_FALSE(EVP_AEAD_CTX_open( + ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(), + nonce.size(), out.data(), out.size(), ad.data(), ad.size())) + << "Decrypted bad data with corrupted byte."; + ERR_clear_error(); + }); } -static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) { +TEST_P(PerAEADTest, CleanupAfterInitFailure) { uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; OPENSSL_memset(key, 0, sizeof(key)); - const size_t key_len = EVP_AEAD_key_length(aead); - assert(sizeof(key) >= key_len); + const size_t key_len = EVP_AEAD_key_length(aead()); + ASSERT_GE(sizeof(key), key_len); EVP_AEAD_CTX ctx; - if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, - 9999 /* a silly tag length to trigger an error */, - NULL /* ENGINE */) != 0) { - fprintf(stderr, "A silly tag length didn't trigger an error!\n"); - return 0; - } + ASSERT_FALSE(EVP_AEAD_CTX_init( + &ctx, aead(), key, key_len, + 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */)); ERR_clear_error(); /* Running a second, failed _init should not cause a memory leak. */ - if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len, - 9999 /* a silly tag length to trigger an error */, - NULL /* ENGINE */) != 0) { - fprintf(stderr, "A silly tag length didn't trigger an error!\n"); - return 0; - } + ASSERT_FALSE(EVP_AEAD_CTX_init( + &ctx, aead(), key, key_len, + 9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */)); ERR_clear_error(); /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a * no-op. */ EVP_AEAD_CTX_cleanup(&ctx); - return 1; } -static int TestTruncatedTags(const EVP_AEAD *aead) { +TEST_P(PerAEADTest, TruncatedTags) { + if (!GetParam().truncated_tags) { + return; + } + uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; OPENSSL_memset(key, 0, sizeof(key)); - const size_t key_len = EVP_AEAD_key_length(aead); - assert(sizeof(key) >= key_len); + const size_t key_len = EVP_AEAD_key_length(aead()); + ASSERT_GE(sizeof(key), key_len); uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; OPENSSL_memset(nonce, 0, sizeof(nonce)); - const size_t nonce_len = EVP_AEAD_nonce_length(aead); - assert(sizeof(nonce) >= nonce_len); + const size_t nonce_len = EVP_AEAD_nonce_length(aead()); + ASSERT_GE(sizeof(nonce), nonce_len); bssl::ScopedEVP_AEAD_CTX ctx; - if (!EVP_AEAD_CTX_init(ctx.get(), aead, key, key_len, 1 /* one byte tag */, - NULL /* ENGINE */)) { - fprintf(stderr, "Couldn't initialise AEAD with truncated tag.\n"); - return 1; - } + ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key, key_len, + 1 /* one byte tag */, NULL /* ENGINE */)); const uint8_t plaintext[1] = {'A'}; @@ -223,68 +244,53 @@ static int TestTruncatedTags(const EVP_AEAD *aead) { constexpr uint8_t kSentinel = 42; OPENSSL_memset(ciphertext, kSentinel, sizeof(ciphertext)); - if (!EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len, - sizeof(ciphertext), nonce, nonce_len, plaintext, - sizeof(plaintext), nullptr /* ad */, 0)) { - fprintf(stderr, "Sealing with truncated tag didn't work.\n"); - return 0; - } + ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len, + sizeof(ciphertext), nonce, nonce_len, plaintext, + sizeof(plaintext), nullptr /* ad */, 0)); for (size_t i = ciphertext_len; i < sizeof(ciphertext); i++) { // Sealing must not write past where it said it did. - if (ciphertext[i] != kSentinel) { - fprintf(stderr, "Sealing wrote off the end of the buffer.\n"); - return 0; - } + EXPECT_EQ(kSentinel, ciphertext[i]) + << "Sealing wrote off the end of the buffer."; } const size_t overhead_used = ciphertext_len - sizeof(plaintext); const size_t expected_overhead = - 1 + EVP_AEAD_max_overhead(aead) - EVP_AEAD_max_tag_len(aead); - if (overhead_used != expected_overhead) { - fprintf(stderr, "AEAD is probably ignoring request to truncate tags.\n"); - return 0; - } + 1 + EVP_AEAD_max_overhead(aead()) - EVP_AEAD_max_tag_len(aead()); + EXPECT_EQ(overhead_used, expected_overhead) + << "AEAD is probably ignoring request to truncate tags."; uint8_t plaintext2[sizeof(plaintext) + 16]; OPENSSL_memset(plaintext2, kSentinel, sizeof(plaintext2)); size_t plaintext2_len; - if (!EVP_AEAD_CTX_open(ctx.get(), plaintext2, &plaintext2_len, - sizeof(plaintext2), nonce, nonce_len, ciphertext, - ciphertext_len, nullptr /* ad */, 0)) { - fprintf(stderr, "Opening with truncated tag didn't work.\n"); - return 0; - } + ASSERT_TRUE(EVP_AEAD_CTX_open( + ctx.get(), plaintext2, &plaintext2_len, sizeof(plaintext2), nonce, + nonce_len, ciphertext, ciphertext_len, nullptr /* ad */, 0)) + << "Opening with truncated tag didn't work."; for (size_t i = plaintext2_len; i < sizeof(plaintext2); i++) { // Likewise, opening should also stay within bounds. - if (plaintext2[i] != kSentinel) { - fprintf(stderr, "Opening wrote off the end of the buffer.\n"); - return 0; - } + EXPECT_EQ(kSentinel, plaintext2[i]) + << "Opening wrote off the end of the buffer."; } - if (plaintext2_len != sizeof(plaintext) || - OPENSSL_memcmp(plaintext2, plaintext, sizeof(plaintext)) != 0) { - fprintf(stderr, "Opening with truncated tag gave wrong result.\n"); - return 0; - } - - return 1; + EXPECT_EQ(Bytes(plaintext), Bytes(plaintext2, plaintext2_len)); } -static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { - const size_t key_len = EVP_AEAD_key_length(aead); - const size_t nonce_len = EVP_AEAD_nonce_length(aead); - const size_t max_overhead = EVP_AEAD_max_overhead(aead); +TEST_P(PerAEADTest, AliasedBuffers) { + if (GetParam().limited_implementation) { + return; + } + + const size_t key_len = EVP_AEAD_key_length(aead()); + const size_t nonce_len = EVP_AEAD_nonce_length(aead()); + const size_t max_overhead = EVP_AEAD_max_overhead(aead()); std::vector key(key_len, 'a'); bssl::ScopedEVP_AEAD_CTX ctx; - if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len, - EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { - return false; - } + ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key_len, + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); static const uint8_t kPlaintext[260] = "testing123456testing123456testing123456testing123456testing123456testing" @@ -299,13 +305,11 @@ static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { std::vector nonce(nonce_len, 'b'); std::vector valid_encryption(sizeof(kPlaintext) + max_overhead); size_t valid_encryption_len; - if (!EVP_AEAD_CTX_seal( - ctx.get(), valid_encryption.data(), &valid_encryption_len, - sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, - kPlaintext, sizeof(kPlaintext), nullptr, 0)) { - fprintf(stderr, "EVP_AEAD_CTX_seal failed with disjoint buffers.\n"); - return false; - } + ASSERT_TRUE(EVP_AEAD_CTX_seal( + ctx.get(), valid_encryption.data(), &valid_encryption_len, + sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, kPlaintext, + sizeof(kPlaintext), nullptr, 0)) + << "EVP_AEAD_CTX_seal failed with disjoint buffers."; // Test with out != in which we expect to fail. std::vector buffer(2 + valid_encryption_len); @@ -315,138 +319,81 @@ static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext)); size_t out_len; - if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len, - sizeof(kPlaintext) + max_overhead, nonce.data(), - nonce_len, in, sizeof(kPlaintext), nullptr, 0) || - EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len, - sizeof(kPlaintext) + max_overhead, nonce.data(), - nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { - fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n"); - return false; - } + EXPECT_FALSE(EVP_AEAD_CTX_seal( + ctx.get(), out1 /* in - 1 */, &out_len, sizeof(kPlaintext) + max_overhead, + nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0)); + EXPECT_FALSE(EVP_AEAD_CTX_seal( + ctx.get(), out2 /* in + 1 */, &out_len, sizeof(kPlaintext) + max_overhead, + nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0)); ERR_clear_error(); OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len); - if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len, - nonce.data(), nonce_len, in, valid_encryption_len, - nullptr, 0) || - EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len, - nonce.data(), nonce_len, in, valid_encryption_len, - nullptr, 0)) { - fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n"); - return false; - } + EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out1 /* in - 1 */, &out_len, + valid_encryption_len, nonce.data(), nonce_len, + in, valid_encryption_len, nullptr, 0)); + EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out2 /* in + 1 */, &out_len, + valid_encryption_len, nonce.data(), nonce_len, + in, valid_encryption_len, nullptr, 0)); ERR_clear_error(); // Test with out == in, which we expect to work. OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext)); - if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len, - sizeof(kPlaintext) + max_overhead, nonce.data(), - nonce_len, in, sizeof(kPlaintext), nullptr, 0)) { - fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n"); - return false; - } - - if (out_len != valid_encryption_len || - OPENSSL_memcmp(in, valid_encryption.data(), out_len) != 0) { - fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n"); - return false; - } + ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), in, &out_len, + sizeof(kPlaintext) + max_overhead, nonce.data(), + nonce_len, in, sizeof(kPlaintext), nullptr, 0)); + EXPECT_EQ(Bytes(valid_encryption.data(), valid_encryption_len), + Bytes(in, out_len)); OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len); - if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len, - nonce.data(), nonce_len, in, valid_encryption_len, - nullptr, 0)) { - fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n"); - return false; - } - - if (out_len != sizeof(kPlaintext) || - OPENSSL_memcmp(in, kPlaintext, out_len) != 0) { - fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n"); - return false; - } - - return true; + ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len, + nonce.data(), nonce_len, in, + valid_encryption_len, nullptr, 0)); + EXPECT_EQ(Bytes(kPlaintext), Bytes(in, out_len)); } -struct KnownAEAD { - const char name[40]; - const EVP_AEAD *(*func)(void); - // limited_implementation indicates that tests that assume a generic AEAD - // interface should not be performed. For example, the key-wrap AEADs only - // handle inputs that are a multiple of eight bytes in length and the - // SSLv3/TLS AEADs have the concept of “direction”. - bool limited_implementation; - // truncated_tags is true if the AEAD supports truncating tags to arbitrary - // lengths. - bool truncated_tags; -}; +// Test that EVP_aead_aes_128_gcm and EVP_aead_aes_256_gcm reject empty nonces. +// AES-GCM is not defined for those. +TEST(AEADTest, AESGCMEmptyNonce) { + static const uint8_t kZeros[32] = {0}; -static const struct KnownAEAD kAEADs[] = { - { "aes-128-gcm", EVP_aead_aes_128_gcm, false, true }, - { "aes-256-gcm", EVP_aead_aes_256_gcm, false, true }, - { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false, false }, - { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false, false }, - { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false, true }, - { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true, false }, - { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true, false }, - { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true, false }, - { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls, true, false }, - { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, true, false }, - { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls, true, false }, - { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true, false }, - { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true, false }, - { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true, false }, - { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true, false }, - { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true, false }, - { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true, false }, - { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false, true }, - { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false, true }, - { "", NULL, false, false }, -}; + // Test AES-128-GCM. + uint8_t buf[16]; + size_t len; + bssl::ScopedEVP_AEAD_CTX ctx; + ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_gcm(), kZeros, 16, + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); -int main(int argc, char **argv) { - CRYPTO_library_init(); + EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf), + nullptr /* nonce */, 0, nullptr /* in */, 0, + nullptr /* ad */, 0)); + uint32_t err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); + EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - if (argc != 3) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } + EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf), + nullptr /* nonce */, 0, kZeros /* in */, + sizeof(kZeros), nullptr /* ad */, 0)); + err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); + EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - const struct KnownAEAD *known_aead; - for (unsigned i = 0;; i++) { - known_aead = &kAEADs[i]; - if (known_aead->func == NULL) { - fprintf(stderr, "Unknown AEAD: %s\n", argv[1]); - return 2; - } - if (strcmp(known_aead->name, argv[1]) == 0) { - break; - } - } + // Test AES-256-GCM. + ctx.Reset(); + ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(), kZeros, 32, + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); - const EVP_AEAD *const aead = known_aead->func(); - if (aead == NULL) { - // AEAD is not compiled in this configuration. - printf("PASS\n"); - return 0; - } + EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf), + nullptr /* nonce */, 0, nullptr /* in */, 0, + nullptr /* ad */, 0)); + err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); + EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); - if (!TestCleanupAfterInitFailure(aead)) { - return 1; - } - - if (known_aead->truncated_tags && !TestTruncatedTags(aead)) { - fprintf(stderr, "Truncated tags test failed for %s.\n", known_aead->name); - return 1; - } - - if (!known_aead->limited_implementation && !TestWithAliasedBuffers(aead)) { - fprintf(stderr, "Aliased buffers test failed for %s.\n", known_aead->name); - return 1; - } - - return FileTestMain(TestAEAD, const_cast(aead), argv[2]); + EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf), + nullptr /* nonce */, 0, kZeros /* in */, + sizeof(kZeros), nullptr /* ad */, 0)); + err = ERR_get_error(); + EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); + EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); } diff --git a/crypto/cipher_extra/cipher_test.cc b/crypto/cipher_extra/cipher_test.cc index bdfcf232..977243cd 100644 --- a/crypto/cipher_extra/cipher_test.cc +++ b/crypto/cipher_extra/cipher_test.cc @@ -57,11 +57,13 @@ #include #include +#include + #include -#include #include #include "../test/file_test.h" +#include "../test/test_util.h" static const EVP_CIPHER *GetCipher(const std::string &name) { @@ -109,11 +111,8 @@ static const EVP_CIPHER *GetCipher(const std::string &name) { return nullptr; } -static bool TestOperation(FileTest *t, - const EVP_CIPHER *cipher, - bool encrypt, - size_t chunk_size, - const std::vector &key, +static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt, + size_t chunk_size, const std::vector &key, const std::vector &iv, const std::vector &plaintext, const std::vector &ciphertext, @@ -131,48 +130,36 @@ static bool TestOperation(FileTest *t, bool is_aead = EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE; bssl::ScopedEVP_CIPHER_CTX ctx; - if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, - encrypt ? 1 : 0)) { - return false; - } + ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, + encrypt ? 1 : 0)); if (t->HasAttribute("IV")) { if (is_aead) { - if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, - iv.size(), 0)) { - return false; - } - } else if (iv.size() != EVP_CIPHER_CTX_iv_length(ctx.get())) { - t->PrintLine("Bad IV length."); - return false; + ASSERT_TRUE( + EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), 0)); + } else { + ASSERT_EQ(iv.size(), EVP_CIPHER_CTX_iv_length(ctx.get())); } } - if (is_aead && !encrypt && - !EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(), - const_cast(tag.data()))) { - return false; + if (is_aead && !encrypt) { + ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(), + const_cast(tag.data()))); } // The ciphers are run with no padding. For each of the ciphers we test, the // output size matches the input size. std::vector result(in->size()); - if (in->size() != out->size()) { - t->PrintLine("Input/output size mismatch (%u vs %u).", (unsigned)in->size(), - (unsigned)out->size()); - return false; - } + ASSERT_EQ(in->size(), out->size()); + int unused, result_len1 = 0, result_len2; + ASSERT_TRUE(EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size())); + ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), + iv.data(), -1)); // Note: the deprecated |EVP_CIPHER|-based AES-GCM API is sensitive to whether // parameters are NULL, so it is important to skip the |in| and |aad| // |EVP_CipherUpdate| calls when empty. - int unused, result_len1 = 0, result_len2; - if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()) || - !EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data(), - -1) || - (!aad.empty() && - !EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(), - aad.size())) || - !EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) { - t->PrintLine("Operation failed."); - return false; + if (!aad.empty()) { + ASSERT_TRUE( + EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(), aad.size())); } + ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0)); if (chunk_size != 0) { for (size_t i = 0; i < in->size();) { size_t todo = chunk_size; @@ -181,72 +168,44 @@ static bool TestOperation(FileTest *t, } int len; - if (!EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len, - in->data() + i, todo)) { - t->PrintLine("Operation failed."); - return false; - } + ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len, + in->data() + i, todo)); result_len1 += len; i += todo; } - } else if (!in->empty() && - !EVP_CipherUpdate(ctx.get(), result.data(), &result_len1, - in->data(), in->size())) { - t->PrintLine("Operation failed."); - return false; - } - if (!EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1, - &result_len2)) { - t->PrintLine("Operation failed."); - return false; + } else if (!in->empty()) { + ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data(), &result_len1, + in->data(), in->size())); } + ASSERT_TRUE( + EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1, &result_len2)); result.resize(result_len1 + result_len2); - if (!t->ExpectBytesEqual(out->data(), out->size(), result.data(), - result.size())) { - return false; - } + EXPECT_EQ(Bytes(*out), Bytes(result)); if (encrypt && is_aead) { uint8_t rtag[16]; - if (tag.size() > sizeof(rtag)) { - t->PrintLine("Bad tag length."); - return false; - } - if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag.size(), - rtag) || - !t->ExpectBytesEqual(tag.data(), tag.size(), rtag, - tag.size())) { - return false; - } + ASSERT_LE(tag.size(), sizeof(rtag)); + ASSERT_TRUE( + EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag.size(), rtag)); + EXPECT_EQ(Bytes(tag), Bytes(rtag, tag.size())); } - return true; } -static bool TestCipher(FileTest *t, void *arg) { +static void TestCipher(FileTest *t) { std::string cipher_str; - if (!t->GetAttribute(&cipher_str, "Cipher")) { - return false; - } + ASSERT_TRUE(t->GetAttribute(&cipher_str, "Cipher")); const EVP_CIPHER *cipher = GetCipher(cipher_str); - if (cipher == nullptr) { - t->PrintLine("Unknown cipher: '%s'.", cipher_str.c_str()); - return false; - } + ASSERT_TRUE(cipher); std::vector key, iv, plaintext, ciphertext, aad, tag; - if (!t->GetBytes(&key, "Key") || - !t->GetBytes(&plaintext, "Plaintext") || - !t->GetBytes(&ciphertext, "Ciphertext")) { - return false; - } - if (EVP_CIPHER_iv_length(cipher) > 0 && - !t->GetBytes(&iv, "IV")) { - return false; + ASSERT_TRUE(t->GetBytes(&key, "Key")); + ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext")); + ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext")); + if (EVP_CIPHER_iv_length(cipher) > 0) { + ASSERT_TRUE(t->GetBytes(&iv, "IV")); } if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE) { - if (!t->GetBytes(&aad, "AAD") || - !t->GetBytes(&tag, "Tag")) { - return false; - } + ASSERT_TRUE(t->GetBytes(&aad, "AAD")); + ASSERT_TRUE(t->GetBytes(&tag, "Tag")); } enum { @@ -261,8 +220,7 @@ static bool TestCipher(FileTest *t, void *arg) { } else if (str == "DECRYPT") { operation = kDecrypt; } else { - t->PrintLine("Unknown operation: '%s'.", str.c_str()); - return false; + FAIL() << "Unknown operation: " << str; } } @@ -270,30 +228,60 @@ static bool TestCipher(FileTest *t, void *arg) { 17, 31, 32, 33, 63, 64, 65, 512}; for (size_t chunk_size : chunk_sizes) { + SCOPED_TRACE(chunk_size); // By default, both directions are run, unless overridden by the operation. - if (operation != kDecrypt && - !TestOperation(t, cipher, true /* encrypt */, chunk_size, key, iv, - plaintext, ciphertext, aad, tag)) { - return false; + if (operation != kDecrypt) { + SCOPED_TRACE("encrypt"); + TestOperation(t, cipher, true /* encrypt */, chunk_size, key, iv, + plaintext, ciphertext, aad, tag); } - if (operation != kEncrypt && - !TestOperation(t, cipher, false /* decrypt */, chunk_size, key, iv, - plaintext, ciphertext, aad, tag)) { - return false; + if (operation != kEncrypt) { + SCOPED_TRACE("decrypt"); + TestOperation(t, cipher, false /* decrypt */, chunk_size, key, iv, + plaintext, ciphertext, aad, tag); } } - - return true; } -int main(int argc, char **argv) { - CRYPTO_library_init(); - - if (argc != 2) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } - - return FileTestMain(TestCipher, nullptr, argv[1]); +TEST(CipherTest, TestVectors) { + FileTestGTest("crypto/cipher_extra/test/cipher_tests.txt", TestCipher); +} + +TEST(CipherTest, CAVP_AES_128_CBC) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_AES_128_CTR) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_AES_192_CBC) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_AES_192_CTR) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_AES_256_CBC) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_AES_256_CTR) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt", + TestCipher); +} + +TEST(CipherTest, CAVP_TDES_CBC) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt", TestCipher); +} + +TEST(CipherTest, CAVP_TDES_ECB) { + FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt", TestCipher); } diff --git a/crypto/ecdh/CMakeLists.txt b/crypto/ecdh/CMakeLists.txt index 3d95180a..8eaeae5e 100644 --- a/crypto/ecdh/CMakeLists.txt +++ b/crypto/ecdh/CMakeLists.txt @@ -7,14 +7,3 @@ add_library( ecdh.c ) - -add_executable( - ecdh_test - - ecdh_test.cc - - $ -) - -target_link_libraries(ecdh_test crypto) -add_dependencies(all_tests ecdh_test) diff --git a/crypto/ecdh/ecdh_test.cc b/crypto/ecdh/ecdh_test.cc index a02fd22f..b3114453 100644 --- a/crypto/ecdh/ecdh_test.cc +++ b/crypto/ecdh/ecdh_test.cc @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -24,6 +26,7 @@ #include #include "../test/file_test.h" +#include "../test/test_util.h" static bssl::UniquePtr GetCurve(FileTest *t, const char *key) { @@ -59,67 +62,53 @@ static bssl::UniquePtr GetBIGNUM(FileTest *t, const char *key) { return bssl::UniquePtr(BN_bin2bn(bytes.data(), bytes.size(), nullptr)); } -static bool TestECDH(FileTest *t, void *arg) { - bssl::UniquePtr group = GetCurve(t, "Curve"); - bssl::UniquePtr priv_key = GetBIGNUM(t, "Private"); - bssl::UniquePtr x = GetBIGNUM(t, "X"); - bssl::UniquePtr y = GetBIGNUM(t, "Y"); - bssl::UniquePtr peer_x = GetBIGNUM(t, "PeerX"); - bssl::UniquePtr peer_y = GetBIGNUM(t, "PeerY"); - std::vector z; - if (!group || !priv_key || !x || !y || !peer_x || !peer_y || - !t->GetBytes(&z, "Z")) { - return false; - } +TEST(ECDHTest, TestVectors) { + FileTestGTest("crypto/ecdh/ecdh_tests.txt", [](FileTest *t) { + bssl::UniquePtr group = GetCurve(t, "Curve"); + ASSERT_TRUE(group); + bssl::UniquePtr priv_key = GetBIGNUM(t, "Private"); + ASSERT_TRUE(priv_key); + bssl::UniquePtr x = GetBIGNUM(t, "X"); + ASSERT_TRUE(x); + bssl::UniquePtr y = GetBIGNUM(t, "Y"); + ASSERT_TRUE(y); + bssl::UniquePtr peer_x = GetBIGNUM(t, "PeerX"); + ASSERT_TRUE(peer_x); + bssl::UniquePtr peer_y = GetBIGNUM(t, "PeerY"); + ASSERT_TRUE(peer_y); + std::vector z; + ASSERT_TRUE(t->GetBytes(&z, "Z")); - bssl::UniquePtr key(EC_KEY_new()); - bssl::UniquePtr pub_key(EC_POINT_new(group.get())); - bssl::UniquePtr peer_pub_key(EC_POINT_new(group.get())); - if (!key || !pub_key || !peer_pub_key || - !EC_KEY_set_group(key.get(), group.get()) || - !EC_KEY_set_private_key(key.get(), priv_key.get()) || - !EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), x.get(), - y.get(), nullptr) || - !EC_POINT_set_affine_coordinates_GFp(group.get(), peer_pub_key.get(), - peer_x.get(), peer_y.get(), - nullptr) || - !EC_KEY_set_public_key(key.get(), pub_key.get()) || - !EC_KEY_check_key(key.get())) { - return false; - } + bssl::UniquePtr key(EC_KEY_new()); + ASSERT_TRUE(key); + bssl::UniquePtr pub_key(EC_POINT_new(group.get())); + ASSERT_TRUE(pub_key); + bssl::UniquePtr peer_pub_key(EC_POINT_new(group.get())); + ASSERT_TRUE(peer_pub_key); + ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get())); + ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get())); + ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), + x.get(), y.get(), nullptr)); + ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp( + group.get(), peer_pub_key.get(), peer_x.get(), peer_y.get(), nullptr)); + ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get())); + ASSERT_TRUE(EC_KEY_check_key(key.get())); - std::vector actual_z; - // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns - // the right amount of data. - actual_z.resize(z.size() + 1); - int ret = ECDH_compute_key(actual_z.data(), actual_z.size(), - peer_pub_key.get(), key.get(), nullptr); - if (ret < 0 || - !t->ExpectBytesEqual(z.data(), z.size(), actual_z.data(), - static_cast(ret))) { - return false; - } + std::vector actual_z; + // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns + // the right amount of data. + actual_z.resize(z.size() + 1); + int ret = ECDH_compute_key(actual_z.data(), actual_z.size(), + peer_pub_key.get(), key.get(), nullptr); + ASSERT_GE(ret, 0); + EXPECT_EQ(Bytes(z), Bytes(actual_z.data(), static_cast(ret))); - // Test |ECDH_compute_key| truncates. - actual_z.resize(z.size() - 1); - ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(), - key.get(), nullptr); - if (ret < 0 || - !t->ExpectBytesEqual(z.data(), z.size() - 1, actual_z.data(), - static_cast(ret))) { - return false; - } - - return true; -} - -int main(int argc, char *argv[]) { - CRYPTO_library_init(); - - if (argc != 2) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } - - return FileTestMain(TestECDH, nullptr, argv[1]); + // Test |ECDH_compute_key| truncates. + actual_z.resize(z.size() - 1); + ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(), + key.get(), nullptr); + ASSERT_GE(ret, 0); + EXPECT_EQ(Bytes(z.data(), z.size() - 1), + Bytes(actual_z.data(), static_cast(ret))); + }); } diff --git a/crypto/fipsmodule/CMakeLists.txt b/crypto/fipsmodule/CMakeLists.txt index c43b103c..f048ec4e 100644 --- a/crypto/fipsmodule/CMakeLists.txt +++ b/crypto/fipsmodule/CMakeLists.txt @@ -205,28 +205,6 @@ add_executable( target_link_libraries(bn_test crypto) add_dependencies(all_tests bn_test) -add_executable( - gcm_test - - modes/gcm_test.cc - - $ -) - -target_link_libraries(gcm_test crypto) -add_dependencies(all_tests gcm_test) - -add_executable( - ctrdrbg_vector_test - - rand/ctrdrbg_vector_test.cc - - $ -) - -target_link_libraries(ctrdrbg_vector_test crypto) -add_dependencies(all_tests ctrdrbg_vector_test) - add_executable( example_mul diff --git a/crypto/fipsmodule/modes/gcm_test.cc b/crypto/fipsmodule/modes/gcm_test.cc index ce7bd96b..bfd42759 100644 --- a/crypto/fipsmodule/modes/gcm_test.cc +++ b/crypto/fipsmodule/modes/gcm_test.cc @@ -56,370 +56,65 @@ #include #include +#include + +#include + #include -#include -#include #include "internal.h" +#include "../../test/file_test.h" #include "../../test/test_util.h" -struct test_case { - const char *key; - const char *plaintext; - const char *additional_data; - const char *nonce; - const char *ciphertext; - const char *tag; -}; +TEST(GCMTest, TestVectors) { + FileTestGTest("crypto/fipsmodule/modes/gcm_tests.txt", [](FileTest *t) { + std::vector key, plaintext, additional_data, nonce, ciphertext, + tag; + ASSERT_TRUE(t->GetBytes(&key, "Key")); + ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext")); + ASSERT_TRUE(t->GetBytes(&additional_data, "AdditionalData")); + ASSERT_TRUE(t->GetBytes(&nonce, "Nonce")); + ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext")); + ASSERT_TRUE(t->GetBytes(&tag, "Tag")); -static const struct test_case test_cases[] = { - { - "00000000000000000000000000000000", - NULL, - NULL, - "000000000000000000000000", - NULL, - "58e2fccefa7e3061367f1d57a4e7455a", - }, - { - "00000000000000000000000000000000", - "00000000000000000000000000000000", - NULL, - "000000000000000000000000", - "0388dace60b6a392f328c2b971b2fe78", - "ab6e47d42cec13bdf53a67b21257bddf", - }, - { - "feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255", - NULL, - "cafebabefacedbaddecaf888", - "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985", - "4d5c2af327cd64a62cf35abd2ba6fab4", - }, - { - "feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbaddecaf888", - "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091", - "5bc94fbc3221a5db94fae95ae7121a47", - }, - { - "feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbad", - "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598", - "3612d2e79e3b0785561be14aaca2fccb", - }, - { - "feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b", - "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5", - "619cc5aefffe0bfa462af43c1699d050", - }, - { - "000000000000000000000000000000000000000000000000", - NULL, - NULL, - "000000000000000000000000", - NULL, - "cd33b28ac773f74ba00ed1f312572435", - }, - { - "000000000000000000000000000000000000000000000000", - "00000000000000000000000000000000", - NULL, - "000000000000000000000000", - "98e7247c07f0fe411c267e4384b0f600", - "2ff58d80033927ab8ef4d4587514f0fb", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255", - NULL, - "cafebabefacedbaddecaf888", - "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256", - "9924a7c8587336bfb118024db8674a14", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbaddecaf888", - "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710", - "2519498e80f1478f37ba55bd6d27618c", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbad", - "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7", - "65dcc57fcf623a24094fcca40d3533f8", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbad", - "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7", - "65dcc57fcf623a24094fcca40d3533f8", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b", - "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b", - "dcf566ff291c25bbb8568fc3d376a6d9", - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - NULL, - NULL, - "000000000000000000000000", - NULL, - "530f8afbc74536b9a963b4f1c4cb738b", - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "00000000000000000000000000000000", - NULL, - "000000000000000000000000", - "cea7403d4d606b6e074ec5d3baf39d18", - "d0d1c8a799996bf0265b98b5d48ab919", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255", - NULL, - "cafebabefacedbaddecaf888", - "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad", - "b094dac5d93471bdec1a502270e3cc6c", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbaddecaf888", - "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662", - "76fc6ece0f4e1768cddf8853bb2d551b", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "cafebabefacedbad", - "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f", - "3a337dbf46a792c45e454913fe2ea8f2", - }, - { - "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39", - "feedfacedeadbeeffeedfacedeadbeefabaddad2", - "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b", - "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f", - "a44a8266ee1c8eb0c8b5d4cf5ae9f19a", - }, - { - "00000000000000000000000000000000", - NULL, - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad", - "000000000000000000000000", - NULL, - "5fea793a2d6f974d37e68e0cb8ff9492", - }, - { - "00000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - NULL, - /* This nonce results in 0xfff in counter LSB. */ - "ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c", - "8b307f6b33286d0ab026a9ed3fe1e85f", - }, -}; + ASSERT_EQ(plaintext.size(), ciphertext.size()); + ASSERT_TRUE(key.size() == 16 || key.size() == 24 || key.size() == 32); + ASSERT_EQ(16u, tag.size()); -static int from_hex(uint8_t *out, char in) { - if (in >= '0' && in <= '9') { - *out = in - '0'; - return 1; - } - if (in >= 'a' && in <= 'f') { - *out = in - 'a' + 10; - return 1; - } - if (in >= 'A' && in <= 'F') { - *out = in - 'A' + 10; - return 1; - } + std::vector out(plaintext.size()); + AES_KEY aes_key; + ASSERT_EQ(0, AES_set_encrypt_key(key.data(), key.size() * 8, &aes_key)); - return 0; -} - -static int decode_hex(uint8_t **out, size_t *out_len, const char *in, - unsigned test_num, const char *description) { - if (in == NULL) { - *out = NULL; - *out_len = 0; - return 1; - } - - size_t len = strlen(in); - if (len & 1) { - fprintf(stderr, "%u: Odd-length %s input.\n", test_num, description); - return 0; - } - - uint8_t *buf = reinterpret_cast(OPENSSL_malloc(len / 2)); - if (buf == NULL) { - fprintf(stderr, "%u: malloc failure.\n", test_num); - goto err; - } - - for (size_t i = 0; i < len; i += 2) { - uint8_t v, v2; - if (!from_hex(&v, in[i]) || - !from_hex(&v2, in[i+1])) { - fprintf(stderr, "%u: invalid hex digit in %s around offset %zu.\n", - test_num, description, i); - goto err; + GCM128_CONTEXT ctx; + CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f)AES_encrypt, 0); + CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce.data(), nonce.size()); + if (!additional_data.empty()) { + CRYPTO_gcm128_aad(&ctx, additional_data.data(), additional_data.size()); } - buf[i/2] = (v << 4) | v2; - } - - *out = buf; - *out_len = len/2; - return 1; - -err: - OPENSSL_free(buf); - return 0; -} - -static int run_test_case(unsigned test_num, const struct test_case *test) { - size_t key_len, plaintext_len, additional_data_len, nonce_len, ciphertext_len, - tag_len; - uint8_t *key = NULL, *plaintext = NULL, *additional_data = NULL, - *nonce = NULL, *ciphertext = NULL, *tag = NULL, *out = NULL; - int ret = 0; - AES_KEY aes_key; - GCM128_CONTEXT ctx; - - if (!decode_hex(&key, &key_len, test->key, test_num, "key") || - !decode_hex(&plaintext, &plaintext_len, test->plaintext, test_num, - "plaintext") || - !decode_hex(&additional_data, &additional_data_len, test->additional_data, - test_num, "additional_data") || - !decode_hex(&nonce, &nonce_len, test->nonce, test_num, "nonce") || - !decode_hex(&ciphertext, &ciphertext_len, test->ciphertext, test_num, - "ciphertext") || - !decode_hex(&tag, &tag_len, test->tag, test_num, "tag")) { - goto out; - } - - if (plaintext_len != ciphertext_len) { - fprintf(stderr, "%u: plaintext and ciphertext have differing lengths.\n", - test_num); - goto out; - } - - if (key_len != 16 && key_len != 24 && key_len != 32) { - fprintf(stderr, "%u: bad key length.\n", test_num); - goto out; - } - - if (tag_len != 16) { - fprintf(stderr, "%u: bad tag length.\n", test_num); - goto out; - } - - out = reinterpret_cast(OPENSSL_malloc(plaintext_len)); - if (plaintext_len != 0 && out == NULL) { - goto out; - } - if (AES_set_encrypt_key(key, key_len*8, &aes_key)) { - fprintf(stderr, "%u: AES_set_encrypt_key failed.\n", test_num); - goto out; - } - - CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f) AES_encrypt, 0); - CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_len); - OPENSSL_memset(out, 0, plaintext_len); - if (additional_data) { - CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len); - } - if (plaintext) { - CRYPTO_gcm128_encrypt(&ctx, &aes_key, plaintext, out, plaintext_len); - } - if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len) || - (ciphertext && OPENSSL_memcmp(out, ciphertext, plaintext_len) != 0)) { - fprintf(stderr, "%u: encrypt failed.\n", test_num); - hexdump(stderr, "got :", out, plaintext_len); - hexdump(stderr, "want:", ciphertext, plaintext_len); - goto out; - } - - CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_len); - OPENSSL_memset(out, 0, plaintext_len); - if (additional_data) { - CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len); - } - if (ciphertext) { - CRYPTO_gcm128_decrypt(&ctx, &aes_key, ciphertext, out, plaintext_len); - } - if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len)) { - fprintf(stderr, "%u: decrypt failed.\n", test_num); - goto out; - } - if (plaintext && OPENSSL_memcmp(out, plaintext, plaintext_len)) { - fprintf(stderr, "%u: plaintext doesn't match.\n", test_num); - goto out; - } - - ret = 1; - -out: - OPENSSL_free(key); - OPENSSL_free(plaintext); - OPENSSL_free(additional_data); - OPENSSL_free(nonce); - OPENSSL_free(ciphertext); - OPENSSL_free(tag); - OPENSSL_free(out); - return ret; -} - -static bool TestByteSwap() { - return CRYPTO_bswap4(0x01020304) == 0x04030201 && - CRYPTO_bswap8(UINT64_C(0x0102030405060708)) == - UINT64_C(0x0807060504030201); -} - -int main(void) { - int ret = 0; - unsigned i; - - CRYPTO_library_init(); - - if (!TestByteSwap()) { - ret = 1; - } - - for (i = 0; i < sizeof(test_cases) / sizeof(struct test_case); i++) { - if (!run_test_case(i, &test_cases[i])) { - ret = 1; + if (!plaintext.empty()) { + CRYPTO_gcm128_encrypt(&ctx, &aes_key, plaintext.data(), out.data(), + plaintext.size()); } - } + ASSERT_TRUE(CRYPTO_gcm128_finish(&ctx, tag.data(), tag.size())); + EXPECT_EQ(Bytes(ciphertext), Bytes(out)); - if (ret == 0) { - printf("PASS\n"); - } - - return ret; + CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce.data(), nonce.size()); + OPENSSL_memset(out.data(), 0, out.size()); + if (!additional_data.empty()) { + CRYPTO_gcm128_aad(&ctx, additional_data.data(), additional_data.size()); + } + if (!ciphertext.empty()) { + CRYPTO_gcm128_decrypt(&ctx, &aes_key, ciphertext.data(), out.data(), + ciphertext.size()); + } + ASSERT_TRUE(CRYPTO_gcm128_finish(&ctx, tag.data(), tag.size())); + EXPECT_EQ(Bytes(plaintext), Bytes(out)); + }); +} + +TEST(GCMTest, ByteSwap) { + EXPECT_EQ(0x04030201u, CRYPTO_bswap4(0x01020304u)); + EXPECT_EQ(UINT64_C(0x0807060504030201), + CRYPTO_bswap8(UINT64_C(0x0102030405060708))); } diff --git a/crypto/fipsmodule/modes/gcm_tests.txt b/crypto/fipsmodule/modes/gcm_tests.txt new file mode 100644 index 00000000..68b3d07a --- /dev/null +++ b/crypto/fipsmodule/modes/gcm_tests.txt @@ -0,0 +1,147 @@ +Key = 00000000000000000000000000000000 +Plaintext = +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = +Tag = 58e2fccefa7e3061367f1d57a4e7455a + +Key = 00000000000000000000000000000000 +Plaintext = 00000000000000000000000000000000 +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = 0388dace60b6a392f328c2b971b2fe78 +Tag = ab6e47d42cec13bdf53a67b21257bddf + +Key = feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255 +AdditionalData = +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985 +Tag = 4d5c2af327cd64a62cf35abd2ba6fab4 + +Key = feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091 +Tag = 5bc94fbc3221a5db94fae95ae7121a47 + +Key = feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbad +Ciphertext = 61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598 +Tag = 3612d2e79e3b0785561be14aaca2fccb + +Key = feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b +Ciphertext = 8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5 +Tag = 619cc5aefffe0bfa462af43c1699d050 + +Key = 000000000000000000000000000000000000000000000000 +Plaintext = +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = +Tag = cd33b28ac773f74ba00ed1f312572435 + +Key = 000000000000000000000000000000000000000000000000 +Plaintext = 00000000000000000000000000000000 +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = 98e7247c07f0fe411c267e4384b0f600 +Tag = 2ff58d80033927ab8ef4d4587514f0fb + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255 +AdditionalData = +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256 +Tag = 9924a7c8587336bfb118024db8674a14 + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710 +Tag = 2519498e80f1478f37ba55bd6d27618c + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbad +Ciphertext = 0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7 +Tag = 65dcc57fcf623a24094fcca40d3533f8 + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbad +Ciphertext = 0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7 +Tag = 65dcc57fcf623a24094fcca40d3533f8 + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b +Ciphertext = d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b +Tag = dcf566ff291c25bbb8568fc3d376a6d9 + +Key = 0000000000000000000000000000000000000000000000000000000000000000 +Plaintext = +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = +Tag = 530f8afbc74536b9a963b4f1c4cb738b + +Key = 0000000000000000000000000000000000000000000000000000000000000000 +Plaintext = 00000000000000000000000000000000 +AdditionalData = +Nonce = 000000000000000000000000 +Ciphertext = cea7403d4d606b6e074ec5d3baf39d18 +Tag = d0d1c8a799996bf0265b98b5d48ab919 + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255 +AdditionalData = +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad +Tag = b094dac5d93471bdec1a502270e3cc6c + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbaddecaf888 +Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662 +Tag = 76fc6ece0f4e1768cddf8853bb2d551b + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = cafebabefacedbad +Ciphertext = c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f +Tag = 3a337dbf46a792c45e454913fe2ea8f2 + +Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308 +Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39 +AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2 +Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b +Ciphertext = 5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f +Tag = a44a8266ee1c8eb0c8b5d4cf5ae9f19a + +Key = 00000000000000000000000000000000 +Plaintext = +AdditionalData = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad +Nonce = 000000000000000000000000 +Ciphertext = +Tag = 5fea793a2d6f974d37e68e0cb8ff9492 + +Key = 00000000000000000000000000000000 +Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +AdditionalData = +# This nonce results in 0xfff in counter LSB. +Nonce = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c +Tag = 8b307f6b33286d0ab026a9ed3fe1e85f diff --git a/crypto/fipsmodule/rand/ctrdrbg_test.cc b/crypto/fipsmodule/rand/ctrdrbg_test.cc index a35e6b08..bd84782d 100644 --- a/crypto/fipsmodule/rand/ctrdrbg_test.cc +++ b/crypto/fipsmodule/rand/ctrdrbg_test.cc @@ -18,6 +18,7 @@ #include #include "internal.h" +#include "../../test/file_test.h" #include "../../test/test_util.h" @@ -81,3 +82,38 @@ TEST(CTRDRBGTest, Large) { CTR_DRBG_clear(&drbg); } + +TEST(CTRDRBGTest, TestVectors) { + FileTestGTest("crypto/fipsmodule/rand/ctrdrbg_vectors.txt", [](FileTest *t) { + std::vector seed, personalisation, reseed, ai_reseed, ai1, ai2, + expected; + ASSERT_TRUE(t->GetBytes(&seed, "EntropyInput")); + ASSERT_TRUE(t->GetBytes(&personalisation, "PersonalizationString")); + ASSERT_TRUE(t->GetBytes(&reseed, "EntropyInputReseed")); + ASSERT_TRUE(t->GetBytes(&ai_reseed, "AdditionalInputReseed")); + ASSERT_TRUE(t->GetBytes(&ai1, "AdditionalInput1")); + ASSERT_TRUE(t->GetBytes(&ai2, "AdditionalInput2")); + ASSERT_TRUE(t->GetBytes(&expected, "ReturnedBits")); + + ASSERT_EQ(static_cast(CTR_DRBG_ENTROPY_LEN), seed.size()); + ASSERT_EQ(static_cast(CTR_DRBG_ENTROPY_LEN), reseed.size()); + + CTR_DRBG_STATE drbg; + CTR_DRBG_init(&drbg, seed.data(), + personalisation.size() > 0 ? personalisation.data() : nullptr, + personalisation.size()); + CTR_DRBG_reseed(&drbg, reseed.data(), + ai_reseed.size() > 0 ? ai_reseed.data() : nullptr, + ai_reseed.size()); + + std::vector out; + out.resize(expected.size()); + + CTR_DRBG_generate(&drbg, out.data(), out.size(), + ai1.size() > 0 ? ai1.data() : nullptr, ai1.size()); + CTR_DRBG_generate(&drbg, out.data(), out.size(), + ai2.size() > 0 ? ai2.data() : nullptr, ai2.size()); + + EXPECT_EQ(Bytes(expected), Bytes(out)); + }); +} diff --git a/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc b/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc deleted file mode 100644 index 4680e6e6..00000000 --- a/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* 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 "internal.h" -#include "../../test/test_util.h" -#include "../../test/file_test.h" - - -static bool TestCTRDRBG(FileTest *t, void *arg) { - std::vector seed, personalisation, reseed, ai_reseed, ai1, ai2, - expected; - if (!t->GetBytes(&seed, "EntropyInput") || - !t->GetBytes(&personalisation, "PersonalizationString") || - !t->GetBytes(&reseed, "EntropyInputReseed") || - !t->GetBytes(&ai_reseed, "AdditionalInputReseed") || - !t->GetBytes(&ai1, "AdditionalInput1") || - !t->GetBytes(&ai2, "AdditionalInput2") || - !t->GetBytes(&expected, "ReturnedBits")) { - t->PrintLine("missing value"); - return false; - } - - if (seed.size() != CTR_DRBG_ENTROPY_LEN || - reseed.size() != CTR_DRBG_ENTROPY_LEN) { - t->PrintLine("bad seed length"); - return false; - } - - CTR_DRBG_STATE drbg; - CTR_DRBG_init(&drbg, seed.data(), - personalisation.size() > 0 ? personalisation.data() : nullptr, - personalisation.size()); - CTR_DRBG_reseed(&drbg, reseed.data(), - ai_reseed.size() > 0 ? ai_reseed.data() : nullptr, - ai_reseed.size()); - - std::vector out; - out.resize(expected.size()); - - CTR_DRBG_generate(&drbg, out.data(), out.size(), - ai1.size() > 0 ? ai1.data() : nullptr, ai1.size()); - CTR_DRBG_generate(&drbg, out.data(), out.size(), - ai2.size() > 0 ? ai2.data() : nullptr, ai2.size()); - - return t->ExpectBytesEqual(expected.data(), expected.size(), out.data(), - out.size()); -} - -int main(int argc, char **argv) { - CRYPTO_library_init(); - - if (argc != 2) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } - - return FileTestMain(TestCTRDRBG, nullptr, argv[1]); -} diff --git a/crypto/hmac_extra/CMakeLists.txt b/crypto/hmac_extra/CMakeLists.txt deleted file mode 100644 index 045213a7..00000000 --- a/crypto/hmac_extra/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -include_directories(../../include) - -add_executable( - hmac_test - - hmac_test.cc - - $ -) - -target_link_libraries(hmac_test crypto) -add_dependencies(all_tests hmac_test) diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index 7b216e28..d2853434 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -54,18 +54,17 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include -#include - #include #include #include -#include +#include + #include #include #include "../test/file_test.h" +#include "../test/test_util.h" static const EVP_MD *GetDigest(const std::string &name) { @@ -85,85 +84,47 @@ static const EVP_MD *GetDigest(const std::string &name) { return nullptr; } -static bool TestHMAC(FileTest *t, void *arg) { - std::string digest_str; - if (!t->GetAttribute(&digest_str, "HMAC")) { - return false; - } - const EVP_MD *digest = GetDigest(digest_str); - if (digest == nullptr) { - t->PrintLine("Unknown digest '%s'", digest_str.c_str()); - return false; - } +TEST(HMACTest, TestVectors) { + FileTestGTest("crypto/hmac_extra/hmac_tests.txt", [](FileTest *t) { + std::string digest_str; + ASSERT_TRUE(t->GetAttribute(&digest_str, "HMAC")); + const EVP_MD *digest = GetDigest(digest_str); + ASSERT_TRUE(digest) << "Unknown digest: " << digest_str; - std::vector key, input, output; - if (!t->GetBytes(&key, "Key") || - !t->GetBytes(&input, "Input") || - !t->GetBytes(&output, "Output")) { - return false; - } + std::vector key, input, output; + ASSERT_TRUE(t->GetBytes(&key, "Key")); + ASSERT_TRUE(t->GetBytes(&input, "Input")); + ASSERT_TRUE(t->GetBytes(&output, "Output")); + ASSERT_EQ(EVP_MD_size(digest), output.size()); - // Test using the one-shot API. - unsigned expected_mac_len = EVP_MD_size(digest); - std::unique_ptr mac(new uint8_t[expected_mac_len]); - unsigned mac_len; - if (nullptr == HMAC(digest, key.data(), key.size(), input.data(), - input.size(), mac.get(), &mac_len) || - mac_len != expected_mac_len || - !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) { - t->PrintLine("One-shot API failed."); - return false; - } + // Test using the one-shot API. + unsigned expected_mac_len = EVP_MD_size(digest); + std::unique_ptr mac(new uint8_t[expected_mac_len]); + unsigned mac_len; + ASSERT_TRUE(HMAC(digest, key.data(), key.size(), input.data(), input.size(), + mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); - // Test using HMAC_CTX. - bssl::ScopedHMAC_CTX ctx; - if (!HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr) || - !HMAC_Update(ctx.get(), input.data(), input.size()) || - !HMAC_Final(ctx.get(), mac.get(), &mac_len) || - mac_len != expected_mac_len || - !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) { - t->PrintLine("HMAC_CTX failed."); - return false; - } + // Test using HMAC_CTX. + bssl::ScopedHMAC_CTX ctx; + ASSERT_TRUE( + HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); - // Test that an HMAC_CTX may be reset with the same key. - if (!HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr) || - !HMAC_Update(ctx.get(), input.data(), input.size()) || - !HMAC_Final(ctx.get(), mac.get(), &mac_len) || - mac_len != expected_mac_len || - !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) { - t->PrintLine("HMAC_CTX with reset failed."); - return false; - } + // Test that an HMAC_CTX may be reset with the same key. + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); - // Test feeding the input in byte by byte. - if (!HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)) { - t->PrintLine("HMAC_CTX streaming failed."); - return false; - } - for (size_t i = 0; i < input.size(); i++) { - if (!HMAC_Update(ctx.get(), &input[i], 1)) { - t->PrintLine("HMAC_CTX streaming failed."); - return false; + // Test feeding the input in byte by byte. + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); + for (size_t i = 0; i < input.size(); i++) { + ASSERT_TRUE(HMAC_Update(ctx.get(), &input[i], 1)); } - } - if (!HMAC_Final(ctx.get(), mac.get(), &mac_len) || - mac_len != expected_mac_len || - !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) { - t->PrintLine("HMAC_CTX streaming failed."); - return false; - } - - return true; -} - -int main(int argc, char *argv[]) { - CRYPTO_library_init(); - - if (argc != 2) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } - - return FileTestMain(TestHMAC, nullptr, argv[1]); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + }); } diff --git a/crypto/poly1305/CMakeLists.txt b/crypto/poly1305/CMakeLists.txt index 1b6a8049..5534e62c 100644 --- a/crypto/poly1305/CMakeLists.txt +++ b/crypto/poly1305/CMakeLists.txt @@ -19,13 +19,3 @@ add_library( ${POLY1305_ARCH_SOURCES} ) - -add_executable( - poly1305_test - - poly1305_test.cc - $ -) - -target_link_libraries(poly1305_test crypto) -add_dependencies(all_tests poly1305_test) diff --git a/crypto/poly1305/poly1305_test.cc b/crypto/poly1305/poly1305_test.cc index 2c25e93b..198cca12 100644 --- a/crypto/poly1305/poly1305_test.cc +++ b/crypto/poly1305/poly1305_test.cc @@ -17,15 +17,16 @@ #include -#include +#include + #include #include "../internal.h" #include "../test/file_test.h" +#include "../test/test_util.h" -static bool TestSIMD(FileTest *t, unsigned excess, - const std::vector &key, +static void TestSIMD(unsigned excess, const std::vector &key, const std::vector &in, const std::vector &mac) { poly1305_state state; @@ -64,68 +65,40 @@ static bool TestSIMD(FileTest *t, unsigned excess, // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output. alignas(16) uint8_t out[16]; CRYPTO_poly1305_finish(&state, out); - if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) { - t->PrintLine("SIMD pattern %u failed.", excess); - return false; - } - - return true; + EXPECT_EQ(Bytes(out), Bytes(mac)) << "SIMD pattern " << excess << " failed."; } -static bool TestPoly1305(FileTest *t, void *arg) { - std::vector key, in, mac; - if (!t->GetBytes(&key, "Key") || - !t->GetBytes(&in, "Input") || - !t->GetBytes(&mac, "MAC")) { - return false; - } - if (key.size() != 32 || mac.size() != 16) { - t->PrintLine("Invalid test"); - return false; - } +TEST(Poly1305Test, TestVectors) { + FileTestGTest("crypto/poly1305/poly1305_tests.txt", [](FileTest *t) { + std::vector key, in, mac; + ASSERT_TRUE(t->GetBytes(&key, "Key")); + ASSERT_TRUE(t->GetBytes(&in, "Input")); + ASSERT_TRUE(t->GetBytes(&mac, "MAC")); + ASSERT_EQ(32u, key.size()); + ASSERT_EQ(16u, mac.size()); - // Test single-shot operation. - poly1305_state state; - CRYPTO_poly1305_init(&state, key.data()); - CRYPTO_poly1305_update(&state, in.data(), in.size()); - // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output. - alignas(16) uint8_t out[16]; - CRYPTO_poly1305_finish(&state, out); - if (!t->ExpectBytesEqual(out, 16, mac.data(), mac.size())) { - t->PrintLine("Single-shot Poly1305 failed."); - return false; - } + // Test single-shot operation. + poly1305_state state; + CRYPTO_poly1305_init(&state, key.data()); + CRYPTO_poly1305_update(&state, in.data(), in.size()); + // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output. + alignas(16) uint8_t out[16]; + CRYPTO_poly1305_finish(&state, out); + EXPECT_EQ(Bytes(out), Bytes(mac)) << "Single-shot Poly1305 failed."; - // Test streaming byte-by-byte. - CRYPTO_poly1305_init(&state, key.data()); - for (size_t i = 0; i < in.size(); i++) { - CRYPTO_poly1305_update(&state, &in[i], 1); - } - CRYPTO_poly1305_finish(&state, out); - if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) { - t->PrintLine("Streaming Poly1305 failed."); - return false; - } + // Test streaming byte-by-byte. + CRYPTO_poly1305_init(&state, key.data()); + for (size_t i = 0; i < in.size(); i++) { + CRYPTO_poly1305_update(&state, &in[i], 1); + } + CRYPTO_poly1305_finish(&state, out); + EXPECT_EQ(Bytes(out), Bytes(mac)) << "Streaming Poly1305 failed."; - // Test SIMD stress patterns. OpenSSL's AVX2 assembly needs a multiple of - // four blocks, so test up to three blocks of excess. - if (!TestSIMD(t, 0, key, in, mac) || - !TestSIMD(t, 16, key, in, mac) || - !TestSIMD(t, 32, key, in, mac) || - !TestSIMD(t, 48, key, in, mac)) { - return false; - } - - return true; -} - -int main(int argc, char **argv) { - CRYPTO_library_init(); - - if (argc != 2) { - fprintf(stderr, "%s \n", argv[0]); - return 1; - } - - return FileTestMain(TestPoly1305, nullptr, argv[1]); + // Test SIMD stress patterns. OpenSSL's AVX2 assembly needs a multiple of + // four blocks, so test up to three blocks of excess. + TestSIMD(0, key, in, mac); + TestSIMD(16, key, in, mac); + TestSIMD(32, key, in, mac); + TestSIMD(48, key, in, mac); + }); } diff --git a/crypto/test/file_test_gtest.cc b/crypto/test/file_test_gtest.cc index 9d3c3e42..cffacb35 100644 --- a/crypto/test/file_test_gtest.cc +++ b/crypto/test/file_test_gtest.cc @@ -23,6 +23,8 @@ #include +#include + std::string GetTestData(const char *path); @@ -81,5 +83,8 @@ void FileTestGTest(const char *path, std::function run_test) { SCOPED_TRACE(testing::Message() << path << ", line " << t.start_line()); run_test(&t); + + // Clean up the error queue for the next test. + ERR_clear_error(); } } diff --git a/sources.cmake b/sources.cmake index 4de0d070..89c64f7f 100644 --- a/sources.cmake +++ b/sources.cmake @@ -6,6 +6,41 @@ set( CRYPTO_TEST_DATA + crypto/cipher_extra/test/aes_128_cbc_sha1_ssl3_tests.txt + crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt + crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt + crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt + crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt + crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt + crypto/cipher_extra/test/aes_128_gcm_tests.txt + crypto/cipher_extra/test/aes_256_cbc_sha1_ssl3_tests.txt + crypto/cipher_extra/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt + crypto/cipher_extra/test/aes_256_cbc_sha1_tls_tests.txt + crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt + crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt + crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt + crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt + crypto/cipher_extra/test/aes_256_gcm_tests.txt + crypto/cipher_extra/test/chacha20_poly1305_tests.txt + crypto/cipher_extra/test/cipher_tests.txt + crypto/cipher_extra/test/des_ede3_cbc_sha1_ssl3_tests.txt + crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_implicit_iv_tests.txt + crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_tests.txt + crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt + crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt + crypto/cipher_extra/test/nist_cavp/aes_128_gcm.txt + crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt + crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt + crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt + crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt + crypto/cipher_extra/test/nist_cavp/aes_256_gcm.txt + crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt + crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt crypto/curve25519/ed25519_tests.txt + crypto/ecdh/ecdh_tests.txt crypto/fipsmodule/aes/aes_tests.txt + crypto/fipsmodule/modes/gcm_tests.txt + crypto/fipsmodule/rand/ctrdrbg_vectors.txt + crypto/hmac_extra/hmac_tests.txt + crypto/poly1305/poly1305_tests.txt ) diff --git a/util/all_tests.json b/util/all_tests.json index e496b8f0..e209cf99 100644 --- a/util/all_tests.json +++ b/util/all_tests.json @@ -1,51 +1,16 @@ [ - ["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-ssl3", "crypto/cipher_extra/test/aes_128_cbc_sha1_ssl3_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-tls", "crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-cbc-sha256-tls", "crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-ctr-hmac-sha256", "crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-gcm", "crypto/cipher_extra/test/aes_128_gcm_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-gcm", "crypto/cipher_extra/test/nist_cavp/aes_128_gcm.txt"], - ["crypto/cipher_extra/aead_test", "aes-128-gcm-siv", "crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-ssl3", "crypto/cipher_extra/test/aes_256_cbc_sha1_ssl3_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-tls", "crypto/cipher_extra/test/aes_256_cbc_sha1_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-cbc-sha256-tls", "crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-cbc-sha384-tls", "crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-ctr-hmac-sha256", "crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-gcm", "crypto/cipher_extra/test/aes_256_gcm_tests.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-gcm", "crypto/cipher_extra/test/nist_cavp/aes_256_gcm.txt"], - ["crypto/cipher_extra/aead_test", "aes-256-gcm-siv", "crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt"], - ["crypto/cipher_extra/aead_test", "chacha20-poly1305", "crypto/cipher_extra/test/chacha20_poly1305_tests.txt"], - ["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-ssl3", "crypto/cipher_extra/test/des_ede3_cbc_sha1_ssl3_tests.txt"], - ["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-tls", "crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_tests.txt"], - ["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_implicit_iv_tests.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/cipher_tests.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt"], - ["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt"], ["crypto/crypto_test"], - ["crypto/ecdh/ecdh_test", "crypto/ecdh/ecdh_tests.txt"], ["crypto/evp/evp_test", "crypto/evp/evp_tests.txt"], ["crypto/fipsmodule/bn_test", "crypto/fipsmodule/bn/bn_tests.txt"], - ["crypto/fipsmodule/ctrdrbg_vector_test", "crypto/fipsmodule/rand/ctrdrbg_vectors.txt"], ["crypto/fipsmodule/ecdsa_sign_test", "crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt"], ["crypto/fipsmodule/ecdsa_test"], ["crypto/fipsmodule/ecdsa_verify_test", "crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt"], ["crypto/fipsmodule/example_mul"], - ["crypto/fipsmodule/gcm_test"], ["crypto/fipsmodule/p256-x86_64_test", "crypto/fipsmodule/ec/p256-x86_64_tests.txt"], - ["crypto/hmac_extra/hmac_test", "crypto/hmac_extra/hmac_tests.txt"], ["crypto/obj/obj_test"], ["crypto/pkcs7/pkcs7_test"], ["crypto/pkcs8/pkcs12_test"], ["crypto/pkcs8/pkcs8_test"], - ["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"], ["crypto/thread_test"], ["crypto/x509v3/tab_test"], ["crypto/x509v3/v3name_test"],