// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <gtest/gtest.h>
#include <array>
#include <ctime>

#include "openssl/ocsp.h"
#include "openssl/pem.h"

#include "../internal.h"
#include "../test/test_util.h"
#include "internal.h"

static const time_t invalid_before_ocsp_update_time = 1621988613;
static const time_t valid_after_ocsp_update_time = 1621988615;
static const time_t valid_before_ocsp_expire_time = 1937348613;
static const time_t invalid_after_ocsp_expire_time = 1937348615;

static const time_t invalid_before_ocsp_update_time_sha256 = 1622145762;
static const time_t valid_after_ocsp_update_time_sha256 = 1622145764;
static const time_t valid_before_ocsp_expire_time_sha256 = 1937505762;
static const time_t invalid_after_ocsp_expire_time_sha256 = 1937505764;

#define OCSP_VERIFYSTATUS_SUCCESS 1
#define OCSP_VERIFYSTATUS_ERROR 0
#define OCSP_VERIFYSTATUS_FATALERROR -1

#define OCSP_RESPFINDSTATUS_SUCCESS 1
#define OCSP_RESPFINDSTATUS_ERROR 0
#define OCSP_RESPFINDSTATUS_UNDEFINED -1

#define OCSP_REQUEST_PARSE_SUCCESS 1
#define OCSP_REQUEST_PARSE_ERROR 0

#define OCSP_HTTP_PARSE_SUCCESS 1
#define OCSP_HTTP_PARSE_ERROR 0

#define OCSP_SIGN_SUCCESS 1
#define OCSP_SIGN_ERROR 0

#define OCSP_URL_PARSE_SUCCESS 1
#define OCSP_URL_PARSE_ERROR 0

std::string GetTestData(const char *path);

static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) {
  int temp_length = 0;
  size_t total_length = 0;
  EVP_ENCODE_CTX ctx;
  EVP_DecodeInit(&ctx);
  out->resize(strlen(in));

  int decode_update_result = EVP_DecodeUpdate(&ctx, out->data(), &temp_length,
                                              (const uint8_t *)in, strlen(in));
  if (decode_update_result != 1 && decode_update_result != 0) {
    fprintf(stderr, "EVP_DecodeUpdate failed\n");
    return false;
  }
  total_length += temp_length;
  temp_length = 0;

  if (1 != EVP_DecodeFinal(&ctx, &out->data()[total_length], &temp_length)) {
    fprintf(stderr, "EVP_DecodeFinal failed\n");
    return false;
  }
  total_length += temp_length;
  out->resize(total_length);
  return true;
}

static bssl::UniquePtr<EC_KEY> ECDSAFromPEM(const char *pem) {
  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
  return bssl::UniquePtr<EC_KEY>(
      PEM_read_bio_ECPrivateKey(bio.get(), nullptr, nullptr, nullptr));
}

static bssl::UniquePtr<STACK_OF(X509)> CertChainFromPEM(const char *pem) {
  bssl::UniquePtr<STACK_OF(X509)> stack(sk_X509_new_null());
  if (!stack) {
    return nullptr;
  }

  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
  for (;;) {
    bssl::UniquePtr<X509> cert = bssl::UniquePtr<X509>(
        PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
    if (cert == nullptr) {
      break;
    }
    if (!bssl::PushToStack(stack.get(), bssl::UpRef(cert.get()))) {
      return nullptr;
    }
  }
  return stack;
}

static bssl::UniquePtr<OCSP_RESPONSE> LoadOCSP_RESPONSE(
    bssl::Span<const uint8_t> der) {
  const uint8_t *ptr = der.data();
  return bssl::UniquePtr<OCSP_RESPONSE>(
      d2i_OCSP_RESPONSE(nullptr, &ptr, der.size()));
}

static bssl::UniquePtr<OCSP_REQUEST> LoadOCSP_REQUEST(
    bssl::Span<const uint8_t> der) {
  const uint8_t *ptr = der.data();
  return bssl::UniquePtr<OCSP_REQUEST>(
      d2i_OCSP_REQUEST(nullptr, &ptr, der.size()));
}

// Load a generic |OCSP_CERTID| for testing.
static OCSP_CERTID *LoadTestOCSP_CERTID() {
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  bssl::UniquePtr<X509> server_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/rsa_cert.pem").c_str())
          .c_str()));
  return OCSP_cert_to_id(nullptr, ca_cert.get(), server_cert.get());
}

static void ExtractAndVerifyBasicOCSP(
    bssl::Span<const uint8_t> der, const std::string ca_cert_file,
    const std::string server_cert_file, int expected_ocsp_verify_status,
    bssl::UniquePtr<OCSP_BASICRESP> *basic_response,
    bssl::UniquePtr<STACK_OF(X509)> *server_cert_chain) {
  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response;
  ocsp_response = LoadOCSP_RESPONSE(der);
  ASSERT_TRUE(ocsp_response);

  int ret = OCSP_response_status(ocsp_response.get());
  if (ret != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
    return;
  }

  *basic_response = bssl::UniquePtr<OCSP_BASICRESP>(
      OCSP_response_get1_basic(ocsp_response.get()));
  ASSERT_TRUE(*basic_response);

  // Set up trust store and certificate chain.
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(
          std::string("crypto/ocsp/test/aws/" + ca_cert_file + ".pem").c_str())
          .c_str()));
  bssl::UniquePtr<X509> server_cert(
      CertFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                          server_cert_file + ".pem")
                                  .c_str())
                      .c_str()));

  bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
  X509_STORE_add_cert(trust_store.get(), ca_cert.get());
  *server_cert_chain = CertsToStack({server_cert.get(), ca_cert.get()});
  ASSERT_TRUE(*server_cert_chain);

  // Verifies the OCSP responder's signature on the OCSP response data.
  const int ocsp_verify_err = OCSP_basic_verify(
      basic_response->get(), server_cert_chain->get(), trust_store.get(), 0);
  ASSERT_EQ(expected_ocsp_verify_status, ocsp_verify_err);
}

static void CheckOCSP_CERTSTATUS(
    bssl::UniquePtr<OCSP_BASICRESP> *basic_response,
    bssl::UniquePtr<STACK_OF(X509)> *server_cert_chain, const EVP_MD *dgst,
    int expected_resp_find_status, int *status, ASN1_GENERALIZEDTIME **thisupd,
    ASN1_GENERALIZEDTIME **nextupd) {
  X509 *subject = sk_X509_value(server_cert_chain->get(), 0);
  X509 *issuer = sk_X509_value(server_cert_chain->get(), 1);
  // Convert issuer certificate to |OCSP_CERTID|.
  bssl::UniquePtr<OCSP_CERTID> cert_id =
      bssl::UniquePtr<OCSP_CERTID>(OCSP_cert_to_id(dgst, subject, issuer));
  ASSERT_TRUE(cert_id);

  int reason = 0;
  ASN1_GENERALIZEDTIME *revtime;
  // Checks revocation status of the response.
  const int ocsp_resp_find_status_res =
      OCSP_resp_find_status(basic_response->get(), cert_id.get(), status,
                            &reason, &revtime, thisupd, nextupd);
  ASSERT_EQ(expected_resp_find_status, ocsp_resp_find_status_res);
}

// Test data below are taken from s2n's ocsp test files:
// https://github.com/aws/s2n-tls/blob/main/tests/pems/ocsp
// OCSP testing methods were taken from s2n's validation tests:
// https://github.com/aws/s2n-tls/blob/main/tests/unit/s2n_x509_validator_test.c
struct OCSPAWSTestVector {
  const char *ocsp_response;
  const char *cafile;
  const char *server_cert;
  const EVP_MD *dgst;
  int expected_ocsp_verify_status;
  int expected_ocsp_resp_find_status;
  int expected_ocsp_cert_status;
  const char *expected_ocsp_cert_status_string;
};

static const OCSPAWSTestVector nTestVectors[] = {
    // === SHA1 OCSP RESPONSES ===
    // Test valid OCSP response signed by an OCSP responder.
    {"ocsp_response", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_GOOD, "good"},
    // Test against same good OCSP response, but checking behavior of not
    // specifying hash algorithm used for |OCSP_cert_to_id| this time (should
    // default to sha1). When |*dgst| is set to NULL, the default hash algorithm
    // should automatically be set to sha1. The revocation status check of the
    // response should work if hash algorithm of |cert_id| has been set to sha1
    // successfully.
    {"ocsp_response", "ca_cert", "rsa_cert", nullptr, OCSP_VERIFYSTATUS_SUCCESS,
     OCSP_RESPFINDSTATUS_SUCCESS, V_OCSP_CERTSTATUS_GOOD, "good"},
    // Test valid OCSP response directly signed by the CA certificate.
    {"ocsp_response_ca_signed", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_GOOD, "good"},
    // Test OCSP response status is revoked.
    {"ocsp_response_revoked", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_REVOKED, "revoked"},
    // Test OCSP response status is unknown.
    {"ocsp_response_unknown", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_UNKNOWN, "unknown"},
    // for the requested certificate. (So this would be a completely valid
    // response to a different OCSP request for the other certificate.)
    {"ocsp_response", "ca_cert", "ecdsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_ERROR, -1, nullptr},
    // Test OCSP response where the requested certificate was signed by the OCSP
    // responder, but signed by the wrong requested OCSP responder key
    // certificate.
    // However, this incorrect OCSP responder certificate may be a valid OCSP
    // responder for some other case and also chains to a trusted root.
    {"ocsp_response_wrong_signer", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_ERROR, OCSP_RESPFINDSTATUS_UNDEFINED, -1, nullptr},
    // Test OCSP response where the requested certificate was signed by an OCSP
    // responder with an expired certificate.
    // However, this incorrect OCSP responder certificate may be a valid OCSP
    // responder for some other case and also chains to a trusted root.
    {"ocsp_response_expired_signer", "ca_cert", "rsa_cert", EVP_sha1(),
     OCSP_VERIFYSTATUS_ERROR, OCSP_RESPFINDSTATUS_UNDEFINED, -1, nullptr},

    // === SHA256 OCSP RESPONSES ===
    // Test valid OCSP response signed by an OCSP responder.
    {"ocsp_response_sha256", "ca_cert", "rsa_cert", EVP_sha256(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_GOOD, "good"},
    // Test a SHA-256 revoked OCSP response status.
    {"ocsp_response_revoked_sha256", "ca_cert", "rsa_cert", EVP_sha256(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_REVOKED, "revoked"},
    // Test a SHA-256 unknown OCSP response status.
    {"ocsp_response_unknown_sha256", "ca_cert", "rsa_cert", EVP_sha256(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_SUCCESS,
     V_OCSP_CERTSTATUS_UNKNOWN, "unknown"},
    // Test a SHA-256 OCSP response signed by the correct responder certificate,
    // but not for the requested certificate. (So this would be a completely
    // valid response to a different OCSP request for the other certificate.)
    {"ocsp_response_sha256", "ca_cert", "ecdsa_cert", EVP_sha256(),
     OCSP_VERIFYSTATUS_SUCCESS, OCSP_RESPFINDSTATUS_ERROR, -1, nullptr},
    // Test a SHA-256 OCSP response signed by the wrong responder certificate,
    // but the requested certificate was signed. (however this incorrect OCSP
    // responder certificate is a valid OCSP responder for some other case and
    // chains to a trusted root). Thus, this response is not valid for any
    // request.
    {"ocsp_response_wrong_signer_sha256", "ca_cert", "rsa_cert", EVP_sha256(),
     OCSP_VERIFYSTATUS_ERROR, OCSP_RESPFINDSTATUS_UNDEFINED, -1, nullptr},
};

class OCSPTestAWS : public testing::TestWithParam<OCSPAWSTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPTestAWS, testing::ValuesIn(nTestVectors));

TEST_P(OCSPTestAWS, VerifyOCSPResponse) {
  const OCSPAWSTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_response) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_reponse_data(data.begin(), data.end());

  // OCSP response parsing and verification step.
  bssl::UniquePtr<OCSP_BASICRESP> basic_response;
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain;
  ExtractAndVerifyBasicOCSP(ocsp_reponse_data, t.cafile, t.server_cert,
                            t.expected_ocsp_verify_status, &basic_response,
                            &server_cert_chain);

  // If OCSP basic verify is successful, we check the OCSP response status.
  if (t.expected_ocsp_verify_status == OCSP_VERIFYSTATUS_SUCCESS) {
    int status = 0;
    ASN1_GENERALIZEDTIME *thisupd, *nextupd;
    CheckOCSP_CERTSTATUS(&basic_response, &server_cert_chain, t.dgst,
                         t.expected_ocsp_resp_find_status, &status, &thisupd,
                         &nextupd);
    // If OCSP response status retrieving is successful, we check if the cert
    // status of the OCSP response is correct.
    if (t.expected_ocsp_resp_find_status == OCSP_RESPFINDSTATUS_SUCCESS) {
      ASSERT_EQ(t.expected_ocsp_cert_status, status);
      ASSERT_EQ(std::string(t.expected_ocsp_cert_status_string),
                std::string(OCSP_cert_status_str(status)));
    }
  }
}

struct OCSPResponseStatusTestVector {
  const char *ocsp_response;
  int expected_ocsp_status;
  const char *expected_ocsp_status_string;
};

static const OCSPResponseStatusTestVector respTestVectors[] = {
    // === Invalid OCSP response requests sent back an OCSP responder ===
    // https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1
    // OCSPResponseStatus: successful
    {"ocsp_response", OCSP_RESPONSE_STATUS_SUCCESSFUL, "successful"},
    // OCSPResponseStatus: malformedRequest
    {"ocsp_response_malformedrequest", OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
     "malformedrequest"},
    // OCSPResponseStatus: internalError
    {"ocsp_response_internalerror", OCSP_RESPONSE_STATUS_INTERNALERROR,
     "internalerror"},
    // OCSPResponseStatus: tryLater
    {"ocsp_response_trylater", OCSP_RESPONSE_STATUS_TRYLATER, "trylater"},
    // OCSPResponseStatus: sigRequired
    {"ocsp_response_sigrequired", OCSP_RESPONSE_STATUS_SIGREQUIRED,
     "sigrequired"},
    // OCSPResponseStatus: unauthorized
    {"ocsp_response_unauthorized", OCSP_RESPONSE_STATUS_UNAUTHORIZED,
     "unauthorized"},
};

class OCSPResponseStatusTest
    : public testing::TestWithParam<OCSPResponseStatusTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPResponseStatusTest,
                         testing::ValuesIn(respTestVectors));

TEST_P(OCSPResponseStatusTest, OCSPResponseStatus) {
  const OCSPResponseStatusTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_response) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_reponse_data(data.begin(), data.end());

  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response(
      LoadOCSP_RESPONSE(ocsp_reponse_data));
  ASSERT_TRUE(ocsp_response);

  int ret = OCSP_response_status(ocsp_response.get());
  ASSERT_EQ(t.expected_ocsp_status, ret);
  ASSERT_EQ(std::string(t.expected_ocsp_status_string),
            std::string(OCSP_response_status_str(ret)));
}


// === Specific test cases ===

// Test valid OCSP response signed by an OCSP responder along with check for
// correct time field parsing.
TEST(OCSPTest, TestGoodOCSP) {
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_reponse_data(data.begin(), data.end());

  bssl::UniquePtr<OCSP_BASICRESP> basic_response;
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain;
  ExtractAndVerifyBasicOCSP(ocsp_reponse_data, "ca_cert", "rsa_cert",
                            OCSP_VERIFYSTATUS_SUCCESS, &basic_response,
                            &server_cert_chain);

  int status = 0;
  ASN1_GENERALIZEDTIME *thisupd, *nextupd;
  CheckOCSP_CERTSTATUS(&basic_response, &server_cert_chain, EVP_sha1(),
                       OCSP_RESPFINDSTATUS_SUCCESS, &status, &thisupd,
                       &nextupd);
  ASSERT_EQ(V_OCSP_CERTSTATUS_GOOD, status);

  // There is 1 |OCSP_SINGLERESP| in the |basic_response|.
  EXPECT_EQ(OCSP_resp_count(basic_response.get()), 1);

  // If OCSP response is verifiable and all good, an OCSP client should check
  // time fields to see if the response is still valid.

  // Check before OCSP was last updated connection timestamp
  time_t connection_time = invalid_before_ocsp_update_time;
  ASSERT_EQ(1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check valid connection timestamp right after OCSP response was validated.
  connection_time = valid_after_ocsp_update_time;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check valid connection timestamp right before OCSP response expires.
  connection_time = valid_before_ocsp_expire_time;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check expired connection timestamp
  connection_time = invalid_after_ocsp_expire_time;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(-1, X509_cmp_time(nextupd, &connection_time));

  // Check that |OCSP_check_validity| sees that |thisupd| is more than 100
  // seconds in the past, and disallows it.
  EXPECT_FALSE(OCSP_check_validity(thisupd, nextupd, 0, 100));
  uint32_t err = ERR_get_error();
  EXPECT_EQ(OCSP_R_STATUS_TOO_OLD, ERR_GET_REASON(err));

  // We offset "nsec" in |OCSP_check_validity| with a negative timestamp
  // equal to the current time. We offset this larger timestamp on purpose to
  // check if |OCSP_check_validity| can properly reject improper timestamps.
  // This will cause the function to fail in two places, once when checking
  // if "(current_time + nsec) > thisupd [Status Not Yet Valid]", and a second
  // time when checking if "nextupd > (current_time - nsec) [Status Expired]".
  EXPECT_FALSE(OCSP_check_validity(thisupd, nextupd, -time(nullptr), -1));
  err = ERR_get_error();
  EXPECT_EQ(OCSP_R_STATUS_NOT_YET_VALID, ERR_GET_REASON(err));
  err = ERR_get_error();
  EXPECT_EQ(OCSP_R_STATUS_EXPIRED, ERR_GET_REASON(err));
  ERR_clear_error();

  // Check that "NEXTUPDATE_BEFORE_THISUPDATE" is properly detected. We have to
  // use |valid_after_ocsp_update_time| instead of |nextupd| to avoid a
  // ticking time-bomb test. |nextupd| will throw an additional
  // "STATUS_NOT_YET_VALID" error until it is a valid timestamp.
  bssl::UniquePtr<ASN1_GENERALIZEDTIME> after_thisupd(
      ASN1_GENERALIZEDTIME_new());
  ASN1_GENERALIZEDTIME_set(after_thisupd.get(), valid_after_ocsp_update_time);
  EXPECT_FALSE(OCSP_check_validity(after_thisupd.get(), thisupd, 0, -1));
  err = ERR_get_error();
  EXPECT_EQ(OCSP_R_STATUS_EXPIRED, ERR_GET_REASON(err));
  err = ERR_get_error();
  EXPECT_EQ(OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE, ERR_GET_REASON(err));

  // We set |nextupd| to NULL on purpose to avoid another ticking time-bomb
  // expiration in our tests. We only check if |thisupd| is a valid timestamp
  // in the past.
  EXPECT_TRUE(OCSP_check_validity(thisupd, nullptr, 0, -1));
}

// Test valid OCSP response, but the data itself is untrusted.
TEST(OCSPTest, TestUntrustedDataOCSP) {
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_reponse_data(data.begin(), data.end());

  // Mess up a byte right in the middle of the cert.
  ocsp_reponse_data[800] = ocsp_reponse_data[800] + 1;

  bssl::UniquePtr<OCSP_BASICRESP> basic_response;
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain;
  ExtractAndVerifyBasicOCSP(ocsp_reponse_data, "ca_cert", "rsa_cert",
                            OCSP_VERIFYSTATUS_ERROR, &basic_response,
                            &server_cert_chain);
}


// Test valid OCSP response hashed with sha256 along with check for correct time
// field parsing.
TEST(OCSPTest, TestGoodOCSP_SHA256) {
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response_sha256.der").c_str());
  std::vector<uint8_t> ocsp_reponse_data(data.begin(), data.end());

  bssl::UniquePtr<OCSP_BASICRESP> basic_response;
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain;
  ExtractAndVerifyBasicOCSP(ocsp_reponse_data, "ca_cert", "rsa_cert",
                            OCSP_VERIFYSTATUS_SUCCESS, &basic_response,
                            &server_cert_chain);

  int status = 0;
  ASN1_GENERALIZEDTIME *thisupd, *nextupd;
  CheckOCSP_CERTSTATUS(&basic_response, &server_cert_chain, EVP_sha256(),
                       OCSP_RESPFINDSTATUS_SUCCESS, &status, &thisupd,
                       &nextupd);
  ASSERT_EQ(V_OCSP_CERTSTATUS_GOOD, status);

  // There is 1 |OCSP_SINGLERESP| in the |basic_response|.
  EXPECT_EQ(OCSP_resp_count(basic_response.get()), 1);

  // If OCSP response is verifiable and all good, an OCSP client should check
  // time fields to see if the response is still valid.

  // Check before OCSP was last updated connection timestamp.
  time_t connection_time = invalid_before_ocsp_update_time_sha256;
  ASSERT_EQ(1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check valid connection timestamp right after OCSP response was validated.
  connection_time = valid_after_ocsp_update_time_sha256;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check valid connection timestamp right before OCSP response expires.
  connection_time = valid_before_ocsp_expire_time_sha256;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(1, X509_cmp_time(nextupd, &connection_time));

  // Check expired connection timestamp.
  connection_time = invalid_after_ocsp_expire_time_sha256;
  ASSERT_EQ(-1, X509_cmp_time(thisupd, &connection_time));
  ASSERT_EQ(-1, X509_cmp_time(nextupd, &connection_time));
}

struct OCSPResponseVerifyFlagTestVector {
  const char *ocsp_response;
  unsigned long ocsp_verify_flag;
  bool include_expired_signer_cert;
  int expected_ocsp_verify_status;
};

static const OCSPResponseVerifyFlagTestVector
    OCSPResponseVerifyFlagTestVectors[] = {
        {"ocsp_response", OCSP_NOINTERN, false, OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_response", OCSP_NOCHAIN, false, OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_response_expired_signer", OCSP_NOVERIFY, false,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_response_wrong_signer", OCSP_NOVERIFY, false,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_response", OCSP_NOEXPLICIT, false, OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_response", OCSP_TRUSTOTHER, false, OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_response_expired_signer", OCSP_TRUSTOTHER, false,
         OCSP_VERIFYSTATUS_ERROR},
        // |OCSP_TRUSTOTHER| sets |OCSP_NOVERIFY| if the signer cert is included
        // within the parameters.
        {"ocsp_response_expired_signer", OCSP_TRUSTOTHER, true,
         OCSP_VERIFYSTATUS_SUCCESS},
};

class OCSPVerifyFlagTest
    : public testing::TestWithParam<OCSPResponseVerifyFlagTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPVerifyFlagTest,
                         testing::ValuesIn(OCSPResponseVerifyFlagTestVectors));

TEST_P(OCSPVerifyFlagTest, OCSPVerifyFlagTest) {
  const OCSPResponseVerifyFlagTestVector &t = GetParam();

  std::string respData =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_response) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());

  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response =
      LoadOCSP_RESPONSE(ocsp_response_data);
  ASSERT_TRUE(ocsp_response);

  int ret = OCSP_response_status(ocsp_response.get());
  ASSERT_EQ(OCSP_RESPONSE_STATUS_SUCCESSFUL, ret);

  bssl::UniquePtr<OCSP_BASICRESP> basic_response =
      bssl::UniquePtr<OCSP_BASICRESP>(
          OCSP_response_get1_basic(ocsp_response.get()));
  ASSERT_TRUE(basic_response);

  // Set up trust store and certificate chain.
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  bssl::UniquePtr<X509> server_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/rsa_cert.pem").c_str())
          .c_str()));

  bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
  X509_STORE_add_cert(trust_store.get(), ca_cert.get());
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain(
      CertsToStack({server_cert.get(), ca_cert.get()}));
  ASSERT_TRUE(server_cert_chain);
  if (t.include_expired_signer_cert) {
    bssl::UniquePtr<X509> signing_cert(CertFromPEM(
        GetTestData(
            std::string("crypto/ocsp/test/aws/ocsp_expired_cert.pem").c_str())
            .c_str()));
    ASSERT_TRUE(sk_X509_push(server_cert_chain.get(), signing_cert.get()));
    X509_up_ref(signing_cert.get());
  }

  // Does basic verification on OCSP response.
  const int ocsp_verify_status =
      OCSP_basic_verify(basic_response.get(), server_cert_chain.get(),
                        trust_store.get(), t.ocsp_verify_flag);
  ASSERT_EQ(t.expected_ocsp_verify_status, ocsp_verify_status);
}

struct OCSPRequestVerifyFlagTestVector {
  const char *ocsp_request;
  unsigned long ocsp_verify_flag;
  bool include_expired_signer_cert;
  int expected_ocsp_verify_status;
};

static const OCSPRequestVerifyFlagTestVector
    OCSPRequestVerifyFlagTestVectors[] = {
        // Although signatures for OCSP requests are optional according to the
        // RFC, OCSP requests with absent signatures can't be verified.
        {"ocsp_request", 0, false, OCSP_VERIFYSTATUS_ERROR},
        // ocsp_request_signed's certificate is embedded in the request.
        {"ocsp_request_signed", 0, false, OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_signed", OCSP_NOINTERN, false, OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_signed", OCSP_NOCHAIN, false, OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_wrong_signer", 0, false, OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_wrong_signer", OCSP_NOCHAIN, false,
         OCSP_VERIFYSTATUS_ERROR},
        // OCSP request verification will fail if the cert can't be found or
        // when working with an expired cert.
        {"ocsp_request_expired_signer", 0, true, OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_expired_signer", 0, false, OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_expired_signer_no_certs", 0, true,
         OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_expired_signer_no_certs", 0, false,
         OCSP_VERIFYSTATUS_ERROR},
        // |OCSP_NOVERIFY| skips certificate verification, but can't succeed if
        // the signer cert isn't found.
        {"ocsp_request_expired_signer", OCSP_NOVERIFY, true,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_expired_signer", OCSP_NOVERIFY, false,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_expired_signer_no_certs", OCSP_NOVERIFY, true,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_expired_signer_no_certs", OCSP_NOVERIFY, false,
         OCSP_VERIFYSTATUS_ERROR},
        // |OCSP_TRUSTOTHER| sets |OCSP_NOVERIFY| if the signer cert is included
        // within the parameters.
        {"ocsp_request_expired_signer", OCSP_TRUSTOTHER, true,
         OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_expired_signer", OCSP_TRUSTOTHER, false,
         OCSP_VERIFYSTATUS_ERROR},
        {"ocsp_request_expired_signer_no_certs", OCSP_TRUSTOTHER, true,
         OCSP_VERIFYSTATUS_SUCCESS},
        {"ocsp_request_expired_signer_no_certs", OCSP_TRUSTOTHER, false,
         OCSP_VERIFYSTATUS_ERROR},
};

class OCSPRequestVerifyFlagTest
    : public testing::TestWithParam<OCSPRequestVerifyFlagTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPRequestVerifyFlagTest,
                         testing::ValuesIn(OCSPRequestVerifyFlagTestVectors));

TEST_P(OCSPRequestVerifyFlagTest, OCSPVerifyFlagTest) {
  const OCSPRequestVerifyFlagTestVector &t = GetParam();

  std::string respData =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_request) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_request_data(respData.begin(), respData.end());
  bssl::UniquePtr<OCSP_REQUEST> ocsp_request =
      LoadOCSP_REQUEST(ocsp_request_data);
  ASSERT_TRUE(ocsp_request);

  // Set up trust store and certificate chain.
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));

  bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
  X509_STORE_add_cert(trust_store.get(), ca_cert.get());
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain(sk_X509_new_null());
  ASSERT_TRUE(server_cert_chain);
  if (t.include_expired_signer_cert) {
    bssl::UniquePtr<X509> signing_cert(CertFromPEM(
        GetTestData(
            std::string("crypto/ocsp/test/aws/ocsp_expired_cert.pem").c_str())
            .c_str()));
    ASSERT_TRUE(sk_X509_push(server_cert_chain.get(), signing_cert.get()));
    X509_up_ref(signing_cert.get());
  }

  // Does basic verification on OCSP request.
  const int ocsp_verify_status =
      OCSP_request_verify(ocsp_request.get(), server_cert_chain.get(),
                          trust_store.get(), t.ocsp_verify_flag);
  ASSERT_EQ(t.expected_ocsp_verify_status, ocsp_verify_status);
}

TEST(OCSPTest, GetInfo) {
  // Create a sample |OCSP_CERTID| structure.
  bssl::UniquePtr<OCSP_CERTID> cert_id(LoadTestOCSP_CERTID());
  ASSERT_TRUE(cert_id);

  ASN1_OCTET_STRING *nameHash = nullptr;
  ASN1_OBJECT *algo = nullptr;
  ASN1_OCTET_STRING *keyHash = nullptr;
  ASN1_INTEGER *serial = nullptr;
  EXPECT_TRUE(
      OCSP_id_get0_info(&nameHash, &algo, &keyHash, &serial, cert_id.get()));
  EXPECT_EQ(nameHash, cert_id.get()->issuerNameHash);
  EXPECT_EQ(algo, cert_id.get()->hashAlgorithm->algorithm);
  EXPECT_EQ(keyHash, cert_id.get()->issuerKeyHash);
  EXPECT_EQ(serial, cert_id.get()->serialNumber);
}

TEST(OCSPTest, BasicAddCert) {
  std::string respData = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse =
      LoadOCSP_RESPONSE(ocsp_response_data);
  bssl::UniquePtr<OCSP_BASICRESP> basicResponse(
      OCSP_response_get1_basic(ocspResponse.get()));
  ASSERT_TRUE(basicResponse);

  bssl::UniquePtr<X509> cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));

  EXPECT_TRUE(OCSP_basic_add1_cert(basicResponse.get(), cert.get()));
  // Check that the cert is the same as the one added to the stack.
  EXPECT_EQ(sk_X509_value(basicResponse.get()->certs,
                          sk_X509_num(basicResponse.get()->certs) - 1),
            cert.get());
}

TEST(OCSPTest, BasicAddStatus) {
  bssl::UniquePtr<OCSP_BASICRESP> basicResponse(OCSP_BASICRESP_new());
  ASSERT_TRUE(basicResponse);
  bssl::UniquePtr<OCSP_CERTID> certId(LoadTestOCSP_CERTID());
  ASSERT_TRUE(certId);

  bssl::UniquePtr<ASN1_TIME> revoked_time(ASN1_TIME_new()),
      this_update(ASN1_TIME_new()), next_update(ASN1_TIME_new());
  ASSERT_TRUE(
      ASN1_TIME_set(revoked_time.get(), invalid_before_ocsp_update_time));
  ASSERT_TRUE(ASN1_TIME_set(this_update.get(), valid_after_ocsp_update_time));
  ASSERT_TRUE(ASN1_TIME_set(next_update.get(), valid_before_ocsp_expire_time));

  EXPECT_TRUE(OCSP_basic_add1_status(basicResponse.get(), certId.get(),
                                     V_OCSP_CERTSTATUS_GOOD, 0, nullptr,
                                     this_update.get(), next_update.get()));

  // |revoked_reason| and |revoked_time| are ignored if |status| is
  // |V_OCSP_CERTSTATUS_GOOD|, but will still succeed.
  EXPECT_TRUE(OCSP_basic_add1_status(
      basicResponse.get(), certId.get(), V_OCSP_CERTSTATUS_GOOD,
      OCSP_REVOKED_STATUS_CACOMPROMISE, revoked_time.get(), this_update.get(),
      next_update.get()));

  EXPECT_TRUE(OCSP_basic_add1_status(basicResponse.get(), certId.get(),
                                     V_OCSP_CERTSTATUS_UNKNOWN, 0, nullptr,
                                     this_update.get(), next_update.get()));

  // |revoked_reason| and |revoked_time| are ignored if |status| is
  // |V_OCSP_CERTSTATUS_UNKNOWN|, but will still succeed.
  EXPECT_TRUE(OCSP_basic_add1_status(
      basicResponse.get(), certId.get(), V_OCSP_CERTSTATUS_UNKNOWN,
      OCSP_REVOKED_STATUS_SUPERSEDED, revoked_time.get(), this_update.get(),
      next_update.get()));

  // Try setting a revoked response without an |ASN1_TIME|.
  EXPECT_FALSE(OCSP_basic_add1_status(basicResponse.get(), certId.get(),
                                      V_OCSP_CERTSTATUS_REVOKED, 0, nullptr,
                                      this_update.get(), nullptr));

  // Try setting a revoked response with an invalid revoked reason number.
  EXPECT_FALSE(OCSP_basic_add1_status(
      basicResponse.get(), certId.get(), V_OCSP_CERTSTATUS_REVOKED,
      OCSP_UNASSIGNED_REVOKED_STATUS, revoked_time.get(), this_update.get(),
      nullptr));

  EXPECT_TRUE(OCSP_basic_add1_status(
      basicResponse.get(), certId.get(), V_OCSP_CERTSTATUS_REVOKED,
      OCSP_REVOKED_STATUS_UNSPECIFIED, revoked_time.get(), this_update.get(),
      nullptr));

  // Try setting an invalid status to the response.
  EXPECT_FALSE(OCSP_basic_add1_status(basicResponse.get(), certId.get(), 4, 0,
                                      nullptr, this_update.get(), nullptr));

  // |OCSP_basic_add1_status| has succeeded 5 times at this point, so the
  // |basicResponse| should have 5 |OCSP_SINGLERESP|s in the internal stack.
  EXPECT_EQ((int)sk_OCSP_SINGLERESP_num(
                basicResponse.get()->tbsResponseData->responses),
            5);
}

TEST(OCSPTest, OCSPResponseRecreate) {
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response(
      LoadOCSP_RESPONSE(ocsp_response_data));
  ASSERT_TRUE(ocsp_response);
  bssl::UniquePtr<OCSP_BASICRESP> basic_response(
      OCSP_response_get1_basic(ocsp_response.get()));
  ASSERT_TRUE(basic_response);

  // Recreate the same |OCSP_RESPONSE| with the same contents.
  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response_recreated(OCSP_response_create(
      OCSP_response_status(ocsp_response.get()), basic_response.get()));
  EXPECT_TRUE(ocsp_response_recreated);

  // Write out the bytes from |ocsp_response_recreated| to compare with the
  // original.
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(i2d_OCSP_RESPONSE_bio(bio.get(), ocsp_response_recreated.get()));
  const uint8_t *bio_data;
  size_t bio_len;
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_data, &bio_len));
  EXPECT_EQ(Bytes(bio_data, bio_len),
            Bytes(ocsp_response_data.data(), ocsp_response_data.size()));

  // Disallow creation of an |OCSP_RESPONSE| with an invalid status number.
  EXPECT_FALSE(OCSP_response_create(OCSP_UNASSIGNED_RESPONSE_STATUS,
                                    basic_response.get()));
}

// === Translation of OpenSSL's OCSP tests ===

// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/test/recipes/80-test_ocsp.t
struct OCSPTestVector {
  const char *ocsp_response;
  const char *cafile;
  const char *untrusted;
  int expected_ocsp_verify_status;
};

// Test vectors from OpenSSL OCSP's tests
static const OCSPTestVector kTestVectors[] = {
    // === VALID OCSP RESPONSES ===
    {"ND1", "ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"ND2", "ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"ND3", "ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"ND1", "ND1_Cross_Root", "ND1_Issuer_ICA-Cross",
     OCSP_VERIFYSTATUS_SUCCESS},
    {"D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    // === INVALID SIGNATURE on the OCSP RESPONSE ===
    {"ISOP_ND1", "ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISOP_ND2", "ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISOP_ND3", "ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISOP_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISOP_D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISOP_D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG RESPONDERID in the OCSP RESPONSE ===
    {"WRID_ND1", "ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WRID_ND2", "ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WRID_ND3", "ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WRID_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WRID_D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WRID_D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG ISSUERNAMEHASH in the OCSP RESPONSE ===
    {"WINH_ND1", "ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WINH_ND2", "ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WINH_ND3", "ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WINH_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WINH_D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WINH_D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG ISSUERKEYHASH in the OCSP RESPONSE ===
    {"WIKH_ND1", "ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WIKH_ND2", "ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WIKH_ND3", "ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WIKH_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WIKH_D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WIKH_D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG KEY in the DELEGATED OCSP SIGNING CERTIFICATE ===
    {"WKDOSC_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"WKDOSC_D2", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"WKDOSC_D3", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === INVALID SIGNATURE on the DELEGATED OCSP SIGNING CERTIFICATE ===
    {"ISDOSC_D1", "D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISDOSC_D1", "D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ISDOSC_D1", "D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG SUBJECT NAME in the ISSUER CERTIFICATE ===
    {"ND1", "WSNIC_ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"ND2", "WSNIC_ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ND3", "WSNIC_ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"D1", "WSNIC_D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"D2", "WSNIC_D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"D3", "WSNIC_D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === WRONG KEY in the ISSUER CERTIFICATE ===
    {"ND1", "WKIC_ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"ND2", "WKIC_ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"ND3", "WKIC_ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"D1", "WKIC_D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_ERROR},
    {"D2", "WKIC_D2_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    {"D3", "WKIC_D3_Issuer_Root", "", OCSP_VERIFYSTATUS_ERROR},
    // === INVALID SIGNATURE on the ISSUER CERTIFICATE ===
    // Expect success, because we're explicitly trusting the issuer certificate.
    // https://datatracker.ietf.org/doc/html/rfc6960#section-2.6
    {"ND1", "ISIC_ND1_Issuer_ICA", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"ND2", "ISIC_ND2_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"ND3", "ISIC_ND3_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"D1", "ISIC_D1_Issuer_ICA", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"D2", "ISIC_D2_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
    {"D3", "ISIC_D3_Issuer_Root", "", OCSP_VERIFYSTATUS_SUCCESS},
};


class OCSPTest : public testing::TestWithParam<OCSPTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPTest, testing::ValuesIn(kTestVectors));

TEST_P(OCSPTest, VerifyOCSPResponse) {
  const OCSPTestVector &t = GetParam();

  bssl::UniquePtr<OCSP_RESPONSE> ocsp_response;
  bssl::UniquePtr<OCSP_BASICRESP> basic_response;

  // Get OCSP response from path.
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/" + std::string(t.ocsp_response) + ".ors")
          .c_str());
  std::vector<uint8_t> input;
  ASSERT_TRUE(DecodeBase64(&input, data.c_str()));

  ocsp_response = LoadOCSP_RESPONSE(input);
  ASSERT_TRUE(ocsp_response);

  int ret = OCSP_response_status(ocsp_response.get());
  ASSERT_EQ(OCSP_RESPONSE_STATUS_SUCCESSFUL, ret);

  basic_response = bssl::UniquePtr<OCSP_BASICRESP>(
      OCSP_response_get1_basic(ocsp_response.get()));
  ASSERT_TRUE(basic_response);

  // Set up OpenSSL OCSP tests trust store parameters and cert chain.
  bssl::UniquePtr<STACK_OF(X509)> server_cert_chain;
  bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
  bssl::UniquePtr<X509_VERIFY_PARAM> vpm(X509_VERIFY_PARAM_new());
  X509_VERIFY_PARAM_set_time(vpm.get(), (time_t)1355875200);
  // Discussion for whether this flag should be on by default or not:
  // https://github.com/openssl/openssl/issues/7871
  ASSERT_EQ(X509_VERIFY_PARAM_set_flags(vpm.get(), X509_V_FLAG_PARTIAL_CHAIN),
            1);

  // Get CA root certificate from path and set up trust store.
  bssl::UniquePtr<X509> ca_certificate(
      CertFromPEM(GetTestData(std::string("crypto/ocsp/test/" +
                                          std::string(t.cafile) + ".pem")
                                  .c_str())
                      .c_str()));
  X509_STORE_add_cert(trust_store.get(), ca_certificate.get());
  ASSERT_EQ(X509_STORE_set1_param(trust_store.get(), vpm.get()), 1);

  // If untrusted cert chain isn't available, we only use CA cert as root
  // cert.
  if (std::string(t.untrusted).empty()) {
    server_cert_chain = CertsToStack({ca_certificate.get()});
  } else {
    server_cert_chain = CertChainFromPEM(
        GetTestData(
            std::string("crypto/ocsp/test/" + std::string(t.untrusted) + ".pem")
                .c_str())
            .c_str());
  }
  ASSERT_TRUE(server_cert_chain);

  // Does basic verification on OCSP response.
  const int ocsp_verify_status = OCSP_basic_verify(
      basic_response.get(), server_cert_chain.get(), trust_store.get(), 0);
  ASSERT_EQ(t.expected_ocsp_verify_status, ocsp_verify_status);
}

struct OCSPRequestTestVector {
  const char *ocsp_request;
  int expected_parse_status;
  int expected_sign_status;
  const char *signer_cert;
  const char *key_type;
  const EVP_MD *dgst;
};

static const OCSPRequestTestVector kRequestTestVectors[] = {
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS, "rsa_cert",
     "rsa_key", EVP_sha1()},
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS, "rsa_cert",
     "rsa_key", EVP_sha256()},
    {"ocsp_request_attached_cert", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR,
     "rsa_cert", "rsa_key", nullptr},
    {"ocsp_request_no_nonce", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS,
     "rsa_cert", "rsa_key", EVP_sha512()},
    {"ocsp_request_signed", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR,
     "rsa_cert", "rsa_key", nullptr},
    {"ocsp_request_signed_sha256", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR,
     "rsa_cert", "rsa_key", nullptr},
    {"ocsp_response", OCSP_REQUEST_PARSE_ERROR, OCSP_SIGN_ERROR, "rsa_cert",
     "rsa_key", nullptr},
    // Test signing with ECDSA certs and keys.
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS,
     "ecdsa_cert", "ecdsa_key", EVP_sha1()},
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS,
     "ecdsa_cert", "ecdsa_key", EVP_sha256()},
    {"ocsp_request_no_nonce", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS,
     "rsa_cert", "rsa_key", EVP_sha256()},
    {"ocsp_request_no_nonce", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_SUCCESS,
     "ecdsa_cert", "ecdsa_key", EVP_sha256()},
    // Test certificate type mismatch.
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR, "rsa_cert",
     "ecdsa_key", EVP_sha256()},
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR, "ecdsa_cert",
     "rsa_key", EVP_sha256()},
    // Test certificate key and cert mismatch.
    {"ocsp_request", OCSP_REQUEST_PARSE_SUCCESS, OCSP_SIGN_ERROR, "ca_cert",
     "rsa_key", EVP_sha256()},
};

class OCSPRequestTest : public testing::TestWithParam<OCSPRequestTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPRequestTest,
                         testing::ValuesIn(kRequestTestVectors));

static const char good_http_request_hdr[] =
    "POST / HTTP/1.0\r\n"
    "Content-Type: application/ocsp-request\r\n"
    "Content-Length: ";

TEST_P(OCSPRequestTest, OCSPRequestParse) {
  const OCSPRequestTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_request) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());

  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);

  if (t.expected_parse_status == OCSP_REQUEST_PARSE_SUCCESS) {
    ASSERT_TRUE(ocspRequest);

    // If request parsing is successful, try setting up a |OCSP_REQ_CTX| with
    // default settings.
    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
    const uint8_t *out;
    size_t outlen;
    bssl::UniquePtr<OCSP_REQ_CTX> ocspReqCtx(
        OCSP_sendreq_new(bio.get(), nullptr, ocspRequest.get(), 0));
    ASSERT_TRUE(ocspReqCtx);
    // Get internal memory of |OCSP_REQ_CTX| and ensure contents are written.
    ASSERT_TRUE(BIO_mem_contents(OCSP_REQ_CTX_get0_mem_bio(ocspReqCtx.get()),
                                 &out, &outlen));
    ASSERT_GT(outlen, (size_t)0);

    // Set up |OCSP_REQ_CTX| without a |OCSP_REQUEST|. Then finalize the context
    // later.
    bssl::UniquePtr<BIO> bio2(BIO_new(BIO_s_mem()));
    const uint8_t *out2;
    size_t outlen2;
    bssl::UniquePtr<OCSP_REQ_CTX> ocspReqCtxLater(
        OCSP_sendreq_new(bio2.get(), nullptr, nullptr, 0));
    ASSERT_TRUE(ocspReqCtxLater);
    ASSERT_TRUE(
        OCSP_REQ_CTX_set1_req(ocspReqCtxLater.get(), ocspRequest.get()));
    ASSERT_TRUE(BIO_mem_contents(
        OCSP_REQ_CTX_get0_mem_bio(ocspReqCtxLater.get()), &out2, &outlen2));

    // Ensure header contents are written as expected.
    EXPECT_EQ(
        good_http_request_hdr + std::to_string(ocsp_request_data.size()) + "\r",
        std::string(reinterpret_cast<const char *>(out),
                    sizeof(good_http_request_hdr) +
                        std::to_string(ocsp_request_data.size()).size()));
    // Check |OCSP_REQ_CTX| construction methods write the exact same contents.
    ASSERT_EQ(Bytes(out, outlen), Bytes(out2, outlen2));
  } else {
    ASSERT_FALSE(ocspRequest);
  }
}

TEST_P(OCSPRequestTest, OCSPRequestSign) {
  const OCSPRequestTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_request) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);

  bssl::UniquePtr<X509> signer_cert(
      CertFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                          std::string(t.signer_cert) + ".pem")
                                  .c_str())
                      .c_str()));
  ASSERT_TRUE(signer_cert);
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  ASSERT_TRUE(ca_cert);

  if (t.expected_parse_status == OCSP_REQUEST_PARSE_SUCCESS) {
    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
    if (std::string(t.key_type) == "rsa_key") {
      bssl::UniquePtr<RSA> rsa(
          RSAFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                             std::string(t.key_type) + ".pem")
                                     .c_str())
                         .c_str()));
      ASSERT_TRUE(rsa);
      ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()));
    } else {
      bssl::UniquePtr<EC_KEY> ecdsa(
          ECDSAFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                               std::string(t.key_type) + ".pem")
                                       .c_str())
                           .c_str()));
      ASSERT_TRUE(ecdsa);
      ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa.get()));
    }

    int ret =
        OCSP_request_sign(ocspRequest.get(), signer_cert.get(), pkey.get(),
                          t.dgst, CertsToStack({ca_cert.get()}).get(), 0);
    if (t.expected_sign_status == OCSP_SIGN_SUCCESS) {
      ASSERT_TRUE(ret);
      EXPECT_TRUE(OCSP_request_is_signed(ocspRequest.get()));
      bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
      ASSERT_TRUE(X509_STORE_add_cert(trust_store.get(), ca_cert.get()));
      EXPECT_TRUE(OCSP_request_verify(ocspRequest.get(),
                                      CertsToStack({signer_cert.get()}).get(),
                                      trust_store.get(), 0));
    } else {
      ASSERT_FALSE(ret);
      EXPECT_FALSE(OCSP_request_is_signed(ocspRequest.get()));
    }
  }
}

struct OCSPResponseSignTestVector {
  int expected_sign_status;
  const char *signer_cert;
  const char *key_type;
  const EVP_MD *dgst;
};

static const OCSPResponseSignTestVector kOCSPResponseSignTestVectors[] = {
    {OCSP_SIGN_SUCCESS, "rsa_cert", "rsa_key", EVP_sha1()},
    {OCSP_SIGN_SUCCESS, "rsa_cert", "rsa_key", EVP_sha256()},
    {OCSP_SIGN_SUCCESS, "rsa_cert", "rsa_key", EVP_sha512()},
    // Test signing with ECDSA certs and keys.
    {OCSP_SIGN_SUCCESS, "ecdsa_cert", "ecdsa_key", EVP_sha1()},
    {OCSP_SIGN_SUCCESS, "ecdsa_cert", "ecdsa_key", EVP_sha256()},
    {OCSP_SIGN_SUCCESS, "ecdsa_cert", "ecdsa_key", EVP_sha512()},
    // Test certificate type mismatch.
    {OCSP_SIGN_ERROR, "rsa_cert", "ecdsa_key", EVP_sha256()},
    {OCSP_SIGN_ERROR, "ecdsa_cert", "rsa_key", EVP_sha256()},
    // Test certificate key and cert mismatch.
    {OCSP_SIGN_ERROR, "ca_cert", "rsa_key", EVP_sha256()},
};

class OCSPResponseSignTest
    : public testing::TestWithParam<OCSPResponseSignTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPResponseSignTest,
                         testing::ValuesIn(kOCSPResponseSignTestVectors));

TEST_P(OCSPResponseSignTest, OCSPResponseSign) {
  const OCSPResponseSignTestVector &t = GetParam();

  // Set up an empty |OCSP_BASICRESP| for signing.
  bssl::UniquePtr<OCSP_BASICRESP> basic_response(OCSP_BASICRESP_new());
  ASSERT_TRUE(basic_response);

  // Gather certs and key needed for signing.
  bssl::UniquePtr<X509> signer_cert(
      CertFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                          std::string(t.signer_cert) + ".pem")
                                  .c_str())
                      .c_str()));
  ASSERT_TRUE(signer_cert);
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  ASSERT_TRUE(ca_cert);
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  if (std::string(t.key_type) == "rsa_key") {
    bssl::UniquePtr<RSA> rsa(
        RSAFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                           std::string(t.key_type) + ".pem")
                                   .c_str())
                       .c_str()));
    ASSERT_TRUE(rsa);
    ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()));
  } else {
    bssl::UniquePtr<EC_KEY> ecdsa(
        ECDSAFromPEM(GetTestData(std::string("crypto/ocsp/test/aws/" +
                                             std::string(t.key_type) + ".pem")
                                     .c_str())
                         .c_str()));
    ASSERT_TRUE(ecdsa);
    ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa.get()));
  }

  // Do the actual sign.
  EXPECT_EQ(OCSP_basic_sign(basic_response.get(), signer_cert.get(), pkey.get(),
                            t.dgst, CertsToStack({ca_cert.get()}).get(), 0),
            t.expected_sign_status);
  if (t.expected_sign_status == OCSP_SIGN_SUCCESS) {
    bssl::UniquePtr<X509_STORE> trust_store(X509_STORE_new());
    ASSERT_TRUE(X509_STORE_add_cert(trust_store.get(), ca_cert.get()));
    EXPECT_TRUE(OCSP_basic_verify(basic_response.get(),
                                  CertsToStack({signer_cert.get()}).get(),
                                  trust_store.get(), 0));
  }
}

// Test against various flags for |OCSP_basic_sign|.
TEST(OCSPResponseSignTestExtended, OCSPResponseSign) {
  bssl::UniquePtr<OCSP_BASICRESP> basic_response(OCSP_BASICRESP_new());
  ASSERT_TRUE(basic_response);

  bssl::UniquePtr<X509> signer_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/rsa_cert.pem").c_str())
          .c_str()));
  ASSERT_TRUE(signer_cert);
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  ASSERT_TRUE(ca_cert);
  bssl::UniquePtr<STACK_OF(X509)> additional_cert =
      CertsToStack({ca_cert.get()});

  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  bssl::UniquePtr<RSA> rsa(RSAFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/rsa_key.pem").c_str())
          .c_str()));
  ASSERT_TRUE(rsa);
  ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()));

  // Call |OCSP_basic_sign| with no flags and check the expected output.
  EXPECT_TRUE(OCSP_basic_sign(basic_response.get(), signer_cert.get(),
                              pkey.get(), EVP_sha256(), additional_cert.get(),
                              0));
  EXPECT_TRUE(
      ASN1_TIME_check(basic_response.get()->tbsResponseData->producedAt));
  // Allow for time field to be within two hours.
  EXPECT_GT(
      X509_cmp_time_posix(basic_response.get()->tbsResponseData->producedAt,
                          time(nullptr) - 3600),
      0);
  EXPECT_LT(
      X509_cmp_time_posix(basic_response.get()->tbsResponseData->producedAt,
                          time(nullptr) + 3600),
      0);

  EXPECT_EQ(basic_response.get()->tbsResponseData->responderId->type,
            V_OCSP_RESPID_NAME);
  EXPECT_EQ(
      X509_NAME_cmp(
          basic_response.get()->tbsResponseData->responderId->value.byName,
          X509_get_subject_name(signer_cert.get())),
      0);
  EXPECT_EQ((int)sk_X509_num(basic_response.get()->certs), 2);
  EXPECT_EQ(X509_cmp(sk_X509_value(basic_response.get()->certs, 0),
                     signer_cert.get()),
            0);
  EXPECT_EQ(X509_cmp(sk_X509_value(basic_response.get()->certs, 1),
                     sk_X509_value(additional_cert.get(), 0)),
            0);

  // Check expected effects of |OCSP_NOTIME|.
  basic_response.reset(OCSP_BASICRESP_new());
  ASSERT_TRUE(basic_response);
  EXPECT_TRUE(OCSP_basic_sign(basic_response.get(), signer_cert.get(),
                              pkey.get(), EVP_sha256(), additional_cert.get(),
                              OCSP_NOTIME));
  EXPECT_FALSE(
      ASN1_TIME_check(basic_response.get()->tbsResponseData->producedAt));

  // Check expected effects of |OCSP_RESPID_KEY|.
  basic_response.reset(OCSP_BASICRESP_new());
  ASSERT_TRUE(basic_response);
  ASSERT_FALSE(basic_response.get()->tbsResponseData->responderId->value.byKey);
  EXPECT_TRUE(OCSP_basic_sign(basic_response.get(), signer_cert.get(),
                              pkey.get(), EVP_sha256(), additional_cert.get(),
                              OCSP_RESPID_KEY));
  EXPECT_EQ(basic_response.get()->tbsResponseData->responderId->type,
            V_OCSP_RESPID_KEY);
  EXPECT_TRUE(basic_response.get()->tbsResponseData->responderId->value.byKey);


  // Check expected effects of |OCSP_NOCERTS|.
  basic_response.reset(OCSP_BASICRESP_new());
  ASSERT_TRUE(basic_response);
  EXPECT_TRUE(OCSP_basic_sign(basic_response.get(), signer_cert.get(),
                              pkey.get(), EVP_sha256(), additional_cert.get(),
                              OCSP_NOCERTS));
  EXPECT_EQ((int)sk_X509_num(basic_response.get()->certs), 0);
}

static const char extended_good_http_request_hdr[] =
    "POST / HTTP/1.0\r\n"
    "Accept-Charset: character-set\r\n"
    "Content-Type: application/ocsp-request\r\n"
    "Content-Length: ";

// Check HTTP header can be written with OCSP_REQ_CTX_add1_header().
TEST(OCSPRequestTest, AddHeader) {
  std::string data = GetTestData(std::string("crypto/ocsp/test/aws/"
                                             "ocsp_request.der")
                                     .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);

  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  const uint8_t *out;
  size_t outlen;
  bssl::UniquePtr<OCSP_REQ_CTX> ocspReqCtx(
      OCSP_sendreq_new(bio.get(), nullptr, nullptr, 0));
  ASSERT_TRUE(ocspReqCtx);
  // Set an additional HTTP header.
  ASSERT_TRUE(OCSP_REQ_CTX_add1_header(ocspReqCtx.get(), "Accept-Charset",
                                       "character-set"));
  ASSERT_TRUE(OCSP_REQ_CTX_set1_req(ocspReqCtx.get(), ocspRequest.get()));

  ASSERT_TRUE(BIO_mem_contents(OCSP_REQ_CTX_get0_mem_bio(ocspReqCtx.get()),
                               &out, &outlen));

  // Ensure additional header contents are written as expected.
  EXPECT_EQ(
      extended_good_http_request_hdr +
          std::to_string(ocsp_request_data.size()) + "\r\n",
      std::string(reinterpret_cast<const char *>(out),
                  sizeof(extended_good_http_request_hdr) +
                      std::to_string(ocsp_request_data.size()).size() + 1));
}

// Check a |OCSP_CERTID| can be added to an |OCSP_REQUEST| with
// OCSP_request_add0_id().
TEST(OCSPRequestTest, AddCert) {
  std::string data = GetTestData(std::string("crypto/ocsp/test/aws/"
                                             "ocsp_request.der")
                                     .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);
  ASSERT_TRUE(ocspRequest);

  // Construct |OCSP_CERTID| from certs.
  OCSP_CERTID *certId = LoadTestOCSP_CERTID();
  ASSERT_TRUE(certId);

  OCSP_ONEREQ *oneRequest = OCSP_request_add0_id(ocspRequest.get(), certId);
  ASSERT_TRUE(oneRequest);
  // OCSP_request_add0_id() allocates a new |OCSP_ONEREQ| and assigns the
  // pointer to |OCSP_CERTID| to it, then adds it to the stack within
  // |OCSP_REQUEST|.
  // |OCSP_REQUEST| now takes ownership of the pointer to |OCSP_CERTID| and
  // still maintains ownership of the pointer |OCSP_ONEREQ|, so we have to set
  // the references to NULL to avoid freeing the same pointers twice.
  oneRequest = nullptr;
  certId = nullptr;
}

static const char good_http_response_hdr[] =
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// Test that |OCSP_set_max_response_length| correctly sets the maximum response
// length.
TEST(OCSPRequestTest, SetResponseLength) {
  std::string data = GetTestData(std::string("crypto/ocsp/test/aws/"
                                             "ocsp_request.der")
                                     .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);
  ASSERT_TRUE(ocspRequest);

  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  bssl::UniquePtr<OCSP_REQ_CTX> ocspReqCtx(
      OCSP_sendreq_new(bio.get(), nullptr, nullptr, 0));
  ASSERT_TRUE(ocspReqCtx);

  // Check custom length is set correctly.
  int new_len = 40000;
  OCSP_set_max_response_length(ocspReqCtx.get(), new_len);
  EXPECT_EQ((int)ocspReqCtx.get()->max_resp_len, new_len);

  // Check that default length is set correctly.
  OCSP_set_max_response_length(ocspReqCtx.get(), 0);
  EXPECT_EQ((int)ocspReqCtx.get()->max_resp_len, OCSP_MAX_RESP_LENGTH);

  // Write an HTTP OCSP response into the BIO.
  std::string respData = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());
  const int respLen = (int)ocsp_response_data.size();
  ASSERT_GT(BIO_printf(bio.get(), "%s", good_http_response_hdr), 0);
  ASSERT_GT(BIO_printf(bio.get(), "%d\r\n\r\n", respLen), 0);
  ASSERT_EQ(BIO_write(bio.get(), ocsp_response_data.data(), respLen), respLen);

  // Set max response length to a length that is too short on purpose.
  OCSP_set_max_response_length(ocspReqCtx.get(), 1);

  // Sends out an OCSP request and expects an OCSP response in |BIO| with
  // |OCSP_REQ_CTX_nbio|. This should fail if the expected length is too short.
  EXPECT_FALSE(OCSP_REQ_CTX_nbio(ocspReqCtx.get()));
}

static const char malformed_http_response_hdr[] =
    "HTTP/1.200 OK\r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// This parses in OpenSSL, but fails in AWS-LC because we check for the HTTP
// protocol characters at the front.
static const char non_http_response_hdr[] =
    "HTPT/1.1 200 OK\r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// Only status code 200 should be accepted.
static const char not_ok_http_response_hdr[] =
    "HTTP/1.1 404 OK\r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// This should parse. Only the status code is mandatory, subsequent lines are
// optional.
static const char no_type_http_response_hdr[] =
    "HTTP/1.1 200 OK\r\n"
    "Content-Length: ";

// This should parse. Only the status code is mandatory, additional information
// is optional.
static const char no_info_http_response_hdr[] =
    "HTTP/1.0 200\r\n"
    "Content-Length: ";

// OpenSSL uses isspace() to test for white-space characters, which includes
// the following. ``\t''``\n''``\v''``\f''``\r''`` '
// This should parse. "\n" is not included since it will skip the header to the
// next line and fail the http parsing.
static const char additional_space_http_response_hdr[] =
    "HTTP/1.1 \t\v\r\f\t 200  \t\v\f\r\t   OK   \r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// This should fail, since the status code is expected on the first line.
static const char next_line_http_response_hdr[] =
    "HTTP/1.1   \n   200    \f   OK\r\n"
    "Content-Type: application/ocsp-response\r\n"
    "Content-Length: ";

// This should fail. Protocol info is expected at the front.
static const char only_code_http_response_hdr[] =
    "200\r\n"
    "Content-Length: ";

// This should fail. We're appending a negative content length.
static const char negative_length_http_response_hdr[] =
    "HTTP/1.0 200\r\n"
    "Content-Length: -10";

// This should fail. We're appending a non-numeric content length.
static const char nonnumeric_length_http_response_hdr[] =
    "HTTP/1.0 200\r\n"
    "Content-Length: abcd";

// This should fail. We're appending a non-numeric content length.
static const char format_string_http_response_hdr[] =
    "HTTP/1.0 200\r\n"
    "Content-Length: %s%s%s%s%s";

// This should fail. We're appending a value that will be beyond the default max
// response length.
static const char max_length_http_response_hdr[] =
    "HTTP/1.0 200\r\n"
    "Content-Length: 999999";

struct OCSPHTTPTestVector {
  const char *http_header;
  bool response_attached;
  int expected_status;
};

static const OCSPHTTPTestVector kResponseHTTPVectors[] = {
    {good_http_response_hdr, true, OCSP_HTTP_PARSE_SUCCESS},
    {malformed_http_response_hdr, true, OCSP_HTTP_PARSE_ERROR},
    {non_http_response_hdr, true, OCSP_HTTP_PARSE_ERROR},
    {not_ok_http_response_hdr, true, OCSP_HTTP_PARSE_ERROR},
    {no_type_http_response_hdr, true, OCSP_REQUEST_PARSE_SUCCESS},
    {no_info_http_response_hdr, true, OCSP_REQUEST_PARSE_SUCCESS},
    {additional_space_http_response_hdr, true, OCSP_REQUEST_PARSE_SUCCESS},
    {next_line_http_response_hdr, true, OCSP_HTTP_PARSE_ERROR},
    {only_code_http_response_hdr, true, OCSP_HTTP_PARSE_ERROR},
    // HTTP Header is OK, but no actual response is attached.
    {good_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {no_type_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {no_info_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {negative_length_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {nonnumeric_length_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {format_string_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR},
    {max_length_http_response_hdr, false, OCSP_HTTP_PARSE_ERROR}};

class OCSPHTTPTest : public testing::TestWithParam<OCSPHTTPTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPHTTPTest,
                         testing::ValuesIn(kResponseHTTPVectors));

// Test if OCSP_sendreq_bio() can properly send out an HTTP request with
// a |OCSP_REQUEST|, and expect an HTTP response with an OCSP response back.
// Always sends the same OCSP request and replies with the same OCSP response.
// This test focuses parsing the OCSP response with HTTP. We have other tests
// to test if the actual OCSP response is parsable and verifiable.
TEST_P(OCSPHTTPTest, OCSPRequestHTTP) {
  const OCSPHTTPTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/ocsp_request.der").c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  std::string respData = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());

  // Write an HTTP OCSP response into the BIO.
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  const int respLen = (int)ocsp_response_data.size();
  ASSERT_GT(BIO_printf(bio.get(), "%s", t.http_header), 0);
  ASSERT_GT(BIO_printf(bio.get(), "%d\r\n\r\n", respLen), 0);
  if (t.response_attached) {
    ASSERT_EQ(BIO_write(bio.get(), ocsp_response_data.data(), respLen),
              respLen);
  }

  // Sends out an OCSP request and expects an OCSP response in |BIO|.
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);
  ASSERT_TRUE(ocspRequest);
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse(
      OCSP_sendreq_bio(bio.get(), nullptr, ocspRequest.get()));
  if (t.expected_status == OCSP_HTTP_PARSE_SUCCESS && t.response_attached) {
    ASSERT_TRUE(ocspResponse);
  } else {
    ASSERT_FALSE(ocspResponse);
  }
}

struct OCSPURLTestVector {
  const char *ocsp_url;
  const char *expected_host;
  const char *expected_port;
  const char *expected_path;
  int expected_ssl;
  int expected_status;
};

static const OCSPURLTestVector kOCSPURLVectors[] = {
    // === VALID URLs ===
    {"http://ocsp.example.com/", "ocsp.example.com", "80", "/", 0,
     OCSP_URL_PARSE_SUCCESS},
    // Non-standard port.
    {"http://ocsp.example.com:8080/", "ocsp.example.com", "8080", "/", 0,
     OCSP_URL_PARSE_SUCCESS},
    {"http://ocsp.example.com/ocsp", "ocsp.example.com", "80", "/ocsp", 0,
     OCSP_URL_PARSE_SUCCESS},
    // Port for HTTPS is 443.
    {"https://ocsp.example.com/", "ocsp.example.com", "443", "/", 1,
     OCSP_URL_PARSE_SUCCESS},
    // Empty path, the default should be "/".
    {"https://ocsp.example.com", "ocsp.example.com", "443", "/", 1,
     OCSP_URL_PARSE_SUCCESS},
    // Parsing an IPv6 host address.
    {"http://[2001:db8::1]/ocsp", "2001:db8::1", "80", "/ocsp", 0,
     OCSP_URL_PARSE_SUCCESS},
    {"https://[2001:db8::1]/ocsp", "2001:db8::1", "443", "/ocsp", 1,
     OCSP_URL_PARSE_SUCCESS},
    // Parsing a URL with an invalid port, but OpenSSL still parses the string
    // where the port is expected.
    {"http://ocsp.example.com:invalid/", "ocsp.example.com", "invalid", "/", 0,
     OCSP_URL_PARSE_SUCCESS},
    // Empty host component.
    {"http:///ocsp", "", "80", "/ocsp", 0, OCSP_URL_PARSE_SUCCESS},
    // Potential Format String attacks.
    {"http://%s%s%s%s%s/ocsp", "%s%s%s%s%s", "80", "/ocsp", 0,
     OCSP_URL_PARSE_SUCCESS},
    {"http://%s%s%s%s%s, argv[1]/ocsp", "%s%s%s%s%s, argv[1]", "80", "/ocsp", 0,
     OCSP_URL_PARSE_SUCCESS},
    {"http://ocsp/%s%s%s%s%s", "ocsp", "80", "/%s%s%s%s%s", 0,
     OCSP_URL_PARSE_SUCCESS},

    // === INVALID URLs ===
    // Not http or https in front.
    {"htp://ocsp.example.com/", nullptr, nullptr, nullptr, 0,
     OCSP_URL_PARSE_ERROR},
    {"%s%s%s%s://%s%s%s%s%s/ocsp", nullptr, nullptr, nullptr, 0,
     OCSP_URL_PARSE_ERROR},
    // Double slash is mandatory.
    {"http:/ocsp.example.com/", nullptr, nullptr, nullptr, 0,
     OCSP_URL_PARSE_ERROR},
    // Malformed.
    {"httocsp.example.com/", nullptr, nullptr, nullptr, 0,
     OCSP_URL_PARSE_ERROR},
    // No closing bracket for ipv6.
    {"http://[2001:db8::1/", nullptr, nullptr, nullptr, 0,
     OCSP_URL_PARSE_ERROR},
};

class OCSPURLTest : public testing::TestWithParam<OCSPURLTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPURLTest, testing::ValuesIn(kOCSPURLVectors));

TEST_P(OCSPURLTest, OCSPParseURL) {
  const OCSPURLTestVector &t = GetParam();

  char *host = nullptr;
  char *path = nullptr;
  char *port = nullptr;
  int is_ssl;

  int ret = OCSP_parse_url(t.ocsp_url, &host, &port, &path, &is_ssl);
  if (t.expected_status == OCSP_URL_PARSE_SUCCESS) {
    EXPECT_EQ(ret, OCSP_URL_PARSE_SUCCESS);
    EXPECT_EQ(std::string(host), std::string(t.expected_host));
    EXPECT_EQ(std::string(port), std::string(t.expected_port));
    EXPECT_EQ(std::string(path), std::string(t.expected_path));
    OPENSSL_free(host);
    OPENSSL_free(path);
    OPENSSL_free(port);
  } else {
    EXPECT_EQ(ret, OCSP_URL_PARSE_ERROR);
    EXPECT_FALSE(host);
    EXPECT_FALSE(port);
    EXPECT_FALSE(path);
  }
}

// Nonce value used in "crypto/ocsp/test/aws/ocsp_response.der".
static unsigned char ocsp_response_nonce[] = {
    0xaf, 0xab, 0xd4, 0xec, 0x6a, 0x17, 0x2c, 0x4a,
    0x98, 0xfb, 0x1a, 0x6d, 0x22, 0xff, 0x29, 0x28};

struct OCSPNonceTestVector {
  const char *ocsp_request;
  const char *ocsp_response;
  bool add_nonce;
  unsigned char *nonce;
  int nonce_len;
  int nonce_check_status;
};

static const OCSPNonceTestVector kNonceTestVectors[] = {
    // Add a nonce to an OCSP request without a nonce.
    {"ocsp_request_no_nonce", "ocsp_response", true, ocsp_response_nonce,
     sizeof(ocsp_response_nonce), OCSP_NONCE_EQUAL},
    // Add a nonce to an OCSP request with a nonce. The original nonce should be
    // overwritten.
    {"ocsp_request", "ocsp_response", true, ocsp_response_nonce,
     sizeof(ocsp_response_nonce), OCSP_NONCE_EQUAL},
    // Generate a random nonce, which should be different from the nonce
    // available in the OCSP response (unless we have a collision).
    {"ocsp_request", "ocsp_response", true, nullptr, 0, OCSP_NONCE_NOT_EQUAL},
    // OCSP request with no nonce, but an OCSP response that does have one.
    {"ocsp_request_no_nonce", "ocsp_response", false, nullptr, 0,
     OCSP_NONCE_RESPONSE_ONLY},
    // OCSP request with a nonce, but an OCSP response that does not have one.
    {"ocsp_request", "ocsp_response_no_nonce", false, nullptr, 0,
     OCSP_NONCE_REQUEST_ONLY},
    // An OCSP request and an OCSP response that don't have a nonce to compare.
    {"ocsp_request_no_nonce", "ocsp_response_no_nonce", false, nullptr, 0,
     OCSP_NONCE_BOTH_ABSENT},
};

class OCSPNonceTest : public testing::TestWithParam<OCSPNonceTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, OCSPNonceTest,
                         testing::ValuesIn(kNonceTestVectors));

TEST_P(OCSPNonceTest, OCSPNonce) {
  const OCSPNonceTestVector &t = GetParam();

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_request) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);
  std::string respData =
      GetTestData(std::string("crypto/ocsp/test/aws/" +
                              std::string(t.ocsp_response) + ".der")
                      .c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse =
      LoadOCSP_RESPONSE(ocsp_response_data);
  bssl::UniquePtr<OCSP_BASICRESP> basicResponse(
      OCSP_response_get1_basic(ocspResponse.get()));
  ASSERT_TRUE(basicResponse);

  if (t.add_nonce) {
    // Adding a nonce should succeed. The original nonce will get overwritten
    // if one already exists.
    EXPECT_TRUE(
        OCSP_request_add1_nonce(ocspRequest.get(), t.nonce, t.nonce_len));

    // Check if hard coded nonce value has been written correctly.
    if (t.nonce) {
      int req_idx = OCSP_REQUEST_get_ext_by_NID(ocspRequest.get(),
                                                NID_id_pkix_OCSP_Nonce, -1);
      const ASN1_OCTET_STRING *nonce_data = X509_EXTENSION_get_data(
          OCSP_REQUEST_get_ext(ocspRequest.get(), req_idx));

      // The ASN.1 Octet String data type encoding begins with a Tag byte of
      // 0x04. The second byte is the length of the encoded value, so we compare
      // the rest of the bytes to ensure the nonce value was written correctly.
      // https://www.ietf.org/rfc/rfc6025.html#section-2.1.2
      EXPECT_EQ(Bytes(&ASN1_STRING_get0_data(nonce_data)[2],
                      ASN1_STRING_length(nonce_data) - 2),
                Bytes(t.nonce, t.nonce_len));
    }
  }
  EXPECT_EQ(OCSP_check_nonce(ocspRequest.get(), basicResponse.get()),
            t.nonce_check_status);

  // Check that nonce copying from |req| to |bs| also works as expected.
  if (t.nonce_check_status == OCSP_NONCE_RESPONSE_ONLY ||
      t.nonce_check_status == OCSP_NONCE_BOTH_ABSENT) {
    EXPECT_EQ(OCSP_copy_nonce(basicResponse.get(), ocspRequest.get()), 2);
    EXPECT_EQ(OCSP_check_nonce(ocspRequest.get(), basicResponse.get()),
              t.nonce_check_status);
  } else {
    // OpenSSL's implementation of |OCSP_copy_nonce| keeps the original nonce in
    // |resp| at the start of the list. We have to remove the old nonce prior to
    // copying the new one over.
    int resp_idx = OCSP_BASICRESP_get_ext_by_NID(basicResponse.get(),
                                                 NID_id_pkix_OCSP_Nonce, -1);
    if (resp_idx >= 0) {
      bssl::UniquePtr<X509_EXTENSION> old_resp_ext(
          OCSP_BASICRESP_delete_ext(basicResponse.get(), resp_idx));
    }
    EXPECT_EQ(OCSP_copy_nonce(basicResponse.get(), ocspRequest.get()), 1);
    EXPECT_EQ(OCSP_check_nonce(ocspRequest.get(), basicResponse.get()),
              OCSP_NONCE_EQUAL);
  }
}

TEST(OCSPTest, OCSPNonce) {
  std::string data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_request_no_nonce.der").c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);

  // Adding a nonce but using 0 to trigger the default specified length
  // should fail. A length must be specified when adding a specified nonce.
  EXPECT_FALSE(
      OCSP_request_add1_nonce(ocspRequest.get(), ocsp_response_nonce, 0));

  // Adding a random nonce with the default length should succeed.
  // |OCSP_REQUEST_get_ext_by_NID| returns a negative number if a nonce does
  // not exist.
  EXPECT_LT(OCSP_REQUEST_get_ext_by_NID(ocspRequest.get(),
                                        NID_id_pkix_OCSP_Nonce, -1),
            0);
  EXPECT_TRUE(OCSP_request_add1_nonce(ocspRequest.get(), nullptr, 0));
  EXPECT_GE(OCSP_REQUEST_get_ext_by_NID(ocspRequest.get(),
                                        NID_id_pkix_OCSP_Nonce, -1),
            0);

  // Same tests as above, but against an |OCSP_BASICRESP|.
  data = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response_no_nonce.der").c_str());
  std::vector<uint8_t> ocsp_response_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse =
      LoadOCSP_RESPONSE(ocsp_response_data);
  ASSERT_TRUE(ocspResponse);
  bssl::UniquePtr<OCSP_BASICRESP> basicResponse(
      OCSP_response_get1_basic(ocspResponse.get()));
  ASSERT_TRUE(basicResponse);

  EXPECT_FALSE(
      OCSP_basic_add1_nonce(basicResponse.get(), ocsp_response_nonce, 0));

  // Adding a random nonce with the default length should succeed.
  // |OCSP_BASICRESP_get_ext_by_NID| returns a negative number if a nonce does
  // not exist.
  // Add a random nonce with a specified length this time around.
  EXPECT_LT(OCSP_BASICRESP_get_ext_by_NID(basicResponse.get(),
                                          NID_id_pkix_OCSP_Nonce, -1),
            0);
  EXPECT_TRUE(OCSP_basic_add1_nonce(basicResponse.get(), nullptr, 10));
  EXPECT_GE(OCSP_BASICRESP_get_ext_by_NID(basicResponse.get(),
                                          NID_id_pkix_OCSP_Nonce, -1),
            0);
}

TEST(OCSPTest, OCSPCRLString) {
  for (int reason_code = 0; reason_code < 11; reason_code++) {
    if (reason_code == 7) {
      // Reason Code 7 is not used.
      EXPECT_EQ("(UNKNOWN)", std::string(OCSP_crl_reason_str(7)));
      continue;
    }
    EXPECT_NE("(UNKNOWN)", std::string(OCSP_crl_reason_str(reason_code)));
  }
  // More unexpected cases.
  EXPECT_EQ("(UNKNOWN)", std::string(OCSP_crl_reason_str(100)));
  EXPECT_EQ("(UNKNOWN)", std::string(OCSP_crl_reason_str(-1)));
  EXPECT_EQ("(UNKNOWN)", std::string(OCSP_crl_reason_str(-100)));
}

TEST(OCSPTest, OCSPBIOTest) {
  std::string reqData =
      GetTestData(std::string("crypto/ocsp/test/aws/ocsp_request.der").c_str());
  std::vector<uint8_t> ocsp_request_data(reqData.begin(), reqData.end());
  std::string respData = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());

  // Write an OCSP response into the BIO.
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  int respLen = (int)ocsp_response_data.size();
  ASSERT_EQ(BIO_write(bio.get(), ocsp_response_data.data(), respLen), respLen);
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse(
      d2i_OCSP_RESPONSE_bio(bio.get(), nullptr));
  EXPECT_TRUE(ocspResponse);

  // Reserialize the OCSP response.
  EXPECT_TRUE(i2d_OCSP_RESPONSE_bio(bio.get(), ocspResponse.get()));
  const uint8_t *bio_data;
  size_t bio_len;
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_data, &bio_len));
  EXPECT_EQ(Bytes(bio_data, bio_len),
            Bytes(ocsp_response_data.data(), respLen));

  // Write an OCSP request into the BIO, but it shouldn't successfully parse
  // with |d2i_OCSP_RESPONSE_bio|.
  BIO_reset(bio.get());
  const int reqLen = (int)ocsp_request_data.size();
  ASSERT_EQ(BIO_write(bio.get(), ocsp_request_data.data(), reqLen), reqLen);
  ocspResponse.reset(d2i_OCSP_RESPONSE_bio(bio.get(), nullptr));
  EXPECT_FALSE(ocspResponse);

  // Write an OCSP request into the BIO.
  bio.reset(BIO_new(BIO_s_mem()));
  ASSERT_EQ(BIO_write(bio.get(), ocsp_request_data.data(), reqLen), reqLen);
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest(
      d2i_OCSP_REQUEST_bio(bio.get(), nullptr));
  EXPECT_TRUE(ocspRequest);

  // Reserialize the OCSP request.
  EXPECT_TRUE(i2d_OCSP_REQUEST_bio(bio.get(), ocspRequest.get()));
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_data, &bio_len));
  EXPECT_EQ(Bytes(bio_data, bio_len), Bytes(ocsp_request_data.data(), reqLen));

  // Write an OCSP response into the BIO, but it shouldn't successfully parse
  // with |d2i_OCSP_REQUEST_bio|.
  BIO_reset(bio.get());
  ASSERT_EQ(BIO_write(bio.get(), ocsp_response_data.data(), respLen), respLen);
  ocspRequest.reset(d2i_OCSP_REQUEST_bio(bio.get(), nullptr));
  EXPECT_FALSE(ocspRequest);
}

TEST(OCSPTest, CertIDDup) {
  bssl::UniquePtr<X509> issuer(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  bssl::UniquePtr<X509> subject(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/rsa_cert.pem").c_str())
          .c_str()));

  // Create a sample OCSP_CERTID structure
  bssl::UniquePtr<OCSP_CERTID> orig_id(
      OCSP_cert_to_id(EVP_sha256(), subject.get(), issuer.get()));
  ASSERT_TRUE(orig_id);

  // Duplicate the OCSP_CERTID structure
  bssl::UniquePtr<OCSP_CERTID> dup_id(OCSP_CERTID_dup(orig_id.get()));
  ASSERT_TRUE(dup_id);

  // Check that the duplicated structure has the same values as the original.
  EXPECT_EQ(
      ASN1_INTEGER_cmp(orig_id.get()->serialNumber, dup_id.get()->serialNumber),
      0);
  EXPECT_EQ(ASN1_STRING_cmp(orig_id.get()->issuerNameHash,
                            dup_id.get()->issuerNameHash),
            0);
  EXPECT_EQ(ASN1_STRING_cmp(orig_id.get()->issuerKeyHash,
                            dup_id.get()->issuerKeyHash),
            0);
  EXPECT_EQ(
      X509_ALGOR_cmp(orig_id.get()->hashAlgorithm, dup_id.get()->hashAlgorithm),
      0);
  // Check that the duplicated structure is not just a replicated pointer.
  EXPECT_NE(orig_id.get(), dup_id.get());
}

TEST(OCSPTest, OCSPResponsePrint) {
  static const std::array<std::string, 19> kExpected{
      {"OCSP Response Data:", "    OCSP Response Status: successful (0x0)",
       "    Response Type: Basic OCSP Response", "    Version: 1 (0x0)",
       "    Responder Id: C = US, ST = WA, O = s2n, OU = s2n Test OCSP, CN = "
       "ocsp.s2ntest.com",
       "    Produced At: May 26 00:23:34 2021 GMT",
       "    Responses:", "    Certificate ID:", "      Hash Algorithm: sha1",
       "      Issuer Name Hash: DE7932B3217E48FB4E47AE0B9007A55376AE44CA",
       "      Issuer Key Hash: 12DF817571CA92D3CE1B2C2B773B9E3377F3F76F",
       "      Serial Number: 7778", "    Cert Status: good",
       "    This Update: May 26 00:23:34 2021 GMT",
       "    Next Update: May 24 00:23:34 2031 GMT", "",
       "    Response Extensions:", "        OCSP Nonce: ",
       "            0410AFABD4EC6A172C4A98FB1A6D22FF2928"}};

  std::string respData = GetTestData(
      std::string("crypto/ocsp/test/aws/ocsp_response.der").c_str());
  std::vector<uint8_t> ocsp_response_data(respData.begin(), respData.end());
  bssl::UniquePtr<OCSP_RESPONSE> ocspResponse =
      LoadOCSP_RESPONSE(ocsp_response_data);

  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(OCSP_RESPONSE_print(bio.get(), ocspResponse.get(), 0));
  const uint8_t *out;
  size_t outlen;
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &out, &outlen));

  // Iterate through |kExpected| and verify that |OCSP_RESPONSE_print| has
  // the expected format.
  std::istringstream iss((std::string((char *)out, outlen)));
  std::string line;
  for (const auto &expected : kExpected) {
    std::getline(iss, line);
    EXPECT_EQ(line, expected);
  }
}

TEST(OCSPTest, OCSPRequestPrint) {
  static const std::array<std::string, 11> kExpected{
      {"OCSP Request Data:", "    Version: 1 (0x0)", "    Requestor List:",
       "        Certificate ID:", "          Hash Algorithm: sha1",
       "          Issuer Name Hash: DE7932B3217E48FB4E47AE0B9007A55376AE44CA",
       "          Issuer Key Hash: 12DF817571CA92D3CE1B2C2B773B9E3377F3F76F",
       "          Serial Number: 7778",
       "    Request Extensions:", "        OCSP Nonce: ",
       "            0410303F128CD824A2B465F4C846882B3E1F"}};

  std::string data =
      GetTestData(std::string("crypto/ocsp/test/aws/ocsp_request.der").c_str());
  std::vector<uint8_t> ocsp_request_data(data.begin(), data.end());
  bssl::UniquePtr<OCSP_REQUEST> ocspRequest =
      LoadOCSP_REQUEST(ocsp_request_data);

  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(OCSP_REQUEST_print(bio.get(), ocspRequest.get(), 0));
  const uint8_t *out;
  size_t outlen;
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &out, &outlen));

  // Iterate through |kExpected| and verify that |OCSP_REQUEST_print| has
  // the expected format.
  std::istringstream iss((std::string((char *)out, outlen)));
  std::string line;
  for (const auto &expected : kExpected) {
    std::getline(iss, line);
    EXPECT_EQ(line, expected);
  }
}

TEST(OCSPTest, OCSPUtilityFunctions) {
  // Create new OCSP_CERTID
  OCSP_CERTID *cert_id = OCSP_CERTID_new();
  ASSERT_TRUE(cert_id);

  bssl::UniquePtr<OCSP_REQUEST> request(OCSP_REQUEST_new());
  ASSERT_TRUE(request);

  // Test that an |OCSP_ONEREQ| does not exist yet.
  EXPECT_EQ(OCSP_request_onereq_count(request.get()), 0);
  EXPECT_FALSE(OCSP_request_onereq_get0(request.get(), 0));

  OCSP_ONEREQ *one = OCSP_request_add0_id(request.get(), cert_id);
  ASSERT_TRUE(one);
  EXPECT_EQ(OCSP_request_onereq_count(request.get()), 1);
  EXPECT_TRUE(OCSP_request_onereq_get0(request.get(), 0));

  // Call function to get OCSP_CERTID
  OCSP_CERTID *returned_id = OCSP_onereq_get0_id(one);

  // Verify the returned OCSP_CERTID is same as the one set
  ASSERT_EQ(returned_id, cert_id);
}

TEST(OCSPTest, OCSP_SINGLERESP) {
  bssl::UniquePtr<OCSP_SINGLERESP> single_resp(OCSP_SINGLERESP_new());
  ASSERT_TRUE(single_resp);

  // Initialize an |X509_EXTENSION| for testing.
  bssl::UniquePtr<ASN1_OCTET_STRING> ext_oct(ASN1_OCTET_STRING_new());
  const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
  ASSERT_TRUE(ASN1_OCTET_STRING_set(ext_oct.get(), data, sizeof(data)));
  bssl::UniquePtr<X509_EXTENSION> ext(X509_EXTENSION_create_by_NID(
      nullptr, NID_id_pkix_OCSP_CrlID, 0, ext_oct.get()));
  ASSERT_TRUE(ext);

  // Test |X509_EXTENSION|s work with |OCSP_SINGLERESP|.
  EXPECT_TRUE(OCSP_SINGLERESP_add_ext(single_resp.get(), ext.get(), -1));
  EXPECT_EQ(OCSP_SINGLERESP_get_ext_count(single_resp.get()), 1);
  X509_EXTENSION *retrieved_ext = OCSP_SINGLERESP_get_ext(single_resp.get(), 0);
  ASSERT_EQ(ASN1_OCTET_STRING_cmp(X509_EXTENSION_get_data(retrieved_ext),
                                  X509_EXTENSION_get_data(ext.get())),
            0);
}
