| /* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| * |
| * 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 <gtest/gtest.h> |
| |
| #include <openssl/aead.h> |
| #include <openssl/aes.h> |
| #include <openssl/bn.h> |
| #include <openssl/cipher.h> |
| #include <openssl/cmac.h> |
| #include <openssl/crypto.h> |
| #include <openssl/ctrdrbg.h> |
| #include <openssl/dh.h> |
| #include <openssl/digest.h> |
| #include <openssl/ec.h> |
| #include <openssl/ecdh.h> |
| #include <openssl/err.h> |
| #include <openssl/evp.h> |
| #include <openssl/hmac.h> |
| #include <openssl/md4.h> |
| #include <openssl/md5.h> |
| #include <openssl/rand.h> |
| #include <openssl/rsa.h> |
| #include <openssl/service_indicator.h> |
| |
| #include "../../test/abi_test.h" |
| #include "../../test/test_util.h" |
| #include "../bn/internal.h" |
| #include "../rand/internal.h" |
| #include "../tls/internal.h" |
| |
| |
| using bssl::FIPSStatus; |
| |
| static const uint8_t kAESKey[16] = {'A', 'W', 'S', '-', 'L', 'C', 'C', 'r', |
| 'y', 'p', 't', 'o', ' ', 'K', 'e', 'y'}; |
| |
| static const uint8_t kPlaintext[64] = { |
| 'A', 'W', 'S', '-', 'L', 'C', 'C', 'r', 'y', 'p', 't', 'o', 'M', |
| 'o', 'd', 'u', 'l', 'e', ' ', 'F', 'I', 'P', 'S', ' ', 'K', 'A', |
| 'T', ' ', 'E', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', ' ', |
| 'a', 'n', 'd', ' ', 'D', 'e', 'c', 'r', 'y', 'p', 't', 'i', 'o', |
| 'n', ' ', 'P', 'l', 'a', 'i', 'n', 't', 'e', 'x', 't', '!'}; |
| |
| #if defined(BORINGSSL_FIPS) |
| |
| // kEVPKeyGenShouldCallFIPSFunctions determines whether |EVP_PKEY_keygen_*| |
| // functions should call the FIPS versions of the key-generation functions. |
| static const bool kEVPKeyGenShouldCallFIPSFunctions = false; |
| |
| // kCurveSecp256k1Supported determines whether secp256k1 tests should be run. |
| static const bool kCurveSecp256k1Supported = false; |
| |
| // kEVPDeriveSetsServiceIndicator is true if `EVP_PKEY_derive` should set the |
| // service indicator for some algorithms. |
| static const bool kEVPDeriveSetsServiceIndicator = false; |
| |
| template <typename T> |
| class TestWithNoErrors : public testing::TestWithParam<T> { |
| void TearDown() override { |
| if (ERR_peek_error() != 0) { |
| auto f = [](const char *str, size_t len, void *unused) -> int { |
| fprintf(stderr, "%s\n", str); |
| return 1; |
| }; |
| ERR_print_errors_cb(f, nullptr); |
| ADD_FAILURE(); |
| } |
| } |
| }; |
| |
| static const uint8_t kAESKey_192[24] = {'A', 'W', 'S', '-', 'L', 'C', 'C', 'r', |
| 'y', 'p', 't', 'o', ' ', '1', '9', '2', |
| '-', 'b', 'i', 't', ' ', 'K', 'e', 'y'}; |
| |
| static const uint8_t kAESKey_256[32] = {'A', 'W', 'S', '-', 'L', 'C', 'C', 'r', |
| 'y', 'p', 't', 'o', ' ', '2', '5', '6', |
| '-', 'b', 'i', 't', ' ', 'L', 'o', 'n', |
| 'g', ' ', 'K', 'e', 'y', '!', '!', '!'}; |
| |
| static const uint8_t kAESIV[AES_BLOCK_SIZE] = {0}; |
| |
| static bssl::UniquePtr<DH> GetDH() { |
| // kFFDHE2048PrivateKeyData is a 225-bit value. (225 because that's the |
| // minimum private key size in |
| // https://tools.ietf.org/html/rfc7919#appendix-A.1.) |
| static const uint8_t kFFDHE2048PrivateKey[] = { |
| 0x01, 0x91, 0x17, 0x3f, 0x2a, 0x05, 0x70, 0x18, 0x7e, 0xc4, |
| 0x22, 0xee, 0xb7, 0x0a, 0x15, 0x2f, 0x39, 0x64, 0x58, 0xf3, |
| 0xb8, 0x18, 0x7b, 0xe3, 0x6b, 0xd3, 0x8a, 0x4f, 0xa1}; |
| bssl::UniquePtr<BIGNUM> priv( |
| BN_bin2bn(kFFDHE2048PrivateKey, sizeof(kFFDHE2048PrivateKey), nullptr)); |
| if (!priv) { |
| return nullptr; |
| } |
| bssl::UniquePtr<DH> dh(DH_get_rfc7919_2048()); |
| if (!dh || !DH_set0_key(dh.get(), nullptr, priv.get())) { |
| return nullptr; |
| } |
| priv.release(); // |DH_set0_key| takes ownership on success. |
| return dh; |
| } |
| |
| static void DoCipherFinal(EVP_CIPHER_CTX *ctx, std::vector<uint8_t> *out, |
| bssl::Span<const uint8_t> in, |
| FIPSStatus expect_approved) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| size_t max_out = in.size(); |
| if (EVP_CIPHER_CTX_encrypting(ctx)) { |
| unsigned block_size = EVP_CIPHER_CTX_block_size(ctx); |
| max_out += block_size - (max_out % block_size); |
| } |
| out->resize(max_out); |
| |
| size_t total = 0; |
| int len; |
| ASSERT_TRUE(EVP_CipherUpdate(ctx, out->data(), &len, in.data(), in.size())); |
| total += static_cast<size_t>(len); |
| // Check if the overall service is approved by checking |EVP_CipherFinal_ex|, |
| // which should be the last part of the service. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_CipherFinal_ex(ctx, out->data() + total, &len))); |
| total += static_cast<size_t>(len); |
| ASSERT_LE(total, max_out); |
| out->resize(total); |
| |
| EXPECT_EQ(approved, expect_approved); |
| } |
| |
| static const uint8_t kTDES_EDE3_CipherText[64] = { |
| 0x2a, 0x17, 0x79, 0x5a, 0x9b, 0x1d, 0xd8, 0x72, 0x06, 0xc6, 0xe7, |
| 0x55, 0x14, 0xaa, 0x7b, 0x2a, 0x6e, 0xfc, 0x71, 0x29, 0xff, 0x9b, |
| 0x67, 0x73, 0x7c, 0x9e, 0x15, 0x74, 0x80, 0xc8, 0x2f, 0xca, 0x93, |
| 0xaa, 0x8e, 0xba, 0x2c, 0x48, 0x88, 0x51, 0xc7, 0xa4, 0xf4, 0xe3, |
| 0x2b, 0x33, 0xe5, 0xa1, 0x58, 0x0a, 0x08, 0x3c, 0xb9, 0xf6, 0xf1, |
| 0x20, 0x67, 0x02, 0x49, 0xa0, 0x92, 0x18, 0xde, 0x2b}; |
| |
| static const uint8_t kTDES_EDE3_CBCCipherText[64] = { |
| 0x2a, 0x17, 0x79, 0x5a, 0x9b, 0x1d, 0xd8, 0x72, 0xbf, 0x3f, 0xfd, |
| 0xe4, 0x0d, 0x66, 0x33, 0x49, 0x3b, 0x8c, 0xa6, 0xd0, 0x0a, 0x66, |
| 0xae, 0xf1, 0xd9, 0xa7, 0xd6, 0xfb, 0xa2, 0x39, 0x6f, 0xf6, 0x1b, |
| 0x8f, 0x67, 0xe1, 0x2b, 0x58, 0x1c, 0xb6, 0xa2, 0xec, 0xb3, 0xc2, |
| 0xe6, 0xd1, 0xcc, 0x11, 0x05, 0xdd, 0xee, 0x9d, 0x87, 0x95, 0xe9, |
| 0x58, 0xc7, 0xef, 0xa4, 0x6d, 0x5e, 0xd6, 0x57, 0x01}; |
| |
| // AES-OFB is not an approved service, and is only used to test we are not |
| // validating un-approved services correctly. |
| static const uint8_t kAESOFBCiphertext[64] = { |
| 0x49, 0xf5, 0x6a, 0x7d, 0x3e, 0xd7, 0xb2, 0x47, 0x35, 0xca, 0x54, |
| 0xf5, 0xf1, 0xb8, 0xd1, 0x48, 0x8e, 0x47, 0x09, 0x95, 0xd5, 0xa0, |
| 0xc6, 0xa3, 0xe4, 0x94, 0xaf, 0xd4, 0x1b, 0x64, 0x25, 0x65, 0x28, |
| 0x9e, 0x82, 0xba, 0x92, 0xca, 0x75, 0xb3, 0xf3, 0x78, 0x44, 0x87, |
| 0xd6, 0x11, 0xf9, 0x22, 0xa3, 0xf3, 0xc6, 0x1d, 0x30, 0x00, 0x5b, |
| 0x77, 0x18, 0x38, 0x39, 0x08, 0x5e, 0x0a, 0x56, 0x6b}; |
| |
| static const uint8_t kAESECBCiphertext[64] = { |
| 0xa4, 0xc1, 0x5c, 0x51, 0x2a, 0x2e, 0x2a, 0xda, 0xd9, 0x02, 0x23, |
| 0xe7, 0xa9, 0x34, 0x9d, 0xd8, 0x15, 0xc5, 0xf5, 0x55, 0x8e, 0xb0, |
| 0x29, 0x95, 0x48, 0x6c, 0x7f, 0xa9, 0x47, 0x19, 0x0b, 0x54, 0xe5, |
| 0x0f, 0x05, 0x76, 0xbb, 0xd0, 0x1a, 0x6c, 0xab, 0xe9, 0xfd, 0x5b, |
| 0xd8, 0x0b, 0x0a, 0xbd, 0x7f, 0xea, 0xda, 0x52, 0x07, 0x65, 0x13, |
| 0x6c, 0xbe, 0xfc, 0x36, 0x82, 0x4b, 0x6a, 0xc3, 0xd5}; |
| |
| static const uint8_t kAESECBCiphertext_192[64] = { |
| 0x1d, 0xc8, 0xaa, 0xa7, 0x29, 0x01, 0x17, 0x09, 0x72, 0xc6, 0xe9, |
| 0x63, 0x02, 0x9d, 0xeb, 0x01, 0xeb, 0xc0, 0xda, 0x82, 0x6c, 0x30, |
| 0x7d, 0x60, 0x1b, 0x3e, 0xc7, 0x7b, 0xe3, 0x18, 0xa2, 0x43, 0x59, |
| 0x15, 0x4a, 0xe4, 0x8a, 0x84, 0xda, 0x16, 0x90, 0x7b, 0xfa, 0x64, |
| 0x37, 0x62, 0x19, 0xf1, 0x95, 0x11, 0x61, 0x84, 0xb0, 0x70, 0x49, |
| 0x72, 0x9f, 0xe7, 0x3a, 0x18, 0x99, 0x01, 0xba, 0xb0}; |
| |
| static const uint8_t kAESECBCiphertext_256[64] = { |
| 0x6f, 0x2d, 0x6d, 0x7a, 0xc1, 0x8f, 0x00, 0x9f, 0x2d, 0xcf, 0xba, |
| 0xe6, 0x4f, 0xdd, 0xe0, 0x09, 0x5b, 0xf3, 0xa4, 0xaf, 0xce, 0x45, |
| 0x49, 0x6e, 0x28, 0x7b, 0x48, 0x57, 0xb5, 0xf5, 0xd8, 0x05, 0x16, |
| 0x0f, 0xea, 0x21, 0x0c, 0x39, 0x78, 0xee, 0x9e, 0x57, 0x3c, 0x40, |
| 0x11, 0x9c, 0xd9, 0x34, 0x97, 0xb9, 0xa6, 0x06, 0x40, 0x60, 0xa2, |
| 0x0c, 0x01, 0xe3, 0x9c, 0xda, 0x3e, 0xad, 0x99, 0x3d}; |
| |
| static const uint8_t kAESCBCCiphertext[64] = { |
| 0xa4, 0xc1, 0x5c, 0x51, 0x2a, 0x2e, 0x2a, 0xda, 0xd9, 0x02, 0x23, |
| 0xe7, 0xa9, 0x34, 0x9d, 0xd8, 0x5c, 0xb3, 0x65, 0x54, 0x72, 0xc8, |
| 0x06, 0xf1, 0x36, 0xc3, 0x97, 0x73, 0x87, 0xca, 0x44, 0x99, 0x21, |
| 0xb8, 0xdb, 0x93, 0x22, 0x00, 0x89, 0x7c, 0x1c, 0xea, 0x36, 0x23, |
| 0x18, 0xdb, 0xc1, 0x52, 0x8c, 0x23, 0x66, 0x11, 0x0d, 0xa8, 0xe9, |
| 0xb8, 0x08, 0x8b, 0xaa, 0x81, 0x47, 0x01, 0xa4, 0x4f}; |
| |
| static const uint8_t kAESCBCCiphertext_192[64] = { |
| 0x1d, 0xc8, 0xaa, 0xa7, 0x29, 0x01, 0x17, 0x09, 0x72, 0xc6, 0xe9, |
| 0x63, 0x02, 0x9d, 0xeb, 0x01, 0xb4, 0x48, 0xa8, 0x00, 0x94, 0x46, |
| 0x7f, 0xe3, 0xc1, 0x24, 0xea, 0x41, 0xa0, 0x2b, 0x47, 0x2f, 0xae, |
| 0x19, 0xce, 0x0d, 0xfa, 0x90, 0x45, 0x85, 0xce, 0xc4, 0x21, 0x0c, |
| 0x74, 0x38, 0x13, 0xfd, 0x64, 0xba, 0x58, 0x10, 0x37, 0x53, 0x48, |
| 0x66, 0x02, 0x76, 0xfb, 0xb1, 0x3a, 0x19, 0xce, 0x61}; |
| |
| static const uint8_t kAESCBCCiphertext_256[64] = { |
| 0x6f, 0x2d, 0x6d, 0x7a, 0xc1, 0x8f, 0x00, 0x9f, 0x2d, 0xcf, 0xba, |
| 0xe6, 0x4f, 0xdd, 0xe0, 0x09, 0x9e, 0xa8, 0x28, 0xdc, 0x27, 0xde, |
| 0x89, 0x26, 0xc7, 0x94, 0x6a, 0xbf, 0xb6, 0x94, 0x05, 0x08, 0x6c, |
| 0x39, 0x07, 0x52, 0xfa, 0x7b, 0xca, 0x7d, 0x9b, 0xbf, 0xb2, 0x43, |
| 0x2b, 0x69, 0xee, 0xc5, 0x68, 0x4c, 0xdd, 0x62, 0xae, 0x8d, 0x7e, |
| 0x71, 0x0c, 0x8f, 0x11, 0xce, 0x1d, 0x8b, 0xee, 0x94}; |
| |
| static const uint8_t kAESCTRCiphertext[64] = { |
| 0x49, 0xf5, 0x6a, 0x7d, 0x3e, 0xd7, 0xb2, 0x47, 0x35, 0xca, 0x54, |
| 0xf5, 0xf1, 0xb8, 0xd1, 0x48, 0xb0, 0x18, 0xc4, 0x5e, 0xeb, 0x42, |
| 0xfd, 0x10, 0x49, 0x1f, 0x2b, 0x11, 0xe9, 0xb0, 0x07, 0xa4, 0x00, |
| 0x56, 0xec, 0x25, 0x53, 0x4d, 0x70, 0x98, 0x38, 0x85, 0x5d, 0x54, |
| 0xab, 0x2c, 0x19, 0x13, 0x6d, 0xf3, 0x0e, 0x6f, 0x48, 0x2f, 0xab, |
| 0xe1, 0x82, 0xd4, 0x30, 0xa9, 0x16, 0x73, 0x93, 0xc3}; |
| |
| static const uint8_t kAESCTRCiphertext_192[64] = { |
| 0x72, 0x7d, 0xbb, 0xd4, 0x8b, 0x16, 0x8b, 0x19, 0xa4, 0xeb, 0xa6, |
| 0xfa, 0xa0, 0xd0, 0x2b, 0xbb, 0x9b, 0x1f, 0xbf, 0x4d, 0x67, 0xfb, |
| 0xea, 0x89, 0x16, 0xd7, 0xa4, 0xb6, 0xbe, 0x1a, 0x78, 0x1c, 0x3d, |
| 0x44, 0x49, 0xa0, 0xf2, 0xb2, 0xb3, 0x82, 0x0f, 0xdd, 0xac, 0xd6, |
| 0xea, 0x6e, 0x1f, 0x09, 0x8d, 0xa5, 0xdb, 0x4f, 0x3f, 0x97, 0x90, |
| 0x26, 0xed, 0xf6, 0xbb, 0x62, 0xb3, 0x6f, 0x52, 0x67}; |
| |
| static const uint8_t kAESCTRCiphertext_256[64] = { |
| 0x4a, 0x87, 0x44, 0x09, 0xf4, 0x1d, 0x80, 0x94, 0x51, 0x9a, 0xe4, |
| 0x89, 0x49, 0xcb, 0x98, 0x0d, 0x27, 0xc5, 0xba, 0x20, 0x00, 0x45, |
| 0xbb, 0x29, 0x75, 0xc0, 0xb7, 0x23, 0x0d, 0x81, 0x9f, 0x43, 0xaa, |
| 0x78, 0x89, 0xc0, 0xc4, 0x6d, 0x99, 0x0d, 0xb8, 0x9b, 0xc3, 0x25, |
| 0xa6, 0xd1, 0x7c, 0x98, 0x3e, 0xff, 0x06, 0x59, 0x41, 0xcf, 0xb2, |
| 0xd5, 0x2f, 0x95, 0xea, 0x83, 0xb1, 0x42, 0xb8, 0xb2}; |
| |
| static const uint8_t kAESCFBCiphertext[64] = { |
| 0x49, 0xf5, 0x6a, 0x7d, 0x3e, 0xd7, 0xb2, 0x47, 0x35, 0xca, 0x54, |
| 0xf5, 0xf1, 0xb8, 0xd1, 0x48, 0x01, 0xdc, 0xba, 0x43, 0x3a, 0x7b, |
| 0xbf, 0x84, 0x91, 0x49, 0xc5, 0xc9, 0xd6, 0xcf, 0x6a, 0x2c, 0x3a, |
| 0x66, 0x99, 0x68, 0xe3, 0xd0, 0x56, 0x05, 0xe7, 0x99, 0x7f, 0xc3, |
| 0xbc, 0x09, 0x13, 0xa6, 0xf0, 0xde, 0x17, 0xf4, 0x85, 0x9a, 0xee, |
| 0x29, 0xc3, 0x77, 0xab, 0xc4, 0xf6, 0xdb, 0xae, 0x24}; |
| |
| static const uint8_t kAESCCMCiphertext[64 + 4] = { |
| 0x7a, 0x02, 0x5d, 0x48, 0x02, 0x44, 0x78, 0x7f, 0xb4, 0x71, 0x74, 0x7b, |
| 0xec, 0x4d, 0x90, 0x29, 0x7b, 0xa7, 0x65, 0xbb, 0x3e, 0x80, 0x41, 0x7e, |
| 0xab, 0xb4, 0x58, 0x22, 0x4f, 0x86, 0xcd, 0xcc, 0xc2, 0x12, 0xeb, 0x36, |
| 0x39, 0x89, 0xe3, 0x66, 0x2a, 0xbf, 0xe3, 0x6c, 0x95, 0x60, 0x13, 0x9e, |
| 0x93, 0xcc, 0xb4, 0x06, 0xbe, 0xaf, 0x3f, 0xba, 0x13, 0x73, 0x09, 0x92, |
| 0xd1, 0x80, 0x73, 0xb3, 0xc3, 0xa3, 0xa4, 0x8b, |
| }; |
| |
| static const uint8_t kAESKWCiphertext[72] = { |
| 0x44, 0xec, 0x7d, 0x92, 0x2c, 0x9f, 0xf3, 0xe8, 0xac, 0xb1, 0xea, 0x3d, |
| 0x0a, 0xc7, 0x51, 0x27, 0xe8, 0x03, 0x11, 0x78, 0xe5, 0xaf, 0x8d, 0xb1, |
| 0x70, 0x96, 0x2e, 0xfa, 0x05, 0x48, 0x48, 0x99, 0x1a, 0x58, 0xcc, 0xfe, |
| 0x11, 0x36, 0x5d, 0x49, 0x98, 0x1e, 0xbb, 0xd6, 0x0b, 0xf5, 0xb9, 0x64, |
| 0xa4, 0x30, 0x3e, 0x60, 0xf6, 0xc5, 0xff, 0x82, 0x30, 0x9a, 0xa7, 0x48, |
| 0x82, 0xe2, 0x00, 0xc1, 0xe9, 0xc2, 0x73, 0x6f, 0xbc, 0x89, 0x66, 0x9d}; |
| |
| static const uint8_t kAESKWPCiphertext[72] = { |
| 0x29, 0x5e, 0xb9, 0xea, 0x96, 0xa7, 0xa5, 0xca, 0xfa, 0xeb, 0xda, 0x78, |
| 0x13, 0xea, 0x83, 0xca, 0x41, 0xdb, 0x4d, 0x36, 0x7d, 0x39, 0x8a, 0xd6, |
| 0xef, 0xd3, 0xd2, 0x2d, 0x3a, 0xc8, 0x55, 0xc8, 0x73, 0xd7, 0x79, 0x55, |
| 0xad, 0xc0, 0xce, 0xad, 0x12, 0x54, 0x51, 0xf0, 0x70, 0x76, 0xff, 0xe7, |
| 0x0c, 0xb2, 0x8e, 0xdd, 0xb6, 0x9a, 0x27, 0x74, 0x98, 0x28, 0xe0, 0xfa, |
| 0x11, 0xe6, 0x3f, 0x86, 0x93, 0x23, 0xf8, 0x0d, 0xcb, 0xaf, 0x2b, 0xb7}; |
| |
| static const uint8_t kAESCMACOutput[16] = {0xe7, 0x32, 0x43, 0xb4, 0xae, 0x79, |
| 0x08, 0x86, 0xe7, 0x9f, 0x0d, 0x3f, |
| 0x88, 0x3f, 0x1a, 0xfd}; |
| |
| const uint8_t kDHOutput[2048 / 8] = { |
| 0x83, 0xf0, 0xd8, 0x4f, 0xdb, 0xe7, 0x65, 0xb6, 0x80, 0x6f, 0xa3, 0x22, |
| 0x9b, 0x33, 0x1c, 0x87, 0x89, 0xc8, 0x1d, 0x2c, 0xa1, 0xba, 0xa3, 0xb8, |
| 0xdf, 0xad, 0x42, 0xea, 0x9a, 0x75, 0xfe, 0xbf, 0xc1, 0xa8, 0xf6, 0xda, |
| 0xec, 0xdf, 0x48, 0x61, 0x7d, 0x7f, 0x3d, 0xab, 0xbd, 0xda, 0xd1, 0xd3, |
| 0xd8, 0xaf, 0x44, 0x4a, 0xba, 0x3f, 0x0e, 0x99, 0x8d, 0x11, 0xdc, 0x63, |
| 0xb1, 0xe0, 0x65, 0xf2, 0xb9, 0x82, 0x81, 0x8c, 0x88, 0x75, 0x8f, 0xa0, |
| 0x94, 0x52, 0x2a, 0x2f, 0x2d, 0x10, 0xb1, 0xf4, 0xd2, 0xdd, 0x0f, 0x8a, |
| 0x7e, 0x49, 0x7b, 0x1e, 0xfd, 0x8c, 0x78, 0xf9, 0x11, 0xdf, 0x80, 0x8b, |
| 0x2e, 0x86, 0x34, 0xbf, 0x4b, 0xca, 0x13, 0x3e, 0x85, 0x63, 0xeb, 0xe4, |
| 0xff, 0xec, 0xb0, 0xe8, 0x83, 0xf6, 0x2c, 0x45, 0x21, 0x90, 0x34, 0x9c, |
| 0x9d, 0x9d, 0xfe, 0x1a, 0x48, 0x53, 0xef, 0x97, 0xd5, 0xea, 0x6a, 0x65, |
| 0xf5, 0xe9, 0x9f, 0x91, 0x4f, 0xb4, 0x43, 0xe7, 0x1f, 0x0a, 0x2e, 0xdb, |
| 0xe6, 0x84, 0x30, 0xdb, 0xad, 0xe4, 0xaf, 0x2c, 0xf9, 0x93, 0xe8, 0x0a, |
| 0xab, 0x7f, 0x1c, 0xde, 0xb3, 0x80, 0xb6, 0x02, 0x42, 0xba, 0x18, 0x0d, |
| 0x0f, 0xc2, 0x1d, 0xa4, 0x4b, 0x2b, 0x84, 0x74, 0x10, 0x97, 0x6d, 0xdc, |
| 0xfa, 0x99, 0xdc, 0xba, 0xf2, 0xcb, 0x1b, 0xe8, 0x1a, 0xba, 0x0c, 0x67, |
| 0x60, 0x07, 0x87, 0xcc, 0xc6, 0x0d, 0xef, 0x56, 0x07, 0x80, 0x55, 0xae, |
| 0x03, 0xa3, 0x62, 0x31, 0x4c, 0x50, 0xf7, 0xf6, 0x87, 0xb3, 0x8d, 0xe2, |
| 0x11, 0x86, 0xe7, 0x9d, 0x98, 0x3c, 0x2a, 0x6c, 0x8a, 0xf0, 0xa7, 0x73, |
| 0x33, 0x07, 0x4e, 0x70, 0xee, 0x14, 0x4b, 0xa3, 0xf7, 0x4f, 0x8f, 0x1a, |
| 0xa2, 0xf6, 0xd1, 0xeb, 0x4d, 0x04, 0xf9, 0x4c, 0x07, 0x36, 0xb1, 0x46, |
| 0x53, 0x55, 0xb1, 0x23}; |
| |
| static const uint8_t kOutput_md4[MD4_DIGEST_LENGTH] = { |
| 0xab, 0x6b, 0xda, 0x84, 0xc0, 0x6b, 0xd0, 0x1d, |
| 0x19, 0xc0, 0x08, 0x11, 0x07, 0x8d, 0xce, 0x0e}; |
| |
| static const uint8_t kOutput_md5[MD5_DIGEST_LENGTH] = { |
| 0xe9, 0x70, 0xa2, 0xf7, 0x9c, 0x55, 0x57, 0xac, |
| 0x4e, 0x7f, 0x6b, 0xbc, 0xa3, 0xb9, 0xb7, 0xdb}; |
| |
| static const uint8_t kOutput_sha1[SHA_DIGEST_LENGTH] = { |
| 0xaa, 0x18, 0x71, 0x34, 0x00, 0x71, 0x67, 0x9f, 0xa1, 0x6d, |
| 0x20, 0x82, 0x91, 0x0f, 0x53, 0x0a, 0xcd, 0x6e, 0xa4, 0x34}; |
| |
| static const uint8_t kOutput_sha224[SHA224_DIGEST_LENGTH] = { |
| 0x5f, 0x1a, 0x9e, 0x68, 0x4c, 0xb7, 0x42, 0x68, 0xa0, 0x8b, |
| 0x87, 0xd7, 0x96, 0xb6, 0xcf, 0x1e, 0x4f, 0x85, 0x1c, 0x47, |
| 0xe9, 0x29, 0xb3, 0xb2, 0x73, 0x72, 0xd2, 0x69}; |
| |
| static const uint8_t kOutput_sha256[SHA256_DIGEST_LENGTH] = { |
| 0xe7, 0x63, 0x1c, 0xbb, 0x12, 0xb5, 0xbf, 0x4f, 0x99, 0x05, 0x9d, |
| 0x40, 0x15, 0x55, 0x34, 0x9c, 0x26, 0x36, 0xd2, 0xfe, 0x6a, 0xd6, |
| 0x26, 0xb4, 0x9d, 0x33, 0x07, 0xf5, 0xe6, 0x29, 0x13, 0x92}; |
| |
| static const uint8_t kOutput_sha384[SHA384_DIGEST_LENGTH] = { |
| 0x15, 0x81, 0x48, 0x8d, 0x95, 0xf2, 0x66, 0x84, 0x65, 0x94, 0x3e, 0xb9, |
| 0x8c, 0xda, 0x36, 0x30, 0x2a, 0x85, 0xc0, 0xcd, 0xec, 0x38, 0xa0, 0x1f, |
| 0x72, 0xe2, 0x68, 0xfe, 0x4e, 0xdb, 0x27, 0x8b, 0x50, 0x15, 0xe0, 0x24, |
| 0xc3, 0x65, 0xd1, 0x66, 0x2a, 0x3e, 0xe7, 0x00, 0x16, 0x51, 0xf5, 0x18}; |
| |
| static const uint8_t kOutput_sha512[SHA512_DIGEST_LENGTH] = { |
| 0x71, 0xcc, 0xec, 0x03, 0xf8, 0x76, 0xf4, 0x0b, 0xf1, 0x1b, 0x89, |
| 0x27, 0x83, 0xa1, 0x70, 0x02, 0x00, 0x2b, 0xe9, 0x3c, 0x3c, 0x65, |
| 0x12, 0xb9, 0xa8, 0x8c, 0xc5, 0x9d, 0xae, 0x3c, 0x73, 0x43, 0x76, |
| 0x4d, 0x98, 0xed, 0xd0, 0xbe, 0xb4, 0xf9, 0x0b, 0x5c, 0x5d, 0x34, |
| 0x46, 0x30, 0x18, 0xc2, 0x05, 0x88, 0x8a, 0x3c, 0x25, 0xcc, 0x06, |
| 0xf8, 0x73, 0xb9, 0xe4, 0x18, 0xa8, 0xc2, 0xf0, 0xe5}; |
| |
| static const uint8_t kOutput_sha512_256[SHA512_256_DIGEST_LENGTH] = { |
| 0x1a, 0x78, 0x68, 0x6b, 0x69, 0x6d, 0x28, 0x14, 0x6b, 0x37, 0x11, |
| 0x2d, 0xfb, 0x72, 0x35, 0xfa, 0xc1, 0xc4, 0x5f, 0x5c, 0x49, 0x91, |
| 0x08, 0x95, 0x0b, 0x0f, 0xc9, 0x88, 0x44, 0x12, 0x01, 0x6a}; |
| |
| static const uint8_t kHMACOutput_sha1[SHA_DIGEST_LENGTH] = { |
| 0x34, 0xac, 0x50, 0x9b, 0xa9, 0x4c, 0x39, 0xef, 0x45, 0xa0, |
| 0x6b, 0xdc, 0xfc, 0xbd, 0x3d, 0x42, 0xe8, 0x0a, 0x97, 0x86}; |
| |
| static const uint8_t kHMACOutput_sha224[SHA224_DIGEST_LENGTH] = { |
| 0x30, 0x62, 0x97, 0x45, 0x9e, 0xea, 0x62, 0xe4, 0x5d, 0xbb, |
| 0x7d, 0x25, 0x3f, 0x77, 0x0f, 0x9d, 0xa4, 0xbd, 0x17, 0x96, |
| 0x23, 0x53, 0xe1, 0x76, 0xf3, 0xf8, 0x9b, 0x74}; |
| |
| static const uint8_t kHMACOutput_sha256[SHA256_DIGEST_LENGTH] = { |
| 0x68, 0x33, 0x3e, 0x74, 0x9a, 0x49, 0xab, 0x77, 0xb4, 0x1a, 0x40, |
| 0xd8, 0x55, 0x07, 0xa7, 0xb6, 0x48, 0xa1, 0xa5, 0xa9, 0xd1, 0x7b, |
| 0x85, 0xe9, 0x33, 0x09, 0x16, 0x79, 0xcc, 0xe9, 0x29, 0x97}; |
| |
| static const uint8_t kHMACOutput_sha384[SHA384_DIGEST_LENGTH] = { |
| 0xcc, 0x39, 0x22, 0x0e, 0x9f, 0x2e, 0x26, 0x4a, 0xb5, 0xf8, 0x4a, 0x0f, |
| 0x73, 0x51, 0x26, 0x1a, 0xf2, 0xef, 0x15, 0xf3, 0x5f, 0x77, 0xce, 0xbb, |
| 0x4c, 0x69, 0x86, 0x0e, 0x1f, 0x5c, 0x4d, 0xc9, 0x96, 0xd9, 0xed, 0x74, |
| 0x6c, 0x45, 0x05, 0x7a, 0x0e, 0x3f, 0x36, 0x8a, 0xda, 0x2a, 0x35, 0xf9}; |
| |
| static const uint8_t kHMACOutput_sha512[SHA512_DIGEST_LENGTH] = { |
| 0x4c, 0x09, 0x46, 0x50, 0x7c, 0xb3, 0xa1, 0xfa, 0xbc, 0xf2, 0xc4, |
| 0x4f, 0x1e, 0x3d, 0xa9, 0x0b, 0x29, 0x4e, 0x12, 0x09, 0x09, 0x32, |
| 0xde, 0x82, 0xa0, 0xab, 0xf6, 0x5e, 0x66, 0x19, 0xd0, 0x86, 0x9a, |
| 0x92, 0xe3, 0xf9, 0x13, 0xa7, 0xe6, 0xfc, 0x1a, 0x2e, 0x50, 0xda, |
| 0xf6, 0x8f, 0xb2, 0xd5, 0xb2, 0x6e, 0x97, 0x82, 0x25, 0x5a, 0x1e, |
| 0xbf, 0x9b, 0x99, 0x8c, 0xf0, 0x37, 0xe6, 0x3d, 0x40}; |
| |
| static const uint8_t kHMACOutput_sha512_256[SHA512_256_DIGEST_LENGTH] = { |
| 0x9c, 0x95, 0x9c, 0x03, 0xc9, 0x8c, 0x90, 0xee, 0x7a, 0xff, 0xed, |
| 0x26, 0xba, 0x75, 0x90, 0xd0, 0xb9, 0xd4, 0x09, 0xf5, 0x22, 0xd6, |
| 0xb6, 0xab, 0xa8, 0xb9, 0xae, 0x01, 0x06, 0x37, 0x8f, 0xd1}; |
| |
| static const uint8_t kDRBGEntropy[48] = { |
| 'B', 'C', 'M', ' ', 'K', 'n', 'o', 'w', 'n', ' ', 'A', 'n', |
| 's', 'w', 'e', 'r', ' ', 'T', 'e', 's', 't', ' ', 'D', 'B', |
| 'R', 'G', ' ', 'I', 'n', 'i', 't', 'i', 'a', 'l', ' ', 'E', |
| 'n', 't', 'r', 'o', 'p', 'y', ' ', ' ', ' ', ' ', ' ', ' '}; |
| |
| static const uint8_t kDRBGPersonalization[18] = {'B', 'C', 'M', 'P', 'e', 'r', |
| 's', 'o', 'n', 'a', 'l', 'i', |
| 'z', 'a', 't', 'i', 'o', 'n'}; |
| |
| static const uint8_t kDRBGAD[16] = {'B', 'C', 'M', ' ', 'D', 'R', 'B', 'G', |
| ' ', 'K', 'A', 'T', ' ', 'A', 'D', ' '}; |
| |
| const uint8_t kDRBGOutput[64] = { |
| 0x1d, 0x63, 0xdf, 0x05, 0x51, 0x49, 0x22, 0x46, 0xcd, 0x9b, 0xc5, |
| 0xbb, 0xf1, 0x5d, 0x44, 0xae, 0x13, 0x78, 0xb1, 0xe4, 0x7c, 0xf1, |
| 0x96, 0x33, 0x3d, 0x60, 0xb6, 0x29, 0xd4, 0xbb, 0x6b, 0x44, 0xf9, |
| 0xef, 0xd9, 0xf4, 0xa2, 0xba, 0x48, 0xea, 0x39, 0x75, 0x59, 0x32, |
| 0xf7, 0x31, 0x2c, 0x98, 0x14, 0x2b, 0x49, 0xdf, 0x02, 0xb6, 0x5d, |
| 0x71, 0x09, 0x50, 0xdb, 0x23, 0xdb, 0xe5, 0x22, 0x95}; |
| |
| static const uint8_t kDRBGEntropy2[48] = { |
| 'B', 'C', 'M', ' ', 'K', 'n', 'o', 'w', 'n', ' ', 'A', 'n', |
| 's', 'w', 'e', 'r', ' ', 'T', 'e', 's', 't', ' ', 'D', 'B', |
| 'R', 'G', ' ', 'R', 'e', 's', 'e', 'e', 'd', ' ', 'E', 'n', |
| 't', 'r', 'o', 'p', 'y', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; |
| |
| static const uint8_t kDRBGReseedOutput[64] = { |
| 0xa4, 0x77, 0x05, 0xdb, 0x14, 0x11, 0x76, 0x71, 0x42, 0x5b, 0xd8, |
| 0xd7, 0xa5, 0x4f, 0x8b, 0x39, 0xf2, 0x10, 0x4a, 0x50, 0x5b, 0xa2, |
| 0xc8, 0xf0, 0xbb, 0x3e, 0xa1, 0xa5, 0x90, 0x7d, 0x54, 0xd9, 0xc6, |
| 0xb0, 0x96, 0xc0, 0x2b, 0x7e, 0x9b, 0xc9, 0xa1, 0xdd, 0x78, 0x2e, |
| 0xd5, 0xa8, 0x66, 0x16, 0xbd, 0x18, 0x3c, 0xf2, 0xaa, 0x7a, 0x2b, |
| 0x37, 0xf9, 0xab, 0x35, 0x64, 0x15, 0x01, 0x3f, 0xc4, |
| }; |
| |
| static const uint8_t kTLSSecret[32] = { |
| 0xbf, 0xe4, 0xb7, 0xe0, 0x26, 0x55, 0x5f, 0x6a, 0xdf, 0x5d, 0x27, |
| 0xd6, 0x89, 0x99, 0x2a, 0xd6, 0xf7, 0x65, 0x66, 0x07, 0x4b, 0x55, |
| 0x5f, 0x64, 0x55, 0xcd, 0xd5, 0x77, 0xa4, 0xc7, 0x09, 0x61, |
| }; |
| static const char kTLSLabel[] = "FIPS self test"; |
| static const uint8_t kTLSSeed1[16] = { |
| 0x8f, 0x0d, 0xe8, 0xb6, 0x90, 0x8f, 0xb1, 0xd2, |
| 0x6d, 0x51, 0xf4, 0x79, 0x18, 0x63, 0x51, 0x65, |
| }; |
| static const uint8_t kTLSSeed2[16] = { |
| 0x7d, 0x24, 0x1a, 0x9d, 0x3c, 0x59, 0xbf, 0x3c, |
| 0x31, 0x1e, 0x2b, 0x21, 0x41, 0x8d, 0x32, 0x81, |
| }; |
| |
| static const uint8_t kTLSOutput_md5_sha1[32] = { |
| 0x36, 0xa9, 0x31, 0xb0, 0x43, 0xe3, 0x64, 0x72, 0xb9, 0x47, 0x54, |
| 0x0d, 0x8a, 0xfc, 0xe3, 0x5c, 0x1c, 0x15, 0x67, 0x7e, 0xa3, 0x5d, |
| 0xf2, 0x3a, 0x57, 0xfd, 0x50, 0x16, 0xe1, 0xa4, 0xa6, 0x37, |
| }; |
| |
| static const uint8_t kTLSOutput_sha224[32] = { |
| 0xdd, 0xaf, 0x6f, 0xaa, 0xd9, 0x2b, 0x3d, 0xb9, 0x46, 0x4c, 0x55, |
| 0x8a, 0xf7, 0xa6, 0x9b, 0x0b, 0x35, 0xcc, 0x07, 0xa7, 0x55, 0x5b, |
| 0x5e, 0x39, 0x12, 0xc0, 0xd4, 0x30, 0xdf, 0x0c, 0xdf, 0x6b, |
| }; |
| |
| static const uint8_t kTLSOutput_sha256[32] = { |
| 0x67, 0x85, 0xde, 0x60, 0xfc, 0x0a, 0x83, 0xe9, 0xa2, 0x2a, 0xb3, |
| 0xf0, 0x27, 0x0c, 0xba, 0xf7, 0xfa, 0x82, 0x3d, 0x14, 0x77, 0x1d, |
| 0x86, 0x29, 0x79, 0x39, 0x77, 0x8a, 0xd5, 0x0e, 0x9d, 0x32, |
| }; |
| |
| static const uint8_t kTLSOutput_sha384[32] = { |
| 0x75, 0x15, 0x3f, 0x44, 0x7a, 0xfd, 0x34, 0xed, 0x2b, 0x67, 0xbc, |
| 0xd8, 0x57, 0x96, 0xab, 0xff, 0xf4, 0x0c, 0x05, 0x94, 0x02, 0x23, |
| 0x81, 0xbf, 0x0e, 0xd2, 0xec, 0x7c, 0xe0, 0xa7, 0xc3, 0x7d, |
| }; |
| |
| static const uint8_t kTLSOutput_sha512[32] = { |
| 0x68, 0xb9, 0xc8, 0x4c, 0xf5, 0x51, 0xfc, 0x7a, 0x1f, 0x6c, 0xe5, |
| 0x43, 0x73, 0x80, 0x53, 0x7c, 0xae, 0x76, 0x55, 0x67, 0xe0, 0x79, |
| 0xbf, 0x3a, 0x53, 0x71, 0xb7, 0x9c, 0xb5, 0x03, 0x15, 0x3f, |
| }; |
| |
| static const uint8_t kAESGCMCiphertext_128[64 + 16] = { |
| 0x38, 0x71, 0xcb, 0x61, 0x70, 0x60, 0x13, 0x8b, 0x2f, 0x91, 0x09, 0x7f, |
| 0x83, 0x20, 0x0f, 0x1f, 0x71, 0xe2, 0x47, 0x46, 0x6f, 0x5f, 0xa8, 0xad, |
| 0xa8, 0xfc, 0x0a, 0xfd, 0x36, 0x65, 0x84, 0x90, 0x28, 0x2b, 0xcb, 0x4f, |
| 0x68, 0xae, 0x09, 0xba, 0xae, 0xdd, 0xdb, 0x91, 0xcc, 0x38, 0xb3, 0xad, |
| 0x10, 0x84, 0xb8, 0x45, 0x36, 0xf3, 0x96, 0xb4, 0xef, 0xba, 0xda, 0x10, |
| 0xf8, 0x8b, 0xf3, 0xda, 0x91, 0x1f, 0x8c, 0xd8, 0x39, 0x7b, 0x1c, 0xfd, |
| 0xe7, 0x99, 0x7d, 0xb7, 0x22, 0x69, 0x67, 0xbd, |
| }; |
| |
| static const uint8_t kAESGCMCiphertext_192[64 + 16] = { |
| 0x05, 0x63, 0x6e, 0xe4, 0xd1, 0x9f, 0xd0, 0x91, 0x18, 0xc9, 0xf8, 0xfd, |
| 0xc2, 0x62, 0x09, 0x05, 0x91, 0xb4, 0x92, 0x66, 0x18, 0xe7, 0x93, 0x6a, |
| 0xc7, 0xde, 0x81, 0x36, 0x93, 0x79, 0x45, 0x34, 0xc0, 0x6d, 0x14, 0x94, |
| 0x93, 0x39, 0x2b, 0x7f, 0x4f, 0x10, 0x1c, 0xa5, 0xfe, 0x3b, 0x37, 0xd7, |
| 0x0a, 0x98, 0xd7, 0xb5, 0xe0, 0xdc, 0xe4, 0x9f, 0x36, 0x40, 0xad, 0x03, |
| 0xbf, 0x53, 0xe0, 0x7c, 0x3f, 0x57, 0x4f, 0x80, 0x99, 0xe6, 0x90, 0x4e, |
| 0x59, 0x2e, 0xe0, 0x76, 0x53, 0x09, 0xc3, 0xd3, |
| }; |
| |
| static const uint8_t kAESGCMCiphertext_256[64 + 16] = { |
| 0x92, 0x5f, 0xae, 0x84, 0xe7, 0x40, 0xfa, 0x1e, 0xaf, 0x8f, 0x97, 0x0e, |
| 0x8e, 0xdd, 0x6a, 0x94, 0x22, 0xee, 0x4f, 0x70, 0x66, 0xbf, 0xb1, 0x99, |
| 0x05, 0xbd, 0xd0, 0xd7, 0x91, 0x54, 0xaf, 0xe1, 0x52, 0xc9, 0x4e, 0x55, |
| 0xa5, 0x23, 0x62, 0x8b, 0x23, 0x40, 0x90, 0x56, 0xe0, 0x68, 0x63, 0xe5, |
| 0x7e, 0x5b, 0xbe, 0x96, 0x7b, 0xc4, 0x16, 0xf9, 0xbe, 0x18, 0x06, 0x79, |
| 0x8f, 0x99, 0x35, 0xe3, 0x2a, 0x82, 0xb5, 0x5e, 0x8a, 0x06, 0xbe, 0x99, |
| 0x57, 0xb1, 0x76, 0xe1, 0xc5, 0xaa, 0x82, 0xe7, |
| }; |
| |
| static const struct AEADTestVector { |
| const char *name; |
| const EVP_AEAD *aead; |
| const uint8_t *key; |
| const int key_length; |
| const uint8_t *expected_ciphertext; |
| const int cipher_text_length; |
| const FIPSStatus expect_approved; |
| const bool test_repeat_nonce; |
| } kAEADTestVectors[] = { |
| // Internal IV usage of AES-GCM is approved. |
| { |
| "AES-GCM 128-bit key internal iv test", |
| EVP_aead_aes_128_gcm_randnonce(), |
| kAESKey, |
| sizeof(kAESKey), |
| nullptr, |
| 0, |
| FIPSStatus::APPROVED, |
| false, |
| }, |
| { |
| "AES-GCM 256-bit key internal iv test", |
| EVP_aead_aes_256_gcm_randnonce(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| nullptr, |
| 0, |
| FIPSStatus::APPROVED, |
| false, |
| }, |
| // External IV usage of AES-GCM is not approved unless used within a TLS |
| // context. |
| { |
| "Generic AES-GCM 128-bit key external iv test", |
| EVP_aead_aes_128_gcm(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESGCMCiphertext_128, |
| sizeof(kAESGCMCiphertext_128), |
| FIPSStatus::NOT_APPROVED, |
| false, |
| }, |
| { |
| "Generic AES-GCM 192-bit key external iv test", |
| EVP_aead_aes_192_gcm(), |
| kAESKey_192, |
| 24, |
| kAESGCMCiphertext_192, |
| sizeof(kAESGCMCiphertext_192), |
| FIPSStatus::NOT_APPROVED, |
| false, |
| }, |
| { |
| "Generic AES-GCM 256-bit key external iv test", |
| EVP_aead_aes_256_gcm(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESGCMCiphertext_256, |
| sizeof(kAESGCMCiphertext_256), |
| FIPSStatus::NOT_APPROVED, |
| false, |
| }, |
| // External IV usage of AEAD AES-GCM APIs specific for TLS is approved. |
| { |
| "TLS1.2 AES-GCM 128-bit key external iv test", |
| EVP_aead_aes_128_gcm_tls12(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESGCMCiphertext_128, |
| sizeof(kAESGCMCiphertext_128), |
| FIPSStatus::APPROVED, |
| true, |
| }, |
| { |
| "TLS1.2 AES-GCM 256-bit key external iv test", |
| EVP_aead_aes_256_gcm_tls12(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESGCMCiphertext_256, |
| sizeof(kAESGCMCiphertext_256), |
| FIPSStatus::APPROVED, |
| true, |
| }, |
| { |
| "TLS1.3 AES-GCM 128-bit key external iv test", |
| EVP_aead_aes_128_gcm_tls13(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESGCMCiphertext_128, |
| sizeof(kAESGCMCiphertext_128), |
| FIPSStatus::APPROVED, |
| true, |
| }, |
| { |
| "TLS1.3 AES-GCM 256-bit key external iv test", |
| EVP_aead_aes_256_gcm_tls13(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESGCMCiphertext_256, |
| sizeof(kAESGCMCiphertext_256), |
| FIPSStatus::APPROVED, |
| true, |
| }, |
| // 128 bit keys with 32 bit tag lengths are approved for AES-CCM. |
| { |
| "AES-CCM 128-bit key test", |
| EVP_aead_aes_128_ccm_bluetooth(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESCCMCiphertext, |
| sizeof(kAESCCMCiphertext), |
| FIPSStatus::APPROVED, |
| false, |
| }, |
| }; |
| |
| class AEADServiceIndicatorTest : public TestWithNoErrors<AEADTestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, AEADServiceIndicatorTest, |
| testing::ValuesIn(kAEADTestVectors)); |
| |
| TEST_P(AEADServiceIndicatorTest, EVP_AEAD) { |
| const AEADTestVector &test = GetParam(); |
| SCOPED_TRACE(test.name); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| bssl::ScopedEVP_AEAD_CTX aead_ctx; |
| std::vector<uint8_t> nonce(EVP_AEAD_nonce_length(test.aead), 0); |
| std::vector<uint8_t> encrypt_output(256); |
| std::vector<uint8_t> decrypt_output(256); |
| size_t out_len; |
| |
| // Test running the EVP_AEAD_CTX interfaces one by one directly, and check |
| // |EVP_AEAD_CTX_seal| and |EVP_AEAD_CTX_open| for approval at the end. |
| // |EVP_AEAD_CTX_init| should not be approved because the function does not |
| // indicate that a service has been fully completed yet. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_AEAD_CTX_init(aead_ctx.get(), test.aead, test.key, |
| test.key_length, 0, nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_AEAD_CTX_seal(aead_ctx.get(), encrypt_output.data(), |
| &out_len, encrypt_output.size(), nonce.data(), |
| EVP_AEAD_nonce_length(test.aead), kPlaintext, |
| sizeof(kPlaintext), nullptr, 0))); |
| EXPECT_EQ(approved, test.expect_approved); |
| encrypt_output.resize(out_len); |
| if (test.expected_ciphertext) { |
| EXPECT_EQ(Bytes(test.expected_ciphertext, test.cipher_text_length), |
| Bytes(encrypt_output)); |
| } |
| |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_AEAD_CTX_open(aead_ctx.get(), decrypt_output.data(), &out_len, |
| decrypt_output.size(), nonce.data(), nonce.size(), |
| encrypt_output.data(), out_len, nullptr, 0))); |
| // Decryption doesn't have nonce uniqueness requirements and so is always |
| // approved for approved key lengths. |
| EXPECT_EQ(approved, test.key_length != 24 ? FIPSStatus::APPROVED |
| : FIPSStatus::NOT_APPROVED); |
| decrypt_output.resize(out_len); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(decrypt_output)); |
| |
| // Second call when encrypting using the same nonce for AES-GCM TLS specific |
| // functions should fail and return |FIPSStatus::NOT_APPROVED|. |
| if (test.test_repeat_nonce) { |
| ASSERT_FALSE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_AEAD_CTX_seal(aead_ctx.get(), encrypt_output.data(), &out_len, |
| encrypt_output.size(), nonce.data(), nonce.size(), |
| kPlaintext, sizeof(kPlaintext), nullptr, 0))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| EXPECT_TRUE( |
| ErrorEquals(ERR_get_error(), ERR_LIB_CIPHER, CIPHER_R_INVALID_NONCE)); |
| } |
| } |
| |
| static const struct CipherTestVector { |
| const EVP_CIPHER *cipher; |
| const uint8_t *key; |
| const int key_length; |
| const uint8_t *expected_ciphertext; |
| const int cipher_text_length; |
| const bool has_iv; |
| const FIPSStatus expect_approved; |
| } kTestVectors[] = { |
| { |
| EVP_aes_128_ecb(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESECBCiphertext, |
| sizeof(kAESECBCiphertext), |
| false, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_192_ecb(), |
| kAESKey_192, |
| sizeof(kAESKey_192), |
| kAESECBCiphertext_192, |
| sizeof(kAESECBCiphertext_192), |
| false, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_256_ecb(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESECBCiphertext_256, |
| sizeof(kAESECBCiphertext_256), |
| false, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_128_cbc(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESCBCCiphertext, |
| sizeof(kAESCBCCiphertext), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_192_cbc(), |
| kAESKey_192, |
| sizeof(kAESKey_192), |
| kAESCBCCiphertext_192, |
| sizeof(kAESCBCCiphertext_192), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_256_cbc(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESCBCCiphertext_256, |
| sizeof(kAESCBCCiphertext_256), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_128_ctr(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESCTRCiphertext, |
| sizeof(kAESCTRCiphertext), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_192_ctr(), |
| kAESKey_192, |
| sizeof(kAESKey_192), |
| kAESCTRCiphertext_192, |
| sizeof(kAESCTRCiphertext_192), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_256_ctr(), |
| kAESKey_256, |
| sizeof(kAESKey_256), |
| kAESCTRCiphertext_256, |
| sizeof(kAESCTRCiphertext_256), |
| true, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| EVP_aes_128_ofb(), |
| kAESKey, |
| sizeof(kAESKey), |
| kAESOFBCiphertext, |
| sizeof(kAESOFBCiphertext), |
| true, |
| FIPSStatus::NOT_APPROVED, |
| }, |
| { |
| EVP_des_ede3(), |
| kAESKey_192, |
| sizeof(kAESKey_192), |
| kTDES_EDE3_CipherText, |
| sizeof(kTDES_EDE3_CipherText), |
| false, |
| FIPSStatus::NOT_APPROVED, |
| }, |
| { |
| EVP_des_ede3_cbc(), |
| kAESKey_192, |
| sizeof(kAESKey_192), |
| kTDES_EDE3_CBCCipherText, |
| sizeof(kTDES_EDE3_CBCCipherText), |
| false, |
| FIPSStatus::NOT_APPROVED, |
| }, |
| }; |
| |
| class EVPServiceIndicatorTest : public TestWithNoErrors<CipherTestVector> {}; |
| |
| static void TestOperation(const EVP_CIPHER *cipher, bool encrypt, |
| const bssl::Span<const uint8_t> key, |
| const bssl::Span<const uint8_t> plaintext, |
| const bssl::Span<const uint8_t> ciphertext, |
| FIPSStatus expect_approved) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| bssl::Span<const uint8_t> in, out; |
| if (encrypt) { |
| in = plaintext; |
| out = ciphertext; |
| } else { |
| in = ciphertext; |
| out = plaintext; |
| } |
| |
| bssl::ScopedEVP_CIPHER_CTX ctx; |
| // Test running the EVP_Cipher interfaces one by one directly, and check |
| // |EVP_EncryptFinal_ex| and |EVP_DecryptFinal_ex| for approval at the end. |
| ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, |
| encrypt ? 1 : 0)); |
| ASSERT_LE(EVP_CIPHER_CTX_iv_length(ctx.get()), sizeof(kAESIV)); |
| |
| ASSERT_TRUE(EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size())); |
| ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), cipher, nullptr, key.data(), kAESIV, |
| encrypt ? 1 : 0)); |
| ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0)); |
| std::vector<uint8_t> encrypt_result; |
| DoCipherFinal(ctx.get(), &encrypt_result, in, expect_approved); |
| EXPECT_EQ(Bytes(out), Bytes(encrypt_result)); |
| |
| // Test using the one-shot |EVP_Cipher| function for approval. |
| bssl::ScopedEVP_CIPHER_CTX ctx2; |
| uint8_t output[256]; |
| ASSERT_TRUE(EVP_CipherInit_ex(ctx2.get(), cipher, nullptr, key.data(), kAESIV, |
| encrypt ? 1 : 0)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_Cipher(ctx2.get(), output, in.data(), in.size())); |
| EXPECT_EQ(approved, expect_approved); |
| EXPECT_EQ(Bytes(out), Bytes(output, in.size())); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(All, EVPServiceIndicatorTest, |
| testing::ValuesIn(kTestVectors)); |
| |
| TEST_P(EVPServiceIndicatorTest, EVP_Ciphers) { |
| const CipherTestVector &test = GetParam(); |
| |
| const EVP_CIPHER *cipher = test.cipher; |
| std::vector<uint8_t> key(test.key, test.key + test.key_length); |
| std::vector<uint8_t> plaintext(kPlaintext, kPlaintext + sizeof(kPlaintext)); |
| std::vector<uint8_t> ciphertext( |
| test.expected_ciphertext, |
| test.expected_ciphertext + test.cipher_text_length); |
| |
| TestOperation(cipher, true /* encrypt */, key, plaintext, ciphertext, |
| test.expect_approved); |
| TestOperation(cipher, false /* decrypt */, key, plaintext, ciphertext, |
| test.expect_approved); |
| } |
| |
| static const struct DigestTestVector { |
| // name is the name of the digest test. |
| const char *name; |
| // length of digest. |
| const int length; |
| // func is the digest to test. |
| const EVP_MD *(*func)(); |
| // one_shot_func is the convenience one-shot version of the digest. |
| uint8_t *(*one_shot_func)(const uint8_t *, size_t, uint8_t *); |
| // expected_digest is the expected digest. |
| const uint8_t *expected_digest; |
| // expected to be approved or not. |
| const FIPSStatus expect_approved; |
| } kDigestTestVectors[] = { |
| { |
| "MD4", |
| MD4_DIGEST_LENGTH, |
| &EVP_md4, |
| &MD4, |
| kOutput_md4, |
| FIPSStatus::NOT_APPROVED, |
| }, |
| { |
| "MD5", |
| MD5_DIGEST_LENGTH, |
| &EVP_md5, |
| &MD5, |
| kOutput_md5, |
| FIPSStatus::NOT_APPROVED, |
| }, |
| { |
| "SHA-1", |
| SHA_DIGEST_LENGTH, |
| &EVP_sha1, |
| &SHA1, |
| kOutput_sha1, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| "SHA-224", |
| SHA224_DIGEST_LENGTH, |
| &EVP_sha224, |
| &SHA224, |
| kOutput_sha224, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| "SHA-256", |
| SHA256_DIGEST_LENGTH, |
| &EVP_sha256, |
| &SHA256, |
| kOutput_sha256, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| "SHA-384", |
| SHA384_DIGEST_LENGTH, |
| &EVP_sha384, |
| &SHA384, |
| kOutput_sha384, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| "SHA-512", |
| SHA512_DIGEST_LENGTH, |
| &EVP_sha512, |
| &SHA512, |
| kOutput_sha512, |
| FIPSStatus::APPROVED, |
| }, |
| { |
| "SHA-512/256", |
| SHA512_256_DIGEST_LENGTH, |
| &EVP_sha512_256, |
| &SHA512_256, |
| kOutput_sha512_256, |
| FIPSStatus::APPROVED, |
| }, |
| }; |
| |
| class EVPMDServiceIndicatorTest : public TestWithNoErrors<DigestTestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, EVPMDServiceIndicatorTest, |
| testing::ValuesIn(kDigestTestVectors)); |
| |
| TEST_P(EVPMDServiceIndicatorTest, EVP_Digests) { |
| const DigestTestVector &test = GetParam(); |
| SCOPED_TRACE(test.name); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| bssl::ScopedEVP_MD_CTX ctx; |
| std::vector<uint8_t> digest(test.length); |
| unsigned digest_len; |
| |
| // Test running the EVP_Digest interfaces one by one directly, and check |
| // |EVP_DigestFinal_ex| for approval at the end. |EVP_DigestInit_ex| and |
| // |EVP_DigestUpdate| should not be approved, because the functions do not |
| // indicate that a service has been fully completed yet. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestInit_ex(ctx.get(), test.func(), nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestUpdate(ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestFinal_ex(ctx.get(), digest.data(), &digest_len))); |
| EXPECT_EQ(approved, test.expect_approved); |
| EXPECT_EQ(Bytes(test.expected_digest, digest_len), Bytes(digest)); |
| |
| // Test using the one-shot |EVP_Digest| function for approval. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_Digest(kPlaintext, sizeof(kPlaintext), digest.data(), |
| &digest_len, test.func(), nullptr))); |
| EXPECT_EQ(approved, test.expect_approved); |
| EXPECT_EQ(Bytes(test.expected_digest, test.length), Bytes(digest)); |
| |
| // Test using the one-shot API for approval. |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| test.one_shot_func(kPlaintext, sizeof(kPlaintext), digest.data())); |
| EXPECT_EQ(approved, test.expect_approved); |
| EXPECT_EQ(Bytes(test.expected_digest, test.length), Bytes(digest)); |
| } |
| |
| static const struct HMACTestVector { |
| // func is the hash function for HMAC to test. |
| const EVP_MD *(*func)(void); |
| // expected_digest is the expected digest. |
| const uint8_t *expected_digest; |
| // expected to be approved or not. |
| const FIPSStatus expect_approved; |
| } kHMACTestVectors[] = { |
| {EVP_sha1, kHMACOutput_sha1, FIPSStatus::APPROVED}, |
| {EVP_sha224, kHMACOutput_sha224, FIPSStatus::APPROVED}, |
| {EVP_sha256, kHMACOutput_sha256, FIPSStatus::APPROVED}, |
| {EVP_sha384, kHMACOutput_sha384, FIPSStatus::APPROVED}, |
| {EVP_sha512, kHMACOutput_sha512, FIPSStatus::APPROVED}, |
| {EVP_sha512_256, kHMACOutput_sha512_256, FIPSStatus::APPROVED}, |
| }; |
| |
| class HMACServiceIndicatorTest : public TestWithNoErrors<HMACTestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, HMACServiceIndicatorTest, |
| testing::ValuesIn(kHMACTestVectors)); |
| |
| TEST_P(HMACServiceIndicatorTest, HMACTest) { |
| const HMACTestVector &test = GetParam(); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| // The key is deliberately long in order to trigger digesting it down to a |
| // block size. This tests that doing so does not cause the indicator to be |
| // mistakenly set in |HMAC_Init_ex|. |
| const uint8_t kHMACKey[512] = {0}; |
| const EVP_MD *const digest = test.func(); |
| const unsigned expected_mac_len = EVP_MD_size(digest); |
| std::vector<uint8_t> mac(expected_mac_len); |
| |
| // Test running the HMAC interfaces one by one directly, and check |
| // |HMAC_Final| for approval at the end. |HMAC_Init_ex| and |HMAC_Update| |
| // should not be approved, because the functions do not indicate that a |
| // service has been fully completed yet. |
| unsigned mac_len; |
| bssl::ScopedHMAC_CTX ctx; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| HMAC_Init_ex(ctx.get(), kHMACKey, sizeof(kHMACKey), digest, nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, HMAC_Update(ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, HMAC_Final(ctx.get(), mac.data(), &mac_len))); |
| EXPECT_EQ(approved, test.expect_approved); |
| EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), |
| Bytes(mac.data(), mac_len)); |
| |
| // Test using the one-shot API for approval. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, HMAC(digest, kHMACKey, sizeof(kHMACKey), kPlaintext, |
| sizeof(kPlaintext), mac.data(), &mac_len))); |
| EXPECT_EQ(approved, test.expect_approved); |
| EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), |
| Bytes(mac.data(), mac_len)); |
| } |
| |
| // RSA tests are not parameterized with the |kRSATestVectors| as key |
| // generation for RSA is time consuming. |
| TEST(ServiceIndicatorTest, RSAKeyGen) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| bssl::UniquePtr<RSA> rsa(RSA_new()); |
| ASSERT_TRUE(rsa); |
| |
| // |RSA_generate_key_fips| may only be used for 2048-, 3072-, and 4096-bit |
| // keys. |
| for (const size_t bits : {512, 1024, 3071, 4095}) { |
| SCOPED_TRACE(bits); |
| |
| rsa.reset(RSA_new()); |
| EXPECT_FALSE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, RSA_generate_key_fips(rsa.get(), bits, nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| |
| // Test that we can generate keys of the supported lengths: |
| for (const size_t bits : {2048, 3072, 4096}) { |
| SCOPED_TRACE(bits); |
| |
| rsa.reset(RSA_new()); |
| EXPECT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, RSA_generate_key_fips(rsa.get(), bits, nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| EXPECT_EQ(bits, RSA_bits(rsa.get())); |
| } |
| |
| // Test running the EVP_PKEY_keygen interfaces one by one directly, and check |
| // |EVP_PKEY_keygen| for approval at the end. |EVP_PKEY_keygen_init| should |
| // not be approved because it does not indicate an entire service has been |
| // completed. |
| bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); |
| EVP_PKEY *raw = nullptr; |
| bssl::UniquePtr<EVP_PKEY> pkey(raw); |
| ASSERT_TRUE(ctx); |
| |
| if (kEVPKeyGenShouldCallFIPSFunctions) { |
| // Test unapproved key sizes of RSA. |
| for (const size_t bits : {512, 1024, 3071, 4095}) { |
| SCOPED_TRACE(bits); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_keygen_init(ctx.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), bits)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_keygen(ctx.get(), &raw))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| pkey.reset(raw); |
| raw = nullptr; |
| } |
| |
| // Test approved key sizes of RSA. |
| for (const size_t bits : {2048, 3072, 4096}) { |
| SCOPED_TRACE(bits); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_keygen_init(ctx.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), bits)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_keygen(ctx.get(), &raw))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| pkey.reset(raw); |
| raw = nullptr; |
| } |
| } |
| } |
| |
| struct RSATestVector { |
| // key_size is the input rsa key size. |
| int key_size; |
| // md_func is the digest to test. |
| const EVP_MD *(*func)(); |
| // whether to use pss testing or not. |
| bool use_pss; |
| // expected to be approved or not for signature generation. |
| FIPSStatus sig_gen_expect_approved; |
| // expected to be approved or not for signature verification. |
| FIPSStatus sig_ver_expect_approved; |
| }; |
| |
| static const struct RSATestVector kRSATestVectors[] = { |
| // RSA test cases that are not approved in any case. |
| {512, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| // PSS with hashLen == saltLen is not possible for 512-bit modulus. |
| {1024, &EVP_md5, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {1536, &EVP_sha256, false, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {1536, &EVP_sha512, true, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {2048, &EVP_md5, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {3071, &EVP_md5, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {3071, &EVP_sha256, false, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {3071, &EVP_sha512, true, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {4096, &EVP_md5, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| |
| // RSA 1024 is not approved under FIPS 186-5. |
| {1024, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {1024, &EVP_sha256, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {1024, &EVP_sha512, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {1024, &EVP_sha1, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {1024, &EVP_sha256, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| // PSS with hashLen == saltLen is not possible for 1024-bit modulus and |
| // SHA-512. |
| |
| {2048, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {2048, &EVP_sha224, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha256, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha384, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha512, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha1, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {2048, &EVP_sha224, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha256, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha384, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {2048, &EVP_sha512, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| |
| {3072, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {3072, &EVP_sha224, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha256, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha384, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha512, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha1, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {3072, &EVP_sha224, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha256, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha384, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {3072, &EVP_sha512, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| |
| {4096, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {4096, &EVP_sha224, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha256, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha384, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha512, false, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha1, true, FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {4096, &EVP_sha224, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha256, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha384, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {4096, &EVP_sha512, true, FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| }; |
| |
| class RSAServiceIndicatorTest : public TestWithNoErrors<RSATestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, RSAServiceIndicatorTest, |
| testing::ValuesIn(kRSATestVectors)); |
| |
| static std::map<unsigned, bssl::UniquePtr<RSA>> &CachedRSAKeys() { |
| static std::map<unsigned, bssl::UniquePtr<RSA>> keys; |
| return keys; |
| } |
| |
| static RSA *GetRSAKey(unsigned bits) { |
| auto it = CachedRSAKeys().find(bits); |
| if (it != CachedRSAKeys().end()) { |
| return it->second.get(); |
| } |
| |
| bssl::UniquePtr<BIGNUM> e(BN_new()); |
| if (!e || !BN_set_word(e.get(), RSA_F4)) { |
| abort(); |
| } |
| |
| bssl::UniquePtr<RSA> key(RSA_new()); |
| if (!key || !RSA_generate_key_ex(key.get(), bits, e.get(), nullptr)) { |
| abort(); |
| } |
| |
| RSA *const ret = key.get(); |
| CachedRSAKeys().emplace(static_cast<unsigned>(bits), std::move(key)); |
| |
| return ret; |
| } |
| |
| TEST_P(RSAServiceIndicatorTest, RSASigGen) { |
| const RSATestVector &test = GetParam(); |
| SCOPED_TRACE(test.key_size); |
| |
| bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); |
| ASSERT_TRUE(pkey); |
| |
| RSA *const rsa = GetRSAKey(test.key_size); |
| ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa)); |
| |
| // Test running the EVP_DigestSign interfaces one by one directly, and check |
| // |EVP_DigestSignFinal| for approval at the end. |EVP_DigestSignInit|, and |
| // |EVP_DigestSignUpdate| should not be approved because they do not indicate |
| // an entire service has been completed. |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| EVP_PKEY_CTX *pctx = nullptr; |
| size_t sig_len; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| if (test.use_pss) { |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestSignUpdate(md_ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| // Determine the size of the signature. The first call of |
| // |EVP_DigestSignFinal| should not return an approval check because no crypto |
| // is being done when |nullptr| is inputted in the |*out_sig| field. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| std::vector<uint8_t> signature(sig_len); |
| // The second call performs the actual operation. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignFinal(md_ctx.get(), signature.data(), &sig_len))); |
| EXPECT_EQ(approved, test.sig_gen_expect_approved); |
| |
| // Test using the one-shot |EVP_DigestSign| function for approval. |
| md_ctx.Reset(); |
| std::vector<uint8_t> oneshot_output(sig_len); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| if (test.use_pss) { |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSign(md_ctx.get(), oneshot_output.data(), &sig_len, |
| kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, test.sig_gen_expect_approved); |
| |
| if (test.use_pss) { |
| // Odd configurations of PSS, for example where the salt length is not equal |
| // to the hash length, are not approved. |
| md_ctx.Reset(); |
| ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get())); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING)); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, 10)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSign(md_ctx.get(), oneshot_output.data(), &sig_len, |
| kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| } |
| |
| TEST_P(RSAServiceIndicatorTest, RSASigVer) { |
| const RSATestVector &test = GetParam(); |
| |
| bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); |
| RSA *const rsa = GetRSAKey(test.key_size); |
| |
| ASSERT_TRUE(pkey); |
| ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa)); |
| |
| std::vector<uint8_t> signature; |
| size_t sig_len; |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| EVP_PKEY_CTX *pctx = nullptr; |
| ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get())); |
| if (test.use_pss) { |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING)); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)); |
| } |
| ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, nullptr, 0)); |
| signature.resize(sig_len); |
| ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, |
| kPlaintext, sizeof(kPlaintext))); |
| signature.resize(sig_len); |
| |
| // Service Indicator approval checks for RSA signature verification. |
| |
| // Test running the EVP_DigestVerify interfaces one by one directly, and check |
| // |EVP_DigestVerifyFinal| for approval at the end. |EVP_DigestVerifyInit|, |
| // |EVP_DigestVerifyUpdate| should not be approved because they do not |
| // indicate an entire service has been done. |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| md_ctx.Reset(); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestVerifyInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| if (test.use_pss) { |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)); |
| } |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerifyUpdate(md_ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerifyFinal(md_ctx.get(), signature.data(), signature.size()))); |
| EXPECT_EQ(approved, test.sig_ver_expect_approved); |
| |
| // Test using the one-shot |EVP_DigestVerify| function for approval. |
| md_ctx.Reset(); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestVerifyInit(md_ctx.get(), &pctx, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| if (test.use_pss) { |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1)); |
| } |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerify(md_ctx.get(), signature.data(), signature.size(), |
| kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, test.sig_ver_expect_approved); |
| } |
| |
| struct ECDSATestVector { |
| // nid is the input curve nid. |
| int nid; |
| // md_func is the digest to test. |
| const EVP_MD *(*func)(); |
| // expected to be approved or not for key generation. |
| FIPSStatus key_check_expect_approved; |
| // expected to be approved or not for signature generation. |
| FIPSStatus sig_gen_expect_approved; |
| // expected to be approved or not for signature verification. |
| FIPSStatus sig_ver_expect_approved; |
| }; |
| |
| static const struct ECDSATestVector kECDSATestVectors[] = { |
| // Only the following NIDs for |EC_GROUP| are creatable with |
| // |EC_GROUP_new_by_curve_name|, and |NID_secp256k1| will only work if |
| // |kCurveSecp256k1Supported| is true. |
| {NID_secp224r1, &EVP_sha1, FIPSStatus::APPROVED, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {NID_secp224r1, &EVP_sha224, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp224r1, &EVP_sha256, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp224r1, &EVP_sha384, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp224r1, &EVP_sha512, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| |
| {NID_X9_62_prime256v1, &EVP_sha1, FIPSStatus::APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {NID_X9_62_prime256v1, &EVP_sha224, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, &EVP_sha256, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, &EVP_sha384, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, &EVP_sha512, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED, FIPSStatus::APPROVED}, |
| |
| {NID_secp384r1, &EVP_sha1, FIPSStatus::APPROVED, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {NID_secp384r1, &EVP_sha224, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp384r1, &EVP_sha256, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp384r1, &EVP_sha384, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp384r1, &EVP_sha512, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| |
| {NID_secp521r1, &EVP_sha1, FIPSStatus::APPROVED, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED}, |
| {NID_secp521r1, &EVP_sha224, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp521r1, &EVP_sha256, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp521r1, &EVP_sha384, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| {NID_secp521r1, &EVP_sha512, FIPSStatus::APPROVED, FIPSStatus::APPROVED, |
| FIPSStatus::APPROVED}, |
| |
| {NID_secp256k1, &EVP_sha1, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, &EVP_sha224, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, &EVP_sha256, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, &EVP_sha384, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, &EVP_sha512, FIPSStatus::NOT_APPROVED, |
| FIPSStatus::NOT_APPROVED, FIPSStatus::NOT_APPROVED}, |
| }; |
| |
| class ECDSAServiceIndicatorTest : public TestWithNoErrors<ECDSATestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, ECDSAServiceIndicatorTest, |
| testing::ValuesIn(kECDSATestVectors)); |
| |
| TEST_P(ECDSAServiceIndicatorTest, ECDSAKeyCheck) { |
| const ECDSATestVector &test = GetParam(); |
| if (test.nid == NID_secp256k1 && !kCurveSecp256k1Supported) { |
| GTEST_SKIP(); |
| } |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| // Test service indicator approval for |EC_KEY_generate_key_fips| and |
| // |EC_KEY_check_fips|. |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(test.nid)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EC_KEY_generate_key_fips(key.get()))); |
| EXPECT_EQ(approved, test.key_check_expect_approved); |
| ASSERT_TRUE( |
| CALL_SERVICE_AND_CHECK_APPROVED(approved, EC_KEY_check_fips(key.get()))); |
| EXPECT_EQ(approved, test.key_check_expect_approved); |
| |
| // See if |EC_KEY_check_fips| still returns approval with only the public |
| // component. |
| bssl::UniquePtr<EC_KEY> key_only_public(EC_KEY_new_by_curve_name(test.nid)); |
| ASSERT_TRUE(EC_KEY_set_public_key(key_only_public.get(), |
| EC_KEY_get0_public_key(key.get()))); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EC_KEY_check_fips(key_only_public.get()))); |
| EXPECT_EQ(approved, test.key_check_expect_approved); |
| |
| if (kEVPKeyGenShouldCallFIPSFunctions) { |
| // Test running the EVP_PKEY_keygen interfaces one by one directly, and |
| // check |EVP_PKEY_keygen| for approval at the end. |EVP_PKEY_keygen_init| |
| // should not be approved because it does not indicate that an entire |
| // service has been completed. |
| bssl::UniquePtr<EVP_PKEY_CTX> ctx( |
| EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr)); |
| EVP_PKEY *raw = nullptr; |
| ASSERT_TRUE(ctx); |
| ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), test.nid)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_keygen(ctx.get(), &raw))); |
| EXPECT_EQ(approved, test.key_check_expect_approved); |
| |
| EVP_PKEY_free(raw); |
| } |
| } |
| |
| TEST_P(ECDSAServiceIndicatorTest, ECDSASigGen) { |
| const ECDSATestVector &test = GetParam(); |
| if (test.nid == NID_secp256k1 && !kCurveSecp256k1Supported) { |
| GTEST_SKIP(); |
| } |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| const EC_GROUP *group = EC_GROUP_new_by_curve_name(test.nid); |
| bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); |
| bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| ASSERT_TRUE(eckey); |
| ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group)); |
| |
| // Generate a generic EC key. |
| ASSERT_TRUE(EC_KEY_generate_key(eckey.get())); |
| ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), eckey.get())); |
| |
| // Test running the EVP_DigestSign interfaces one by one directly, and check |
| // |EVP_DigestSignFinal| for approval at the end. |EVP_DigestSignInit|, |
| // |EVP_DigestSignUpdate| should not be approved because they do not indicate |
| // an entire service has been done. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignInit(md_ctx.get(), nullptr, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestSignUpdate(md_ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| // Determine the size of the signature. The first call of |
| // |EVP_DigestSignFinal| should not return an approval check because no crypto |
| // is being done when |nullptr| is given as the |out_sig| field. |
| size_t max_sig_len; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignFinal(md_ctx.get(), nullptr, &max_sig_len))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| std::vector<uint8_t> signature(max_sig_len); |
| // The second call performs the actual operation. |
| size_t sig_len = max_sig_len; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignFinal(md_ctx.get(), signature.data(), &sig_len))); |
| ASSERT_LE(sig_len, signature.size()); |
| EXPECT_EQ(approved, test.sig_gen_expect_approved); |
| |
| // Test using the one-shot |EVP_DigestSign| function for approval. |
| md_ctx.Reset(); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSignInit(md_ctx.get(), nullptr, test.func(), nullptr, |
| pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| sig_len = max_sig_len; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, |
| kPlaintext, sizeof(kPlaintext)))); |
| ASSERT_LE(sig_len, signature.size()); |
| EXPECT_EQ(approved, test.sig_gen_expect_approved); |
| } |
| |
| TEST_P(ECDSAServiceIndicatorTest, ECDSASigVer) { |
| const ECDSATestVector &test = GetParam(); |
| if (test.nid == NID_secp256k1 && !kCurveSecp256k1Supported) { |
| GTEST_SKIP(); |
| } |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| const EC_GROUP *group = EC_GROUP_new_by_curve_name(test.nid); |
| bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); |
| bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| ASSERT_TRUE(eckey); |
| ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group)); |
| |
| // Generate ECDSA signatures for ECDSA verification. |
| ASSERT_TRUE(EC_KEY_generate_key(eckey.get())); |
| ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), eckey.get())); |
| std::vector<uint8_t> signature; |
| size_t sig_len = 0; |
| ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, test.func(), nullptr, |
| pkey.get())); |
| ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len)); |
| signature.resize(sig_len); |
| ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), signature.data(), &sig_len, |
| kPlaintext, sizeof(kPlaintext))); |
| signature.resize(sig_len); |
| |
| // Service Indicator approval checks for ECDSA signature verification. |
| |
| // Test running the EVP_DigestVerify interfaces one by one directly, and check |
| // |EVP_DigestVerifyFinal| for approval at the end. |EVP_DigestVerifyInit|, |
| // |EVP_DigestVerifyUpdate| should not be approved because they do not |
| // indicate an entire service has been done. |
| md_ctx.Reset(); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestVerifyInit(md_ctx.get(), nullptr, test.func(), |
| nullptr, pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerifyUpdate(md_ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerifyFinal(md_ctx.get(), signature.data(), signature.size()))); |
| EXPECT_EQ(approved, test.sig_ver_expect_approved); |
| |
| // Test using the one-shot |EVP_DigestVerify| function for approval. |
| md_ctx.Reset(); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_DigestVerifyInit(md_ctx.get(), nullptr, test.func(), |
| nullptr, pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_DigestVerify(md_ctx.get(), signature.data(), signature.size(), |
| kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, test.sig_ver_expect_approved); |
| } |
| |
| #if defined(AWSLC_FIPS) |
| |
| // Test that |EVP_DigestSignFinal| and |EVP_DigestSignVerify| are approved with |
| // manually constructing using the context setting functions. |
| TEST_P(ECDSAServiceIndicatorTest, ManualECDSASignVerify) { |
| const ECDSATestVector &test = GetParam(); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| bssl::ScopedEVP_MD_CTX ctx; |
| ASSERT_TRUE(EVP_DigestInit(ctx.get(), test.func())); |
| ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), kPlaintext, sizeof(kPlaintext))); |
| |
| const EC_GROUP *group = EC_GROUP_new_by_curve_name(test.nid); |
| bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); |
| bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| ASSERT_TRUE(eckey); |
| ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group)); |
| |
| // Generate a generic ec key. |
| EC_KEY_generate_key(eckey.get()); |
| ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), eckey.get())); |
| |
| // Manual construction for signing. |
| bssl::UniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); |
| ASSERT_TRUE(EVP_PKEY_sign_init(pctx.get())); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), test.func())); |
| EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get()); |
| // Determine the size of the signature. |
| size_t sig_len = 0; |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| std::vector<uint8_t> sig; |
| sig.resize(sig_len); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), sig.data(), &sig_len))); |
| EXPECT_EQ(approved, test.sig_gen_expect_approved); |
| sig.resize(sig_len); |
| |
| // Manual construction for verification. |
| ASSERT_TRUE(EVP_PKEY_verify_init(pctx.get())); |
| ASSERT_TRUE(EVP_PKEY_CTX_set_signature_md(pctx.get(), test.func())); |
| EVP_MD_CTX_set_pkey_ctx(ctx.get(), pctx.get()); |
| |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| ASSERT_TRUE(EVP_DigestVerifyFinal(ctx.get(), sig.data(), sig_len))); |
| EXPECT_EQ(approved, test.sig_ver_expect_approved); |
| } |
| |
| #endif // AWSLC_FIPS |
| |
| struct ECDHTestVector { |
| // nid is the input curve nid. |
| const int nid; |
| // digest_length is the length of the hash output to test with. |
| const int digest_length; |
| // expect_approved to be approved or not. |
| const FIPSStatus expect_approved; |
| }; |
| |
| static const struct ECDHTestVector kECDHTestVectors[] = { |
| // Only the following NIDs for |EC_GROUP| are creatable with |
| // |EC_GROUP_new_by_curve_name|. |
| // |ECDH_compute_key_fips| fails directly when an invalid hash length is |
| // inputted. |
| {NID_secp224r1, SHA224_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp224r1, SHA256_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp224r1, SHA384_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp224r1, SHA512_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| |
| {NID_X9_62_prime256v1, SHA224_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, SHA256_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, SHA384_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_X9_62_prime256v1, SHA512_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| |
| {NID_secp384r1, SHA224_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp384r1, SHA256_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp384r1, SHA384_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp384r1, SHA512_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| |
| {NID_secp521r1, SHA224_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp521r1, SHA256_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp521r1, SHA384_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| {NID_secp521r1, SHA512_DIGEST_LENGTH, FIPSStatus::APPROVED}, |
| |
| {NID_secp256k1, SHA224_DIGEST_LENGTH, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, SHA256_DIGEST_LENGTH, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, SHA384_DIGEST_LENGTH, FIPSStatus::NOT_APPROVED}, |
| {NID_secp256k1, SHA512_DIGEST_LENGTH, FIPSStatus::NOT_APPROVED}, |
| }; |
| |
| class ECDH_ServiceIndicatorTest : public TestWithNoErrors<ECDHTestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, ECDH_ServiceIndicatorTest, |
| testing::ValuesIn(kECDHTestVectors)); |
| |
| TEST_P(ECDH_ServiceIndicatorTest, ECDH) { |
| const ECDHTestVector &test = GetParam(); |
| if (test.nid == NID_secp256k1 && !kCurveSecp256k1Supported) { |
| GTEST_SKIP(); |
| } |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| const EC_GROUP *group = EC_GROUP_new_by_curve_name(test.nid); |
| bssl::UniquePtr<EC_KEY> our_key(EC_KEY_new()); |
| bssl::UniquePtr<EC_KEY> peer_key(EC_KEY_new()); |
| bssl::ScopedEVP_MD_CTX md_ctx; |
| ASSERT_TRUE(our_key); |
| ASSERT_TRUE(peer_key); |
| |
| // Generate two generic ec key pairs. |
| ASSERT_TRUE(EC_KEY_set_group(our_key.get(), group)); |
| ASSERT_TRUE(EC_KEY_generate_key(our_key.get())); |
| ASSERT_TRUE(EC_KEY_check_key(our_key.get())); |
| |
| ASSERT_TRUE(EC_KEY_set_group(peer_key.get(), group)); |
| ASSERT_TRUE(EC_KEY_generate_key(peer_key.get())); |
| ASSERT_TRUE(EC_KEY_check_key(peer_key.get())); |
| |
| // Test that |ECDH_compute_key_fips| has service indicator approval as |
| // expected. |
| std::vector<uint8_t> digest(test.digest_length); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, ECDH_compute_key_fips(digest.data(), digest.size(), |
| EC_KEY_get0_public_key(peer_key.get()), |
| our_key.get()))); |
| EXPECT_EQ(approved, test.expect_approved); |
| |
| // Test running the EVP_PKEY_derive interfaces one by one directly, and check |
| // |EVP_PKEY_derive| for approval at the end. |EVP_PKEY_derive_init| and |
| // |EVP_PKEY_derive_set_peer| should not be approved because they do not |
| // indicate an entire service has been done. |
| bssl::UniquePtr<EVP_PKEY> our_pkey(EVP_PKEY_new()); |
| ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(our_pkey.get(), our_key.get())); |
| bssl::UniquePtr<EVP_PKEY_CTX> our_ctx( |
| EVP_PKEY_CTX_new(our_pkey.get(), nullptr)); |
| bssl::UniquePtr<EVP_PKEY> peer_pkey(EVP_PKEY_new()); |
| ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(peer_pkey.get(), peer_key.get())); |
| |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_derive_init(our_ctx.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_derive_set_peer(our_ctx.get(), peer_pkey.get()))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| // Determine the size of the output key. The first call of |EVP_PKEY_derive| |
| // should not return an approval check because no crypto is being done when |
| // |nullptr| is inputted in the |*key| field |
| size_t out_len = 0; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_PKEY_derive(our_ctx.get(), nullptr, &out_len))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| std::vector<uint8_t> derive_output(out_len); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_PKEY_derive(our_ctx.get(), derive_output.data(), &out_len))); |
| EXPECT_EQ(approved, kEVPDeriveSetsServiceIndicator |
| ? test.expect_approved |
| : FIPSStatus::NOT_APPROVED); |
| } |
| |
| static const struct KDFTestVector { |
| // func is the hash function for KDF to test. |
| const EVP_MD *(*func)(); |
| const uint8_t *expected_output; |
| const FIPSStatus expect_approved; |
| } kKDFTestVectors[] = { |
| {EVP_md5_sha1, kTLSOutput_md5_sha1, FIPSStatus::APPROVED}, |
| {EVP_sha224, kTLSOutput_sha224, FIPSStatus::NOT_APPROVED}, |
| {EVP_sha256, kTLSOutput_sha256, FIPSStatus::APPROVED}, |
| {EVP_sha384, kTLSOutput_sha384, FIPSStatus::APPROVED}, |
| {EVP_sha512, kTLSOutput_sha512, FIPSStatus::APPROVED}, |
| }; |
| |
| class KDF_ServiceIndicatorTest : public TestWithNoErrors<KDFTestVector> {}; |
| |
| INSTANTIATE_TEST_SUITE_P(All, KDF_ServiceIndicatorTest, |
| testing::ValuesIn(kKDFTestVectors)); |
| |
| TEST_P(KDF_ServiceIndicatorTest, TLSKDF) { |
| const KDFTestVector &test = GetParam(); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| uint8_t output[32]; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CRYPTO_tls1_prf(test.func(), output, sizeof(output), kTLSSecret, |
| sizeof(kTLSSecret), kTLSLabel, |
| sizeof(kTLSLabel), kTLSSeed1, sizeof(kTLSSeed1), |
| kTLSSeed2, sizeof(kTLSSeed2)))); |
| EXPECT_EQ(Bytes(test.expected_output, sizeof(output)), |
| Bytes(output, sizeof(output))); |
| EXPECT_EQ(approved, test.expect_approved); |
| } |
| |
| TEST_P(KDF_ServiceIndicatorTest, TLS13KDF) { |
| const KDFTestVector &test = GetParam(); |
| |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| uint8_t output[32]; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CRYPTO_tls13_hkdf_expand_label( |
| output, sizeof(output), test.func(), kTLSSecret, |
| sizeof(kTLSSecret), /*label=*/kTLSSeed1, sizeof(kTLSSeed1), |
| /*hash=*/kTLSSeed2, sizeof(kTLSSeed2)))); |
| |
| EXPECT_EQ(approved, test.expect_approved); |
| } |
| |
| TEST(ServiceIndicatorTest, CMAC) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new()); |
| ASSERT_TRUE(ctx); |
| |
| // Test running the CMAC interfaces one by one directly, and check |
| // |CMAC_Final| for approval at the end. |CMAC_Init| and |CMAC_Update| |
| // should not be approved, because the functions do not indicate that a |
| // service has been fully completed yet. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CMAC_Init(ctx.get(), kAESKey, sizeof(kAESKey), |
| EVP_aes_128_cbc(), nullptr))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CMAC_Update(ctx.get(), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| uint8_t mac[16]; |
| size_t out_len; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CMAC_Final(ctx.get(), mac, &out_len))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| EXPECT_EQ(Bytes(kAESCMACOutput), Bytes(mac)); |
| |
| // Test using the one-shot API for approval. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_CMAC(mac, kAESKey, sizeof(kAESKey), kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(Bytes(kAESCMACOutput), Bytes(mac)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, BasicTest) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| bssl::ScopedEVP_AEAD_CTX aead_ctx; |
| ASSERT_TRUE(EVP_AEAD_CTX_init(aead_ctx.get(), |
| EVP_aead_aes_128_gcm_randnonce(), kAESKey, |
| sizeof(kAESKey), 0, nullptr)); |
| // This test ensures that the counter gets incremented once, i.e. it was |
| // locked through the internal calls. |
| const int counter_before = FIPS_service_indicator_after_call(); |
| size_t out_len; |
| uint8_t output[256]; |
| EVP_AEAD_CTX_seal(aead_ctx.get(), output, &out_len, sizeof(output), nullptr, |
| 0, kPlaintext, sizeof(kPlaintext), nullptr, 0); |
| const int counter_after = FIPS_service_indicator_after_call(); |
| EXPECT_EQ(counter_after, counter_before + 1); |
| |
| // Call an approved service. |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_AEAD_CTX_seal(aead_ctx.get(), output, &out_len, |
| sizeof(output), nullptr, 0, kPlaintext, |
| sizeof(kPlaintext), nullptr, 0)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // Fail an approved service on purpose. |
| ASSERT_FALSE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_AEAD_CTX_seal(aead_ctx.get(), output, &out_len, 0, nullptr, 0, |
| kPlaintext, sizeof(kPlaintext), nullptr, 0))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| // Call a non-approved service. |
| uint8_t aes_iv[sizeof(kAESIV)]; |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| AES_KEY aes_key; |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| int num = 0; |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ofb128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, &num)); |
| EXPECT_EQ(Bytes(kAESOFBCiphertext), Bytes(output, sizeof(kAESOFBCiphertext))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| |
| // Test the SHA interfaces one by one and check that only |*_Final| does the |
| // approval at the end. |
| TEST(ServiceIndicatorTest, SHA) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| std::vector<uint8_t> digest; |
| |
| digest.resize(MD4_DIGEST_LENGTH); |
| MD4_CTX md4_ctx; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED(approved, MD4_Init(&md4_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, MD4_Update(&md4_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, MD4_Final(digest.data(), &md4_ctx))); |
| EXPECT_EQ(Bytes(kOutput_md4), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| digest.resize(MD5_DIGEST_LENGTH); |
| MD5_CTX md5_ctx; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED(approved, MD5_Init(&md5_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, MD5_Update(&md5_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, MD5_Final(digest.data(), &md5_ctx))); |
| EXPECT_EQ(Bytes(kOutput_md5), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| digest.resize(SHA_DIGEST_LENGTH); |
| SHA_CTX sha_ctx; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED(approved, SHA1_Init(&sha_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA1_Update(&sha_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA1_Final(digest.data(), &sha_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha1), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| digest.resize(SHA224_DIGEST_LENGTH); |
| SHA256_CTX sha224_ctx; |
| ASSERT_TRUE( |
| CALL_SERVICE_AND_CHECK_APPROVED(approved, SHA224_Init(&sha224_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA224_Update(&sha224_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA224_Final(digest.data(), &sha224_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha224), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| digest.resize(SHA256_DIGEST_LENGTH); |
| SHA256_CTX sha256_ctx; |
| ASSERT_TRUE( |
| CALL_SERVICE_AND_CHECK_APPROVED(approved, SHA256_Init(&sha256_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA256_Update(&sha256_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA256_Final(digest.data(), &sha256_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha256), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| digest.resize(SHA384_DIGEST_LENGTH); |
| SHA512_CTX sha384_ctx; |
| ASSERT_TRUE( |
| CALL_SERVICE_AND_CHECK_APPROVED(approved, SHA384_Init(&sha384_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA384_Update(&sha384_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA384_Final(digest.data(), &sha384_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha384), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| digest.resize(SHA512_DIGEST_LENGTH); |
| SHA512_CTX sha512_ctx; |
| ASSERT_TRUE( |
| CALL_SERVICE_AND_CHECK_APPROVED(approved, SHA512_Init(&sha512_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA512_Update(&sha512_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA512_Final(digest.data(), &sha512_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha512), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| digest.resize(SHA512_256_DIGEST_LENGTH); |
| SHA512_CTX sha512_256_ctx; |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA512_256_Init(&sha512_256_ctx))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| SHA512_256_Update(&sha512_256_ctx, kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, SHA512_256_Final(digest.data(), &sha512_256_ctx))); |
| EXPECT_EQ(Bytes(kOutput_sha512_256), Bytes(digest)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESECB) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t output[256]; |
| |
| // AES-ECB Encryption KAT for 128 bit key. |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| // AES_ecb_encrypt encrypts (or decrypts) a single, 16 byte block from in to |
| // out. |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kPlaintext[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_ENCRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kAESECBCiphertext), Bytes(output, sizeof(kAESECBCiphertext))); |
| |
| // AES-ECB Decryption KAT for 128 bit key. |
| ASSERT_TRUE(AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kAESECBCiphertext[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_DECRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output, sizeof(kPlaintext))); |
| |
| // AES-ECB Encryption KAT for 192 bit key. |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_192, 8 * sizeof(kAESKey_192), &aes_key) == 0); |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kPlaintext[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_ENCRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kAESECBCiphertext_192), |
| Bytes(output, sizeof(kAESECBCiphertext_192))); |
| |
| // AES-ECB Decryption KAT for 192 bit key. |
| ASSERT_TRUE( |
| AES_set_decrypt_key(kAESKey_192, 8 * sizeof(kAESKey_192), &aes_key) == 0); |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kAESECBCiphertext_192[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_DECRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output, sizeof(kPlaintext))); |
| |
| // AES-ECB Encryption KAT for 256 bit key. |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_256, 8 * sizeof(kAESKey_256), &aes_key) == 0); |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kPlaintext[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_ENCRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kAESECBCiphertext_256), |
| Bytes(output, sizeof(kAESECBCiphertext_256))); |
| |
| // AES-ECB Decryption KAT for 256 bit key. |
| ASSERT_TRUE( |
| AES_set_decrypt_key(kAESKey_256, 8 * sizeof(kAESKey_256), &aes_key) == 0); |
| for (size_t i = 0; i < sizeof(kPlaintext) / AES_BLOCK_SIZE; i++) { |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ecb_encrypt(&kAESECBCiphertext_256[i * AES_BLOCK_SIZE], |
| &output[i * AES_BLOCK_SIZE], &aes_key, AES_DECRYPT)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output, sizeof(kPlaintext))); |
| } |
| |
| TEST(ServiceIndicatorTest, AESCBC) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t aes_iv[sizeof(kAESIV)]; |
| uint8_t output[sizeof(kPlaintext)]; |
| |
| // AES-CBC Encryption KAT for 128 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, AES_ENCRYPT)); |
| EXPECT_EQ(Bytes(kAESCBCCiphertext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CBC Decryption KAT for 128 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE(AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_cbc_encrypt(kAESCBCCiphertext, output, sizeof(kAESCBCCiphertext), |
| &aes_key, aes_iv, AES_DECRYPT)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CBC Encryption KAT for 192 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_192, 8 * sizeof(kAESKey_192), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, AES_ENCRYPT)); |
| EXPECT_EQ(Bytes(kAESCBCCiphertext_192), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CBC Decryption KAT for 192 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_decrypt_key(kAESKey_192, 8 * sizeof(kAESKey_192), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cbc_encrypt(kAESCBCCiphertext_192, output, |
| sizeof(kAESCBCCiphertext_192), &aes_key, aes_iv, |
| AES_DECRYPT)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CBC Encryption KAT for 256 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_256, 8 * sizeof(kAESKey_256), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cbc_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, AES_ENCRYPT)); |
| EXPECT_EQ(Bytes(kAESCBCCiphertext_256), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CBC Decryption KAT for 256 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_decrypt_key(kAESKey_256, 8 * sizeof(kAESKey_256), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cbc_encrypt(kAESCBCCiphertext_256, output, |
| sizeof(kAESCBCCiphertext_256), &aes_key, aes_iv, |
| AES_DECRYPT)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESCTR) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t aes_iv[sizeof(kAESIV)]; |
| uint8_t output[sizeof(kPlaintext)]; |
| unsigned num = 0; |
| uint8_t ecount_buf[AES_BLOCK_SIZE]; |
| |
| // AES-CTR Encryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ctr128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kAESCTRCiphertext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CTR Decryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ctr128_encrypt(kAESCTRCiphertext, output, sizeof(kAESCTRCiphertext), |
| &aes_key, aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CTR Encryption KAT for 192 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_192, 8 * sizeof(kAESKey_192), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ctr128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kAESCTRCiphertext_192), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CTR Decryption KAT for 192 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ctr128_encrypt(kAESCTRCiphertext_192, output, |
| sizeof(kAESCTRCiphertext_192), &aes_key, |
| aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CTR Encryption KAT for 256 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE( |
| AES_set_encrypt_key(kAESKey_256, 8 * sizeof(kAESKey_256), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ctr128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kAESCTRCiphertext_256), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-CTR Decryption KAT for 256 bit key. |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ctr128_encrypt(kAESCTRCiphertext_256, output, |
| sizeof(kAESCTRCiphertext_256), &aes_key, |
| aes_iv, ecount_buf, &num)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESOFB) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t aes_iv[sizeof(kAESIV)]; |
| uint8_t output[sizeof(kPlaintext)]; |
| int num = 0; |
| |
| // AES-OFB Encryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_ofb128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, &num)); |
| EXPECT_EQ(Bytes(kAESOFBCiphertext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| // AES-OFB Decryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_ofb128_encrypt(kAESOFBCiphertext, output, sizeof(kAESOFBCiphertext), |
| &aes_key, aes_iv, &num)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESCFB) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t aes_iv[sizeof(kAESIV)]; |
| uint8_t output[sizeof(kPlaintext)]; |
| int num = 0; |
| |
| // AES-CFB Encryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_cfb128_encrypt(kPlaintext, output, sizeof(kPlaintext), |
| &aes_key, aes_iv, &num, AES_ENCRYPT)); |
| EXPECT_EQ(Bytes(kAESCFBCiphertext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| |
| // AES-CFB Decryption KAT |
| memcpy(aes_iv, kAESIV, sizeof(aes_iv)); |
| CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_cfb128_encrypt(kAESCFBCiphertext, output, sizeof(kAESCFBCiphertext), |
| &aes_key, aes_iv, &num, AES_DECRYPT)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESKW) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t output[sizeof(kPlaintext) + 8]; |
| size_t outlen; |
| |
| // AES-KW Encryption KAT |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| outlen = CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_wrap_key(&aes_key, nullptr, output, kPlaintext, sizeof(kPlaintext))); |
| ASSERT_EQ(outlen, sizeof(kAESKWCiphertext)); |
| EXPECT_EQ(Bytes(kAESKWCiphertext), Bytes(output)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-KW Decryption KAT |
| ASSERT_TRUE(AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| outlen = CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_unwrap_key(&aes_key, nullptr, output, kAESKWCiphertext, |
| sizeof(kAESKWCiphertext))); |
| ASSERT_EQ(outlen, sizeof(kPlaintext)); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output, sizeof(kPlaintext))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, AESKWP) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| AES_KEY aes_key; |
| uint8_t output[sizeof(kPlaintext) + 15]; |
| size_t outlen; |
| |
| // AES-KWP Encryption KAT |
| ASSERT_TRUE(AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, AES_wrap_key_padded(&aes_key, output, &outlen, sizeof(output), |
| kPlaintext, sizeof(kPlaintext)))); |
| EXPECT_EQ(Bytes(kAESKWPCiphertext), Bytes(output, outlen)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // AES-KWP Decryption KAT |
| ASSERT_TRUE(AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) == 0); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| AES_unwrap_key_padded(&aes_key, output, &outlen, sizeof(output), |
| kAESKWPCiphertext, sizeof(kAESKWPCiphertext)))); |
| EXPECT_EQ(Bytes(kPlaintext), Bytes(output, outlen)); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, FFDH) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| |
| // |DH_compute_key_padded| should be a non-approved service. |
| bssl::UniquePtr<DH> dh(GetDH()); |
| uint8_t dh_out[sizeof(kDHOutput)]; |
| ASSERT_EQ(DH_size(dh.get()), static_cast<int>(sizeof(dh_out))); |
| ASSERT_EQ(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, DH_compute_key_padded( |
| dh_out, DH_get0_priv_key(dh.get()), dh.get())), |
| static_cast<int>(sizeof(dh_out))); |
| EXPECT_EQ(Bytes(kDHOutput), Bytes(dh_out)); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| } |
| |
| TEST(ServiceIndicatorTest, DRBG) { |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| CTR_DRBG_STATE drbg; |
| uint8_t output[sizeof(kDRBGOutput)]; |
| |
| // Test running the DRBG interfaces and check |CTR_DRBG_generate| for approval |
| // at the end since it indicates a service is being done. |CTR_DRBG_init| and |
| // |CTR_DRBG_reseed| should not be approved, because the functions do not |
| // indicate that a service has been fully completed yet. |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CTR_DRBG_init(&drbg, kDRBGEntropy, kDRBGPersonalization, |
| sizeof(kDRBGPersonalization)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CTR_DRBG_generate(&drbg, output, sizeof(kDRBGOutput), kDRBGAD, |
| sizeof(kDRBGAD)))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| EXPECT_EQ(Bytes(kDRBGOutput), Bytes(output)); |
| |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| CTR_DRBG_reseed(&drbg, kDRBGEntropy2, kDRBGAD, sizeof(kDRBGAD)))); |
| EXPECT_EQ(approved, FIPSStatus::NOT_APPROVED); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, CTR_DRBG_generate(&drbg, output, sizeof(kDRBGReseedOutput), |
| kDRBGAD, sizeof(kDRBGAD)))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| EXPECT_EQ(Bytes(kDRBGReseedOutput), Bytes(output)); |
| |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, RAND_bytes(output, sizeof(output)))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| #else // !BORINGSSL_FIPS |
| |
| // Service indicator calls should not be used in non-FIPS builds. However, if |
| // used, the macro |CALL_SERVICE_AND_CHECK_APPROVED| will return |
| // |FIPSStatus::APPROVED|, but the direct calls to |
| // |FIPS_service_indicator_xxx| will not indicate an approved state. |
| TEST(ServiceIndicatorTest, BasicTest) { |
| // Reset and check the initial state and counter. |
| FIPSStatus approved = FIPSStatus::NOT_APPROVED; |
| uint64_t before = FIPS_service_indicator_before_call(); |
| ASSERT_EQ(before, (uint64_t)0); |
| |
| // Call an approved service. |
| bssl::ScopedEVP_AEAD_CTX aead_ctx; |
| uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH] = {0}; |
| uint8_t output[256]; |
| size_t out_len; |
| ASSERT_TRUE(EVP_AEAD_CTX_init(aead_ctx.get(), |
| EVP_aead_aes_128_gcm_randnonce(), kAESKey, |
| sizeof(kAESKey), 0, nullptr)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, EVP_AEAD_CTX_seal(aead_ctx.get(), output, &out_len, |
| sizeof(output), nullptr, 0, kPlaintext, |
| sizeof(kPlaintext), nullptr, 0))); |
| // Macro should return true, to ensure FIPS/non-FIPS compatibility. |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| |
| // Call a non-approved service. |
| ASSERT_TRUE(EVP_AEAD_CTX_init(aead_ctx.get(), EVP_aead_aes_128_gcm(), kAESKey, |
| sizeof(kAESKey), 0, nullptr)); |
| ASSERT_TRUE(CALL_SERVICE_AND_CHECK_APPROVED( |
| approved, |
| EVP_AEAD_CTX_seal(aead_ctx.get(), output, &out_len, sizeof(output), nonce, |
| EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()), |
| kPlaintext, sizeof(kPlaintext), nullptr, 0))); |
| EXPECT_EQ(approved, FIPSStatus::APPROVED); |
| } |
| |
| #endif // BORINGSSL_FIPS |