blob: a3f06eb0520ab8e2e647bdc8a84754885543670f [file] [log] [blame]
/* 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(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