/* 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_EQ(ERR_GET_REASON(ERR_get_error()), 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, BN_num_bits(rsa->n));
  }

  // 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 test cases that are approved.
    {1024, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::APPROVED},
    {1024, &EVP_sha256, false, FIPSStatus::NOT_APPROVED, FIPSStatus::APPROVED},
    {1024, &EVP_sha512, false, FIPSStatus::NOT_APPROVED, FIPSStatus::APPROVED},
    {1024, &EVP_sha1, true, FIPSStatus::NOT_APPROVED, FIPSStatus::APPROVED},
    {1024, &EVP_sha256, true, FIPSStatus::NOT_APPROVED, FIPSStatus::APPROVED},
    // PSS with hashLen == saltLen is not possible for 1024-bit modulus and
    // SHA-512.

    {2048, &EVP_sha1, false, FIPSStatus::NOT_APPROVED, FIPSStatus::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::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::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::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::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::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 signature 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::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::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::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::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;

  bssl::UniquePtr<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.get()));

  // 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;

  bssl::UniquePtr<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.get()));

  // 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)));

  bssl::UniquePtr<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.get()));

  // 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;

  bssl::UniquePtr<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.get()));
  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.get()));
  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
