Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/gtests/ssl_gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 117 kB image not shown  

Quelle  tls_ech_unittest.cc   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "secerr.h"
#include "ssl.h"

#include "gtest_utils.h"
#include "pk11pub.h"
#include "tls_agent.h"
#include "tls_connect.h"
#include "util.h"
#include "tls13ech.h"

namespace nss_test {

class TlsAgentEchTest : public TlsAgentStreamTestClient13 {
 protected:
  void InstallEchConfig(const DataBuffer& echconfig, PRErrorCode err = 0) {
    SECStatus rv = SSL_SetClientEchConfigs(agent_->ssl_fd(), echconfig.data(),
                                           echconfig.len());
    if (err == 0) {
      ASSERT_EQ(SECSuccess, rv);
    } else {
      ASSERT_EQ(SECFailure, rv);
      ASSERT_EQ(err, PORT_GetError());
    }
  }
};

#include "cpputil.h"  // Unused function error if included without HPKE.

static std::string kPublicName("public.name");

static const std::vector<HpkeSymmetricSuite> kDefaultSuites = {
    {HpkeKdfHkdfSha256, HpkeAeadChaCha20Poly1305},
    {HpkeKdfHkdfSha256, HpkeAeadAes128Gcm}};
static const std::vector<HpkeSymmetricSuite> kSuiteChaCha = {
    {HpkeKdfHkdfSha256, HpkeAeadChaCha20Poly1305}};
static const std::vector<HpkeSymmetricSuite> kSuiteAes = {
    {HpkeKdfHkdfSha256, HpkeAeadAes128Gcm}};
std::vector<HpkeSymmetricSuite> kBogusSuite = {
    {static_cast<HpkeKdfId>(0xfefe), static_cast<HpkeAeadId>(0xfefe)}};
static const std::vector<HpkeSymmetricSuite> kUnknownFirstSuite = {
    {static_cast<HpkeKdfId>(0xfefe), static_cast<HpkeAeadId>(0xfefe)},
    {HpkeKdfHkdfSha256, HpkeAeadAes128Gcm}};

class TlsConnectStreamTls13Ech : public TlsConnectTestBase {
 public:
  TlsConnectStreamTls13Ech()
      : TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}

  void ReplayChWithMalformedInner(const std::string& ch, uint8_t server_alert,
                                  uint32_t server_code, uint32_t client_code) {
    std::vector<uint8_t> ch_vec = hex_string_to_bytes(ch);
    DataBuffer ch_buf;
    ScopedSECKEYPublicKey pub;
    ScopedSECKEYPrivateKey priv;
    EnsureTlsSetup();
    ImportFixedEchKeypair(pub, priv);
    SetMutualEchConfigs(pub, priv);

    TlsAgentTestBase::MakeRecord(variant_, ssl_ct_handshake,
                                 SSL_LIBRARY_VERSION_TLS_1_3, ch_vec.data(),
                                 ch_vec.size(), &ch_buf, 0);
    StartConnect();
    client_->SendDirect(ch_buf);
    ExpectAlert(server_, server_alert);
    server_->Handshake();
    server_->CheckErrorCode(server_code);
    client_->ExpectReceiveAlert(server_alert, kTlsAlertFatal);
    client_->Handshake();
    client_->CheckErrorCode(client_code);
  }

  // Setup Client/Server with mismatched AEADs
  void SetupForEchRetry() {
    ScopedSECKEYPublicKey server_pub;
    ScopedSECKEYPrivateKey server_priv;
    ScopedSECKEYPublicKey client_pub;
    ScopedSECKEYPrivateKey client_priv;
    DataBuffer server_rec;
    DataBuffer client_rec;
    TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteChaCha,
                                          kPublicName, 100, server_rec,
                                          server_pub, server_priv);
    ASSERT_EQ(SECSuccess,
              SSL_SetServerEchConfigs(server_->ssl_fd(), server_pub.get(),
                                      server_priv.get(), server_rec.data(),
                                      server_rec.len()));

    TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                          kPublicName, 100, client_rec,
                                          client_pub, client_priv);
    ASSERT_EQ(SECSuccess,
              SSL_SetClientEchConfigs(client_->ssl_fd(), client_rec.data(),
                                      client_rec.len()));
  }

  // Parse a captured SNI extension and validate the contained name.
  void CheckSniExtension(const DataBuffer& data,
                         const std::string expected_name) {
    TlsParser parser(data.data(), data.len());
    uint32_t tmp;
    ASSERT_TRUE(parser.Read(&tmp, 2));
    ASSERT_EQ(parser.remaining(), tmp);
    ASSERT_TRUE(parser.Read(&tmp, 1));
    ASSERT_EQ(0U, tmp); /* sni_nametype_hostname */
    DataBuffer name;
    ASSERT_TRUE(parser.ReadVariable(&name, 2));
    ASSERT_EQ(0U, parser.remaining());
    // Manual comparison to silence coverity false-positives.
    ASSERT_EQ(name.len(), kPublicName.length());
    ASSERT_EQ(0,
              memcmp(kPublicName.c_str(), name.data(), kPublicName.length()));
  }

  void DoEchRetry(const ScopedSECKEYPublicKey& server_pub,
                  const ScopedSECKEYPrivateKey& server_priv,
                  const DataBuffer& server_rec) {
    StackSECItem retry_configs;
    ASSERT_EQ(SECSuccess,
              SSL_GetEchRetryConfigs(client_->ssl_fd(), &retry_configs));
    ASSERT_NE(0U, retry_configs.len);

    // Reset expectations for the TlsAgent dtor.
    server_->ExpectReceiveAlert(kTlsAlertCloseNotify, kTlsAlertWarning);
    Reset();
    EnsureTlsSetup();
    ASSERT_EQ(SECSuccess,
              SSL_SetServerEchConfigs(server_->ssl_fd(), server_pub.get(),
                                      server_priv.get(), server_rec.data(),
                                      server_rec.len()));
    ASSERT_EQ(SECSuccess,
              SSL_SetClientEchConfigs(client_->ssl_fd(), retry_configs.data,
                                      retry_configs.len));
    client_->ExpectEch();
    server_->ExpectEch();
    Connect();
  }

  void ImportFixedEchKeypair(ScopedSECKEYPublicKey& pub,
                             ScopedSECKEYPrivateKey& priv) {
    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    if (!slot) {
      ADD_FAILURE() << "No slot";
      return;
    }
    std::vector<uint8_t> pkcs8_r = hex_string_to_bytes(kFixedServerKey);
    SECItem pkcs8_r_item = {siBuffer, toUcharPtr(pkcs8_r.data()),
                            static_cast<unsigned int>(pkcs8_r.size())};

    SECKEYPrivateKey* tmp_priv = nullptr;
    ASSERT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey(
                              slot.get(), &pkcs8_r_item, nullptr, nullptr,
                              falsefalse, KU_ALL, &tmp_priv, nullptr));
    priv.reset(tmp_priv);
    SECKEYPublicKey* tmp_pub = SECKEY_ConvertToPublicKey(tmp_priv);
    pub.reset(tmp_pub);
    ASSERT_NE(nullptr, tmp_pub);
  }

  void SetMutualEchConfigs(ScopedSECKEYPublicKey& pub,
                           ScopedSECKEYPrivateKey& priv) {
    DataBuffer echconfig;
    TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                          kPublicName, 100, echconfig, pub,
                                          priv);
    ASSERT_EQ(SECSuccess,
              SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                      echconfig.data(), echconfig.len()));
    ASSERT_EQ(SECSuccess,
              SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
                                      echconfig.len()));
  }

  void ValidatePublicNames(const std::vector<std::string>& names,
                           SECStatus expected) {
    static const std::vector<HpkeSymmetricSuite> kSuites = {
        {HpkeKdfHkdfSha256, HpkeAeadAes128Gcm}};

    ScopedSECItem ecParams = MakeEcKeyParams(ssl_grp_ec_curve25519);
    ScopedSECKEYPublicKey pub;
    ScopedSECKEYPrivateKey priv;
    SECKEYPublicKey* pub_p = nullptr;
    SECKEYPrivateKey* priv_p =
        SECKEY_CreateECPrivateKey(ecParams.get(), &pub_p, nullptr);
    pub.reset(pub_p);
    priv.reset(priv_p);
    ASSERT_TRUE(!!pub);
    ASSERT_TRUE(!!priv);

    EnsureTlsSetup();

    DataBuffer cfg;
    SECStatus rv;
    for (auto name : names) {
      if (g_ssl_gtest_verbose) {
        std::cout << ((expected == SECFailure) ? "in" : "")
                  << "valid public_name: " << name << std::endl;
      }
      GenerateEchConfig(HpkeDhKemX25519Sha256, kSuites, name, 100, cfg, pub,
                        priv);

      rv = SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                   cfg.data(), cfg.len());
      EXPECT_EQ(expected, rv);

      rv = SSL_SetClientEchConfigs(client_->ssl_fd(), cfg.data(), cfg.len());
      EXPECT_EQ(expected, rv);
    }
  }

 private:
  // Testing certan invalid CHInner configurations is tricky, particularly
  // since the CHOuter forms AAD and isn't available in filters. Instead of
  // generating these inputs on the fly, use a fixed server keypair so that
  // the input can be generated once (e.g. via a debugger) and replayed in
  // each invocation of the test.
  std::string kFixedServerKey =
      "3067020100301406072a8648ce3d020106092b06010401da470f01044c304a"
      "02010104205a8aa0d2476b28521588e0c704b14db82cdd4970d340d293a957"
      "6deaee9ec1c7a1230321008756e2580c07c1d2ffcb662f5fadc6d6ff13da85"
      "abd7adfecf984aaa102c1269";
};

static void CheckCertVerifyPublicName(TlsAgent* agent) {
  agent->UpdatePreliminaryChannelInfo();
  EXPECT_NE(0U, (agent->pre_info().valuesSet & ssl_preinfo_ech));
  EXPECT_EQ(agent->GetEchExpected(), agent->pre_info().echAccepted);

  // Check that echPublicName is only exposed in the rejection
  // case, so that the application can use it for CertVerfiy.
  if (agent->GetEchExpected()) {
    EXPECT_EQ(nullptr, agent->pre_info().echPublicName);
  } else {
    EXPECT_NE(nullptr, agent->pre_info().echPublicName);
    if (agent->pre_info().echPublicName) {
      EXPECT_EQ(0,
                strcmp(kPublicName.c_str(), agent->pre_info().echPublicName));
    }
  }
}

static SECStatus AuthCompleteFail(TlsAgent* agent, PRBool, PRBool) {
  CheckCertVerifyPublicName(agent);
  return SECFailure;
}

// Given two EchConfigList structures, e.g. from GenerateEchConfig, construct
// a single list containing all entries.
static DataBuffer MakeEchConfigList(DataBuffer config1, DataBuffer config2) {
  DataBuffer sizedConfigListBuffer;

  sizedConfigListBuffer.Write(2, config1.data() + 2, config1.len() - 2);
  sizedConfigListBuffer.Write(sizedConfigListBuffer.len(), config2.data() + 2,
                              config2.len() - 2);
  sizedConfigListBuffer.Write(0, sizedConfigListBuffer.len() - 2, 2);

  PR_ASSERT(sizedConfigListBuffer.len() == config1.len() + config2.len() - 2);
  return sizedConfigListBuffer;
}

TEST_P(TlsAgentEchTest, EchConfigsSupportedYesNo) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  // ECHConfig 2 cipher_suites are unsupported.
  DataBuffer config1;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config1, pub, priv);
  DataBuffer config2;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
                                        kPublicName, 100, config2, pub, priv);
  EnsureInit();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE

  DataBuffer sizedConfigListBuffer = MakeEchConfigList(config1, config2);
  InstallEchConfig(sizedConfigListBuffer, 0);
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_TRUE(filter->captured());
}

TEST_P(TlsAgentEchTest, EchConfigsSupportedNoYes) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer config2;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config2, pub, priv);
  DataBuffer config1;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
                                        kPublicName, 100, config1, pub, priv);
  // ECHConfig 1 cipher_suites are unsupported.
  DataBuffer sizedConfigListBuffer = MakeEchConfigList(config1, config2);
  EnsureInit();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  InstallEchConfig(sizedConfigListBuffer, 0);
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_TRUE(filter->captured());
}

TEST_P(TlsAgentEchTest, EchConfigsSupportedNoNo) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer config2;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
                                        kPublicName, 100, config2, pub, priv);
  DataBuffer config1;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
                                        kPublicName, 100, config1, pub, priv);
  // ECHConfig 1 and 2 cipher_suites are unsupported.
  DataBuffer sizedConfigListBuffer = MakeEchConfigList(config1, config2);
  EnsureInit();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  InstallEchConfig(sizedConfigListBuffer, SEC_ERROR_INVALID_ARGS);
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, ShortEchConfig) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  echconfig.Truncate(echconfig.len() - 1);
  InstallEchConfig(echconfig, SEC_ERROR_BAD_DATA);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, LongEchConfig) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  echconfig.Write(echconfig.len(), 1, 1);  // Append one byte
  InstallEchConfig(echconfig, SEC_ERROR_BAD_DATA);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, UnsupportedEchConfigVersion) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  static const uint8_t bad_version[] = {0xff, 0xff};
  DataBuffer bad_ver_buf(bad_version, sizeof(bad_version));
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  echconfig.Splice(bad_ver_buf, 2, 2);
  InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, UnsupportedHpkeKem) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  // SSL_EncodeEchConfigId encodes without validation.
  TlsConnectTestBase::GenerateEchConfig(static_cast<HpkeKemId>(0xff),
                                        kDefaultSuites, kPublicName, 100,
                                        echconfig, pub, priv);
  InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, EchRejectIgnoreAllUnknownSuites) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite,
                                        kPublicName, 100, echconfig, pub, priv);
  InstallEchConfig(echconfig, SEC_ERROR_INVALID_ARGS);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, EchConfigRejectEmptyPublicName) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kBogusSuite, "",
                                        100, echconfig, pub, priv);
  InstallEchConfig(echconfig, SSL_ERROR_RX_MALFORMED_ECH_CONFIG);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_FALSE(filter->captured());
}

TEST_F(TlsConnectStreamTls13, EchAcceptIgnoreSingleUnknownSuite) {
  EnsureTlsSetup();
  DataBuffer echconfig;
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256,
                                        kUnknownFirstSuite, kPublicName, 100,
                                        echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
                                    echconfig.len()));
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));

  client_->ExpectEch();
  server_->ExpectEch();
  Connect();
}

TEST_P(TlsAgentEchTest, ApiInvalidArgs) {
  EnsureInit();
  // SetClient
  EXPECT_EQ(SECFailure, SSL_SetClientEchConfigs(agent_->ssl_fd(), nullptr, 1));

  EXPECT_EQ(SECFailure,
            SSL_SetClientEchConfigs(agent_->ssl_fd(),
                                    reinterpret_cast<const uint8_t*>(1), 0));

  // SetServer
  EXPECT_EQ(SECFailure,
            SSL_SetServerEchConfigs(agent_->ssl_fd(), nullptr,
                                    reinterpret_cast<SECKEYPrivateKey*>(1),
                                    reinterpret_cast<const uint8_t*>(1), 1));
  EXPECT_EQ(SECFailure,
            SSL_SetServerEchConfigs(
                agent_->ssl_fd(), reinterpret_cast<SECKEYPublicKey*>(1),
                nullptr, reinterpret_cast<const uint8_t*>(1), 1));
  EXPECT_EQ(SECFailure,
            SSL_SetServerEchConfigs(
                agent_->ssl_fd(), reinterpret_cast<SECKEYPublicKey*>(1),
                reinterpret_cast<SECKEYPrivateKey*>(1), nullptr, 1));
  EXPECT_EQ(SECFailure,
            SSL_SetServerEchConfigs(agent_->ssl_fd(),
                                    reinterpret_cast<SECKEYPublicKey*>(1),
                                    reinterpret_cast<SECKEYPrivateKey*>(1),
                                    reinterpret_cast<const uint8_t*>(1), 0));

  // GetRetries
  EXPECT_EQ(SECFailure, SSL_GetEchRetryConfigs(agent_->ssl_fd(), nullptr));

  // EncodeEchConfigId
  EXPECT_EQ(SECFailure,
            SSL_EncodeEchConfigId(0, nullptr, 1, static_cast<HpkeKemId>(1),
                                  reinterpret_cast<SECKEYPublicKey*>(1),
                                  reinterpret_cast<HpkeSymmetricSuite*>(1), 1,
                                  reinterpret_cast<uint8_t*>(1),
                                  reinterpret_cast<unsigned int*>(1), 1));

  EXPECT_EQ(SECFailure,
            SSL_EncodeEchConfigId(0, "name", 1, static_cast<HpkeKemId>(1),
                                  reinterpret_cast<SECKEYPublicKey*>(1),
                                  nullptr, 1, reinterpret_cast<uint8_t*>(1),
                                  reinterpret_cast<unsigned int*>(1), 1));
  EXPECT_EQ(SECFailure,
            SSL_EncodeEchConfigId(0, "name", 1, static_cast<HpkeKemId>(1),
                                  reinterpret_cast<SECKEYPublicKey*>(1),
                                  reinterpret_cast<HpkeSymmetricSuite*>(1), 0,
                                  reinterpret_cast<uint8_t*>(1),
                                  reinterpret_cast<unsigned int*>(1), 1));

  EXPECT_EQ(SECFailure, SSL_EncodeEchConfigId(
                            0, "name", 1, static_cast<HpkeKemId>(1), nullptr,
                            reinterpret_cast<HpkeSymmetricSuite*>(1), 1,
                            reinterpret_cast<uint8_t*>(1),
                            reinterpret_cast<unsigned int*>(1), 1));

  EXPECT_EQ(SECFailure,
            SSL_EncodeEchConfigId(0, nullptr, 0, static_cast<HpkeKemId>(1),
                                  reinterpret_cast<SECKEYPublicKey*>(1),
                                  reinterpret_cast<HpkeSymmetricSuite*>(1), 1,
                                  reinterpret_cast<uint8_t*>(1),
                                  reinterpret_cast<unsigned int*>(1), 1));

  EXPECT_EQ(SECFailure, SSL_EncodeEchConfigId(
                            0, "name", 1, static_cast<HpkeKemId>(1),
                            reinterpret_cast<SECKEYPublicKey*>(1),
                            reinterpret_cast<HpkeSymmetricSuite*>(1), 1,
                            nullptr, reinterpret_cast<unsigned int*>(1), 1));

  EXPECT_EQ(SECFailure,
            SSL_EncodeEchConfigId(0, "name", 1, static_cast<HpkeKemId>(1),
                                  reinterpret_cast<SECKEYPublicKey*>(1),
                                  reinterpret_cast<HpkeSymmetricSuite*>(1), 1,
                                  reinterpret_cast<uint8_t*>(1), nullptr, 1));
}

TEST_P(TlsAgentEchTest, NoEarlyRetryConfigs) {
  EnsureInit();
  StackSECItem retry_configs;
  EXPECT_EQ(SECFailure,
            SSL_GetEchRetryConfigs(agent_->ssl_fd(), &retry_configs));
  EXPECT_EQ(SSL_ERROR_HANDSHAKE_NOT_COMPLETED, PORT_GetError());

  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  InstallEchConfig(echconfig, 0);

  EXPECT_EQ(SECFailure,
            SSL_GetEchRetryConfigs(agent_->ssl_fd(), &retry_configs));
  EXPECT_EQ(SSL_ERROR_HANDSHAKE_NOT_COMPLETED, PORT_GetError());
}

TEST_P(TlsAgentEchTest, NoSniSoNoEch) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  SSL_SetURL(agent_->ssl_fd(), "");
  InstallEchConfig(echconfig, 0);
  SSL_SetURL(agent_->ssl_fd(), "");
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, NoEchConfigSoNoEch) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_FALSE(filter->captured());
}

TEST_P(TlsAgentEchTest, EchConfigDuplicateExtensions) {
  EnsureInit();
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);

  static const uint8_t duped_xtn[] = {0x00, 0x08, 0x00, 0x01, 0x00,
                                      0x00, 0x00, 0x01, 0x00, 0x00};
  DataBuffer buf(duped_xtn, sizeof(duped_xtn));
  echconfig.Truncate(echconfig.len() - 2);
  echconfig.Append(buf);
  uint32_t len;
  ASSERT_TRUE(echconfig.Read(0, 2, &len));
  len += buf.len() - 2;
  DataBuffer new_len;
  ASSERT_TRUE(new_len.Write(0, len, 2));
  echconfig.Splice(new_len, 0, 2);
  new_len.Truncate(0);

  ASSERT_TRUE(echconfig.Read(4, 2, &len));
  len += buf.len() - 2;
  ASSERT_TRUE(new_len.Write(0, len, 2));
  echconfig.Splice(new_len, 4, 2);

  InstallEchConfig(echconfig, SEC_ERROR_EXTENSION_VALUE_INVALID);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(agent_->ssl_fd(),
                                                 PR_FALSE));  // Don't GREASE
  auto filter = MakeTlsFilter<TlsExtensionCapture>(
      agent_, ssl_tls13_encrypted_client_hello_xtn);
  agent_->Handshake();
  ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
  ASSERT_FALSE(filter->captured());
}

TEST_F(TlsConnectStreamTls13Ech, EchFixedConfig) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  EnsureTlsSetup();
  ImportFixedEchKeypair(pub, priv);
  SetMutualEchConfigs(pub, priv);

  client_->ExpectEch();
  server_->ExpectEch();
  Connect();
}

// The next set of tests all use a fixed server key and a pre-built ClientHello.
// This ClientHelo can be constructed using the above EchFixedConfig test,
// modifying tls13_ConstructInnerExtensionsFromOuter as indicated.  For this
// small number of tests, these fixed values are easier to construct than
// constructing ClientHello in the test that can be successfully decrypted.

// Test an encoded ClientHelloInner containing an extra extensionType
// in outer_extensions, for which there is no corresponding (uncompressed)
// extension in ClientHelloOuter.
TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsReferencesMissing) {
  // Construct this by prepending 0xabcd to ssl_tls13_outer_extensions_xtn.
  std::string ch =
      "010001fc030390901d039ca83262d9115a5f98f43ddb2553241a8de5c46d9f118c4c29c2"
      "64bc000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "00206df5f908d1c02320e246694c765d5ec1c0f7d7aef2b1b00b17c36331623d332d002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00209a4f67b0744d1fba23aa4bacfadb2a"
      "c706562dae04d80a83ae668a6f2dd6ef2700cfab1671182341df246d66c3aca873e8c714"
      "bc2b1c3b576653609533c486df0bdcf63ab4e4e7d0b67fadf4e3504eec96f72e6778b15d"
      "69c9a9594a041348a7130f67a1a7cac796a0e6d6fca505438355278a9a8fd55e44218441"
      "9927a1e084ac7d7adeb2f0c19faafba430876bf0cdf4d195b2d06428b3de13120f65748a"
      "468f8997a2c3bf1dd7f3996a0f2c70dea6c88149df182b3c3b78a8da8bb709a9ed9d77c6"
      "5dc09accdfeb66c90db26b99a35052a8cbaf7bb9307a1e17d90a7aa9f768f5f446559d08"
      "69bccc83eda9d2b347a00015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsInsideInner) {
  // Construct this by appending ssl_tls13_outer_extensions_xtn to the
  // references in
  // ssl_tls13_outer_extensions_xtn.
  std::string ch =
      "010001fc03035e2268bc7133079cd33eb088253393e561d80c5ee6f9a238aff022e1e10d"
      "4c82000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "00200e071fd982854d50236ed0e4e7981460840f03d03fd84b44c409fe486203b252002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d002099a032502ea4fd3c85b858ae1c59df"
      "6a374f3698ed6bca188cf75c432c78cf5a00cf28dde32de7ade40abb16d550c1eec3dad4"
      "a03c85efb95ec605837deae92a419285116e5cb8223ea53cff2b605e66f28e96d37e9b4e"
      "3035fb1cfa125fa053d6770091b5731c9fb03e872a82991dfdd24ad8399fcc76db7fadba"
      "029e064beb02c1282684a93e777bcefbca3dd143dfc225d2e65c80dbf3819ebda288e32c"
      "3a1f8a27bb3aa9480dee2a4307073da3e15ee03dba386223d9399ad796af80c646f85406"
      "282c34fd9406d25752087f08140e1be834e8a149f0bebfc2b3db16ccba83c37051e2e75d"
      "e8a4e999ef385c74c96d0015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsDuplicateReference) {
  // Construct this by altering tls13_ConstructInnerExtensionsFromOuter to have
  // each extension inserted in the reference list twice and running the
  // EchFixedConfig test.
  std::string ch =
      "010001fc0303d8717df80286fcd8b4242ed846995c6473e290678231046bb1bfc7848460"
      "b122000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "00206f21d5fdf7bf81943939a03656c1195ad347cec453bf7a16d0773ffef481d22f002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d011900000100034d002027eb9b641ba8ffc3a4028d00d1f5bd"
      "e190736b1ea5a79513dee0a551cc6fe55200efc2ed6bf501f100896eb91221ce512c20c3"
      "c5c110e7be6a5d340854ff5ac0175312631b021fd5a5c9841549989f415c4041a4b384b1"
      "dba1d6b4182cc48904f993a15eab6bf7787b267ca65acef51c019508e0c9b382086a71d8"
      "517cf19644d66d396efc066a4d37916d67b0e5fe08d52dd94d068dd85b9a245aaffac4ff"
      "66d9a5221fd5805473bb7584eb7f218357c00aff890d2f2edf1c092c648c888b5cba1ca6"
      "26817fda7765fcedfbc418b90b1841d878ed443593cafb61fa8fb708c53977615b45f545"
      "2a8236cab3ec121cdc91a2de6a79437cae9d09e781339fddcac005ce62fd65d50e33faa2"
      "2366955a0374001500220000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, EchOuterExtensionsOutOfOrder) {
  // Construct this by altering tls13_ConstructInnerExtensionsFromOuter to leave
  // a gap at the start and insert a 'late' extension there.
  std::string ch =
      "010001fc0303fabff6caf4d8b1eb1db5945c96badefec4b33188b97121e6a206e82b74bd"
      "a855000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "00208fe970fc0c908f0c51734f18467e640df1d45a6ace2948b5c4bf73ee52ab3160002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00203339239f8925c3f9b89f4ced17c3b3"
      "1c649299d7e10b3cdbc115de2a57d90d2200cf006e62866516380e8a16763bee5b2a75a8"
      "74e8698c459f474d0e952c2fd3300bef1decd6f259b8ac2912684ef69b7a7be2520fbf15"
      "5e0c3f88998789976ca1fbcaa40616fc513e3353540db091da76ca98007532974550d3da"
      "aaddb799baf60adbc5800df30e187251427fe9de707d18a270352ee44f6eb37f0d8c72a1"
      "5f9ffb5dd4bbb6045473c8d99b7a5c2c8cc59027f346cbe6ef240d5cf1919f58a998d427"
      "0f8c882d03d22ec4df4079e15a639452ea4c24023f6bcad89566ce6a32b1dad6ddf6b436"
      "3e6759bd48bed1b30a840015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

// Drop supported_versions from CHInner, make sure we don't negotiate 1.2+ECH.
TEST_F(TlsConnectStreamTls13Ech, EchVersion12Inner) {
  // Construct this by removing ssl_tls13_supported_versions_xtn entirely.
  std::string ch =
      "010001fc030338e9ebcde2b87ef779c4d9a9b9870aef3978130b254fbf168a92644c97c1"
      "c5cb000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "002081b3ea444fd631f9264e01276bcc1a6771aed3b5a8a396446467d1c820e52b25002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00205864042b43f4d4d544558fbcba410f"
      "ebfb78ddfc5528672a7f7d9e70abc3eb6300cf6ff3271da628139bddc4a58ee92db26170"
      "7310dee54d88c8a96a8d998b8608d5f10260b7e201e5dc8cafa13917a3fdfdf399082959"
      "8adf3c291decf640f696e64c4e22bafb81565587c50dd829ccad68bd00babeaba7d8a7a5"
      "400ad3200dbae674c549953ca6d3298ed751a9bc215a33be444fe908bf1c6f374cc139f9"
      "98339f58b8fd3510a670e4102e3f7de21586ebd70c3fb1df8bb6b9e5dbc0db147dbac6d0"
      "72dfc6cdf17ecee5c019c311b37ef9f5ceabb7edbdf87a4a04041c4d8b512a16517c5380"
      "e8d4f6e3b2412b4a6c030015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_UNSUPPORTED_VERSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

// Use CHInner supported_versions to negotiate 1.2.
TEST_F(TlsConnectStreamTls13Ech, EchVersion12InnerSupportedVersions) {
  // Construct this by changing ssl_tls13_supported_versions_xtn to write
  // TLS 1.2 instead of TLS 1.3.
  std::string ch =
      "010001fc0303f7146bdc88c399feb49c62b796db2f8b1330e25292a889edf7c65231d0be"
      "b95f000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "0020d31f8eb204efba49dbdbf40bb046b1e0b90fa3f034260d60f351d4b15e614e7f002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d0020eaa25e92721e65fd405577bf2fd322"
      "857e60f8766a595929fc404c9a01ef441200cf04992c693fbc8eac87726b336a11abc411"
      "541ceff50d533d4cf4d6e1078479acb5446675b652f22d6db04daf0c3640ec2429ba4f51"
      "99c00daa43e9a7d85bd6733041feeca0b38ee6ca07042c7e67d40cd3e236499f3f9d92ab"
      "e4642e483c75d77c247b0228bc773c09551d15845c35663afd1805c5b3adb136ffa6d94f"
      "b7cbfe93d5d33c894b2a6437ad9a2278d5863ed20db652a6084c9e95a8dfaf821d0b474a"
      "7efc2839f110edb4a73376ecab629b26b1eea63304899c49a07157fbbee67c786686cb04"
      "a53666a74e1e003aefc70015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertProtocolVersion,
                             SSL_ERROR_UNSUPPORTED_VERSION,
                             SSL_ERROR_PROTOCOL_VERSION_ALERT);
}

// Replay a CH for which CHInner lacks the required ech xtn of inner type
TEST_F(TlsConnectStreamTls13Ech, EchInnerMissing) {
  // Construct by omitting the ech inner extension
  std::string ch =
      "010001fc0303fa9cd9cf5b77bb4083f69a1d169d44b356faea0d6a0aee6d50412de6fef7"
      "8d22000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "0020c329f1dde4d51b50f68c21053b545290b250af527b2832d3acf2c6af9b8b8d5c002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00207e2a0397b7d2776ae468057d630243"
      "b01388cf80680b074323adf4091aba7b4c00cff4b649fb5b3a0719c1e085c7006a95eaad"
      "32375b717a42d009c075e6246342fdc1e847c528495f90378ff5b4912da5190f7e8bfa1c"
      "c9744b50e9e469cd7cd12bcb5f6534b7d617459d2efa4d796ad244567c49f1d22feb08a5"
      "8e8ebdce059c28883dd69ca401e189f3ef438c3f0bf3d377e6727a1f6abf3a8a8cc149ee"
      "60a1aa5ba4a50e99d2519216762558e9613a238bd630b5822f549575d9402f8da066aaef"
      "2e0e6a7a04583b041925e0ef4575107c4436f9af26e561c0ab733cd88bee6a20e6414128"
      "ea0ba1c73612bb62c1e90015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_MISSING_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, EchInnerWrongSize) {
  // Construct by including ech inner with wrong size
  std::string ch =
      "010001fc03035f8410dab9e49b0833d13390f3fe0b3c6321d842961c9cc46b59a0b5b8e1"
      "4e0b000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "0020526a56087d685e574accb0e87d6781bc553612479e56460fe6a497fa1cd74e2e002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00200d096bf6ac0c3bcb79d70677da0e0d"
      "249b40bc5ba6b8727654619fe6567d0b0700cfd13e136d2d041e3cd993b252386d97e98d"
      "c972d29d28e0281a210fa56156b95e4371a6610a0b3e65f1b842875fb456de9b9c0e03f8"
      "aa4d1055057ac3e20e5fa45b837ccbb06ef3856c71f1f63e91b60bfb5f3415f26e9a0d3c"
      "4d404d5d5aaa6dca8d57cf2e6b4aaf399fa7271b0c1eedbfdd85fbc9711b0446eb9c9535"
      "a74f3e5a71e2e22dc8d89980f96233ec9b80fbe4f295ff7903bade407fc544c8d76df4fb"
      "ce4b8d79cea0ff7e0b0736ecbeaf5a146a4f81a930e788ae144cf2219e90dc3594165a7e"
      "2a0b64f6189a87a348840015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertDecodeError,
                             SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION,
                             SSL_ERROR_DECODE_ERROR_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, InnerWithEchAndEchIsInner) {
  // Construct by appending an empty ssl_tls13_encrypted_client_hello_xtn of
  // type outer to
  // CHInner.
  std::string ch =
      "010001fc0303527df5a8dbcf390c184c5274295283fdba78d05784170d8f3cb8c7d84747"
      "afb5000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "002099461dcfcdc7804a0f34bf3ca49ac39776a7ef4d8edd30fab3599ff59b09f826002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00201da1341e8ba21ff90e025d2438d4e5"
      "b4e8b376befc57cf8c9afb484e6f051b2f00cff747491b810705e5cc8d8a1302468000d9"
      "8660d659d8382a6fc23ca1a582def728eabb363771328035565048213b1d725b20f757be"
      "63d6956cd861aa9d33adcc913de2443695f70e130af96fd2b078dd662478a29bd17a4479"
      "715c949b5fc118456d0243c9d1819cecd0f5fbd1c78dadd6fcd09abe41ca97a00c97efb3"
      "894c9d4bab60dcd150b55608f6260723a08e112e39e6a43f645f85a08085054f27f269bc"
      "1acb9ff5007b04eaef3414767666472e4e24c2a2953f5dc68aeb5207d556f1b872a810b6"
      "686cf83a09db8b474df70015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_UNEXPECTED_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13, EchWithInnerExtNotSplit) {
  static uint8_t type_val[1] = {1};
  DataBuffer type_buffer(type_val, sizeof(type_val));

  EnsureTlsSetup();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE));
  MakeTlsFilter<TlsExtensionAppender>(client_, kTlsHandshakeClientHello,
                                      ssl_tls13_encrypted_client_hello_xtn,
                                      type_buffer);
  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
  client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
  server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
}

/* Parameters
 * Length of SNI for first connection
 * Length of SNI for second connection
 * Use GREASE for first connection?
 * Use GREASE for second connection?
 * For both connections, SNI length to pad to.
 */

class EchCHPaddingTest : public TlsConnectStreamTls13,
                         public testing::WithParamInterface<
                             std::tuple<intintboolboolint>> {};

TEST_P(EchCHPaddingTest, EchChPaddingEqual) {
  auto parameters = GetParam();
  std::string name_str1 = std::string(std::get<0>(parameters), 'a');
  std::string name_str2 = std::string(std::get<1>(parameters), 'a');
  const char* name1 = name_str1.c_str();
  const char* name2 = name_str2.c_str();
  bool grease_mode1 = std::get<2>(parameters);
  bool grease_mode2 = std::get<3>(parameters);
  uint8_t max_name_len = std::get<4>(parameters);

  // Connection 1
  EnsureTlsSetup();
  SSL_SetURL(client_->ssl_fd(), name1);
  if (grease_mode1) {
    EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
    EXPECT_EQ(SECSuccess,
              SSL_SetTls13GreaseEchSize(client_->ssl_fd(), max_name_len));
    client_->ExpectEch(false);
    server_->ExpectEch(false);
  } else {
    SetupEch(client_, server_, HpkeDhKemX25519Sha256, truetruetrue,
             max_name_len);
  }
  auto filter1 = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  Connect();
  size_t echXtnLen1 = filter1->extension().len();

  Reset();

  // Connection 2
  EnsureTlsSetup();
  SSL_SetURL(client_->ssl_fd(), name2);
  if (grease_mode2) {
    EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
    EXPECT_EQ(SECSuccess,
              SSL_SetTls13GreaseEchSize(client_->ssl_fd(), max_name_len));
    client_->ExpectEch(false);
    server_->ExpectEch(false);
  } else {
    SetupEch(client_, server_, HpkeDhKemX25519Sha256, truetruetrue,
             max_name_len);
  }
  auto filter2 = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  Connect();
  size_t echXtnLen2 = filter2->extension().len();

  // We always expect an ECH extension.
  ASSERT_TRUE(echXtnLen2 > 0 && echXtnLen1 > 0);
  // We expect the ECH extension to round to the same multiple of 32.
  // Note: It will not be 0 % 32 because we pad the Payload, but have a number
  // of extra bytes from the rest of the ECH extension (e.g. ciphersuite)
  ASSERT_EQ(echXtnLen1 % 32, echXtnLen2 % 32);
  // Both connections should have the same size after padding.
  if (name_str1.size() <= max_name_len && name_str2.size() <= max_name_len) {
    ASSERT_EQ(echXtnLen1, echXtnLen2);
  }
}

#define ECH_PADDING_TEST_INSTANTIATE(name, values)                           \
  INSTANTIATE_TEST_SUITE_P(name, EchCHPaddingTest,                           \
                           testing::Combine(values, values, testing::Bool(), \
                                            testing::Bool(), values))

const int kExtremalSNILengths[] = {1, 128, 255};
const int kNormalSNILengths[] = {17, 24, 100};
const int kLongSNILengths[] = {90, 167, 214};

/* Each invocation with N lengths, results in 4N^3 test cases, so we test
 * 3 lots of (4*3^3) rather than all permutations. */

ECH_PADDING_TEST_INSTANTIATE(extremal, testing::ValuesIn(kExtremalSNILengths));
ECH_PADDING_TEST_INSTANTIATE(normal, testing::ValuesIn(kNormalSNILengths));
ECH_PADDING_TEST_INSTANTIATE(lengthy, testing::ValuesIn(kLongSNILengths));

// Check the server rejects ClientHellos with bad padding
TEST_F(TlsConnectStreamTls13Ech, EchChPaddingChecked) {
  // Generate this string by changing the padding in
  // tls13_GenPaddingClientHelloInner
  std::string ch =
      "010001fc03037473367a6eb6773391081b403908fc0c0026aac706889c59ca694d0c1188"
      "c4b3000006130113031302010001cd00000010000e00000b7075626c69632e6e616d65ff"
      "01000100000a00140012001d00170018001901000101010201030104003300260024001d"
      "0020f7d8ad5fea0165e115e984e11c43f1d8f255bd8f772b893432d8d7721e91785a002b"
      "0003020304000d0018001604030503060302030804080508060401050106010201002d00"
      "020101001c00024001fe0d00f900000100034d00207e0ad8e83f8a9c89e1ae4fd65b8091"
      "01e496bbb5f29ce20b299ce58937e2563300cff471a787585e15ae5aff5e4fee7ec988ba"
      "72f8a95db41e793568b0301d553251f0826dc0c3ff658e4e029ef840ae86fa80af4b11b5"
      "3a33fab99887bf8df18bc87abbb1f578f7964848d91a2023cbe7609fcc31bd721865009c"
      "ad68c09e438d677f7c56af76e62c168bdb373bb88962471dacc4ddf654e435cd903f6555"
      "4c9a93ffd2541cd7bce520e7215d15495184b781ca8c138cedd573fbdef1d40e5de82c33"
      "5c9c43370102ecb0b66dd27efc719a9a54589b6e6b599b1b0146e121eae0ab5b2070c12f"
      "4f4f2b099808294a459f0015004200000000000000000000000000000000000000000000"
      "000000000000000000000000000000000000000000000000000000000000000000000000"
      "0000000000000000";
  ReplayChWithMalformedInner(ch, kTlsAlertIllegalParameter,
                             SSL_ERROR_RX_MALFORMED_ECH_EXTENSION,
                             SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}

TEST_F(TlsConnectStreamTls13Ech, EchConfigList) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  EnsureTlsSetup();

  DataBuffer config1;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config1, pub, priv);
  DataBuffer config2;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config2, pub, priv);
  DataBuffer configList = MakeEchConfigList(config1, config2);
  SECStatus rv =
      SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                              configList.data(), configList.len());
  printf("%u", rv);
  ASSERT_EQ(rv, SECSuccess);
}

TEST_F(TlsConnectStreamTls13Ech, EchConfigsTrialDecrypt) {
  // Apply two ECHConfigs on the server. They are identical with the exception
  // of the public key: the first ECHConfig contains a public key for which we
  // lack the private value. Use an SSLInt function to zero all the config_ids
  // (client and server), then confirm that trial decryption works.
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  EnsureTlsSetup();
  ImportFixedEchKeypair(pub, priv);
  ScopedSECKEYPublicKey pub2;
  ScopedSECKEYPrivateKey priv2;
  DataBuffer config2;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config2, pub, priv);
  DataBuffer config1;
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kSuiteAes,
                                        kPublicName, 100, config1, pub2, priv2);
  // Zero the config id for both, only public key differs.
  config2.Write(7, (uint32_t)0, 1);
  config1.Write(7, (uint32_t)0, 1);
  // Server only knows private key for conf2
  DataBuffer configList = MakeEchConfigList(config1, config2);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    configList.data(), configList.len()));
  ASSERT_EQ(SECSuccess, SSL_SetClientEchConfigs(client_->ssl_fd(),
                                                config2.data(), config2.len()));
  client_->ExpectEch();
  server_->ExpectEch();
  Connect();
}

TEST_F(TlsConnectStreamTls13Ech, EchAcceptBasic) {
  EnsureTlsSetup();
  SetupEch(client_, server_);
  auto c_filter_sni =
      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
  Connect();
  ASSERT_TRUE(c_filter_sni->captured());
  CheckSniExtension(c_filter_sni->extension(), kPublicName);
}

TEST_F(TlsConnectStreamTls13, EchAcceptWithResume) {
  EnsureTlsSetup();
  SetupEch(client_, server_);
  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
  Connect();
  SendReceive();  // Need to read so that we absorb the session ticket.
  CheckKeys();

  Reset();
  EnsureTlsSetup();
  SetupEch(client_, server_);
  ExpectResumption(RESUME_TICKET);
  auto filter =
      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_pre_shared_key_xtn);
  StartConnect();
  Handshake();
  CheckConnected();
  // Make sure that the PSK extension is only in CHInner.
  ASSERT_TRUE(filter->captured());
}

TEST_F(TlsConnectStreamTls13, EchAcceptWithExternalPsk) {
  static const std::string kPskId = "testing123";
  EnsureTlsSetup();
  SetupEch(client_, server_);

  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  ASSERT_TRUE(!!slot);
  ScopedPK11SymKey key(
      PK11_KeyGen(slot.get(), CKM_HKDF_KEY_GEN, nullptr, 16, nullptr));
  ASSERT_TRUE(!!key);
  AddPsk(key, kPskId, ssl_hash_sha256);

  // Not permitted in outer.
  auto filter =
      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_pre_shared_key_xtn);
  StartConnect();
  Handshake();
  CheckConnected();
  SendReceive();
  CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
  // The PSK extension is present in CHOuter.
  ASSERT_TRUE(filter->captured());

  // But the PSK in CHOuter is completely different.
  // (Failure/collision chance means kPskId needs to be longish.)
  uint32_t v = 0;
  ASSERT_TRUE(filter->extension().Read(0, 2, &v));
  ASSERT_EQ(v, kPskId.size() + 2 + 4) << "check size of identities";
  ASSERT_TRUE(filter->extension().Read(2, 2, &v));
  ASSERT_EQ(v, kPskId.size()) << "check size of identity";
  bool different = false;
  for (size_t i = 0; i < kPskId.size(); ++i) {
    ASSERT_TRUE(filter->extension().Read(i + 4, 1, &v));
    different |= v != static_cast<uint8_t>(kPskId[i]);
  }
  ASSERT_TRUE(different);
}

// If an earlier version is negotiated, False Start must be disabled.
TEST_F(TlsConnectStreamTls13, EchDowngradeNoFalseStart) {
  EnsureTlsSetup();
  SetupEch(client_, server_, HpkeDhKemX25519Sha256, falsetruefalse);
  MakeTlsFilter<TlsExtensionDropper>(client_,
                                     ssl_tls13_encrypted_client_hello_xtn);
  client_->EnableFalseStart();
  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                           SSL_LIBRARY_VERSION_TLS_1_3);
  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                           SSL_LIBRARY_VERSION_TLS_1_2);

  StartConnect();
  client_->Handshake();
  server_->Handshake();
  client_->Handshake();
  EXPECT_FALSE(client_->can_falsestart_hook_called());

  // Make sure the write is blocked.
  client_->ExpectReadWriteError();
  client_->SendData(10);
}

SSLHelloRetryRequestAction RetryEchHello(PRBool firstHello,
                                         const PRUint8* clientToken,
                                         unsigned int clientTokenLen,
                                         PRUint8* appToken,
                                         unsigned int* appTokenLen,
                                         unsigned int appTokenMax, void* arg) {
  auto* called = reinterpret_cast<size_t*>(arg);
  ++*called;

  EXPECT_EQ(0U, clientTokenLen);
  return firstHello ? ssl_hello_retry_request : ssl_hello_retry_accept;
}

// Generate HRR on CH1 Inner
TEST_F(TlsConnectStreamTls13, EchAcceptWithHrr) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  ASSERT_EQ(SECSuccess,
            SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
                                    echconfig.len()));
  client_->ExpectEch();
  server_->ExpectEch();

  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));

  auto server_hrr_ech_xtn = MakeTlsFilter<TlsExtensionCapture>(
      server_, ssl_tls13_encrypted_client_hello_xtn);
  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();
  server_->Handshake();
  MakeNewServer();
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  client_->ExpectEch();
  server_->ExpectEch();
  Handshake();
  ASSERT_TRUE(server_hrr_ech_xtn->captured());
  EXPECT_EQ(1U, cb_called);
  CheckConnected();
  SendReceive();
}

TEST_F(TlsConnectStreamTls13Ech, EchGreaseSize) {
  EnsureTlsSetup();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));

  auto greased_ext = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  Connect();
  ASSERT_TRUE(greased_ext->captured());

  Reset();
  EnsureTlsSetup();

  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  ImportFixedEchKeypair(pub, priv);
  SetMutualEchConfigs(pub, priv);

  auto real_ext = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  client_->ExpectEch();
  server_->ExpectEch();
  Connect();

  ASSERT_TRUE(real_ext->captured());
  ASSERT_EQ(real_ext->extension().len(), greased_ext->extension().len());
}

TEST_F(TlsConnectStreamTls13Ech, EchGreaseClientDisable) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  EnsureTlsSetup();
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE));

  auto c_filter_esni = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);

  Connect();
  ASSERT_TRUE(!c_filter_esni->captured());
}

TEST_F(TlsConnectStreamTls13Ech, EchHrrGreaseServerDisable) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(server_->ssl_fd(), PR_FALSE));
  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));

  auto server_hrr_ech_xtn = MakeTlsFilter<TlsExtensionCapture>(
      server_, ssl_tls13_encrypted_client_hello_xtn);
  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();
  server_->Handshake();
  MakeNewServer();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(server_->ssl_fd(), PR_FALSE));
  Handshake();
  ASSERT_TRUE(!server_hrr_ech_xtn->captured());
  EXPECT_EQ(1U, cb_called);
  CheckConnected();
  SendReceive();
}

TEST_F(TlsConnectStreamTls13Ech, EchGreaseSizePsk) {
  // Original connection without ECH
  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
  Connect();
  SendReceive();

  // Resumption with only GREASE
  Reset();
  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
  ExpectResumption(RESUME_TICKET);
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));

  auto greased_ext = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  Connect();
  SendReceive();
  ASSERT_TRUE(greased_ext->captured());

  // Finally, resume with ECH enabled
  // ECH state does not determine whether resumption succeeds
  // or is attempted, so this should work fine.
  Reset();
  ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
  ExpectResumption(RESUME_TICKET, 2);

  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  ImportFixedEchKeypair(pub, priv);
  SetMutualEchConfigs(pub, priv);

  auto real_ext = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  client_->ExpectEch();
  server_->ExpectEch();
  Connect();
  ASSERT_TRUE(real_ext->captured());

  ASSERT_EQ(real_ext->extension().len(), greased_ext->extension().len());
}

// Send GREASE ECH in CH1. CH2 must send exactly the same GREASE ECH contents.
TEST_F(TlsConnectStreamTls13, GreaseEchHrrMatches) {
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));

  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(),
                                                 PR_TRUE));  // GREASE
  auto capture = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);

  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();  // Send CH1
  EXPECT_TRUE(capture->captured());
  DataBuffer ch1_grease = capture->extension();

  server_->Handshake();
  MakeNewServer();
  capture = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);

  EXPECT_FALSE(capture->captured());
  client_->Handshake();  // Send CH2
  EXPECT_TRUE(capture->captured());
  EXPECT_EQ(ch1_grease, capture->extension());

  EXPECT_EQ(1U, cb_called);
  server_->StartConnect();
  Handshake();
  CheckConnected();
}

TEST_F(TlsConnectStreamTls13Ech, EchRejectMisizedEchXtn) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(server_->ssl_fd(), PR_TRUE));
  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));
  auto server_hrr_ext_xtn_fake = MakeTlsFilter<TlsExtensionResizer>(
      server_, ssl_tls13_encrypted_client_hello_xtn, 34);
  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();
  server_->Handshake();
  // Process the hello retry.
  server_->ExpectReceiveAlert(kTlsAlertDecodeError, kTlsAlertFatal);
  client_->ExpectSendAlert(kTlsAlertDecodeError);
  Handshake();
  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_ECH_EXTENSION);
  server_->CheckErrorCode(SSL_ERROR_DECODE_ERROR_ALERT);
  EXPECT_EQ(1U, cb_called);
}

TEST_F(TlsConnectStreamTls13Ech, EchRejectDroppedEchXtn) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  ASSERT_EQ(SECSuccess,
            SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
                                    echconfig.len()));
  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));
  auto server_hrr_ext_xtn_fake = MakeTlsFilter<TlsExtensionDropper>(
      server_, ssl_tls13_encrypted_client_hello_xtn);
  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();
  server_->Handshake();
  MakeNewServer();
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  // Process the hello retry.
  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
  client_->ExpectSendAlert(kTlsAlertBadRecordMac);
  Handshake();
  client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
  server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
  EXPECT_EQ(1U, cb_called);
}

// Generate an HRR on CHInner. Mangle the Hrr Xtn causing client to reject ECH
// which then causes a MAC mismatch.
TEST_F(TlsConnectStreamTls13Ech, EchRejectMangledHrrXtn) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  ASSERT_EQ(SECSuccess,
            SSL_SetClientEchConfigs(client_->ssl_fd(), echconfig.data(),
                                    echconfig.len()));

  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));
  auto server_hrr_ech_xtn = MakeTlsFilter<TlsExtensionDamager>(
      server_, ssl_tls13_encrypted_client_hello_xtn, 4);
  // Start the handshake.
  client_->StartConnect();
  server_->StartConnect();
  client_->Handshake();
  server_->Handshake();
  MakeNewServer();
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  client_->ExpectEch(false);
  server_->ExpectEch(false);
  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
  client_->ExpectSendAlert(kTlsAlertBadRecordMac);
  Handshake();
  client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
  server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
  EXPECT_EQ(1U, cb_called);
}

// First capture an ECH CH Xtn.
// Start new connection, inject ECH CH Xtn.
// Server will respond with ECH HRR Xtn.
// Check Client correctly panics.
TEST_F(TlsConnectStreamTls13Ech, EchClientRejectSpuriousHrrXtn) {
  ScopedSECKEYPublicKey pub;
  ScopedSECKEYPrivateKey priv;
  DataBuffer echconfig;
  ConfigureSelfEncrypt();
  EnsureTlsSetup();
  TlsConnectTestBase::GenerateEchConfig(HpkeDhKemX25519Sha256, kDefaultSuites,
                                        kPublicName, 100, echconfig, pub, priv);
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_TRUE));
  client_->ExpectEch(false);
  server_->ExpectEch(false);
  auto client_ech_xtn_capture = MakeTlsFilter<TlsExtensionCapture>(
      client_, ssl_tls13_encrypted_client_hello_xtn);
  Connect();
  ASSERT_TRUE(client_ech_xtn_capture->captured());

  // Now configure client without ECH. Server with ECH.
  Reset();
  EnsureTlsSetup();
  EXPECT_EQ(SECSuccess, SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE));
  ASSERT_EQ(SECSuccess,
            SSL_SetServerEchConfigs(server_->ssl_fd(), pub.get(), priv.get(),
                                    echconfig.data(), echconfig.len()));
  client_->ExpectEch(false);
  server_->ExpectEch(false);
  size_t cb_called = 0;
  EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
                            server_->ssl_fd(), RetryEchHello, &cb_called));

  // Inject CH ECH Xtn into CH.
  DataBuffer buff = DataBuffer(client_ech_xtn_capture->extension());
  auto client_ech_xtn = MakeTlsFilter<TlsExtensionAppender>(
      client_, kTlsHandshakeClientHello, ssl_tls13_encrypted_client_hello_xtn,
      buff);

  // Connect and check we see the HRR extension and alert.
  auto server_hrr_ech_xtn = MakeTlsFilter<TlsExtensionCapture>(
      server_, ssl_tls13_encrypted_client_hello_xtn);
  server_hrr_ech_xtn->SetHandshakeTypes({kTlsHandshakeHelloRetryRequest});

  ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=99 G=95

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.