tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

tls_mlkem_unittest.cc (19997B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ssl.h"
      8 #include "sslerr.h"
      9 #include "sslproto.h"
     10 
     11 extern "C" {
     12 // This is not something that should make you happy.
     13 #include "libssl_internals.h"
     14 }
     15 
     16 #include "gtest_utils.h"
     17 #include "nss_scoped_ptrs.h"
     18 #include "tls_connect.h"
     19 #include "tls_filter.h"
     20 #include "tls_parser.h"
     21 
     22 namespace nss_test {
     23 
     24 TEST_P(TlsKeyExchangeTest13, Mlkem768x25519Supported) {
     25  EnsureKeyShareSetup();
     26  ConfigNamedGroups({ssl_grp_kem_mlkem768x25519});
     27 
     28  Connect();
     29  CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_rsa_sign,
     30            ssl_sig_rsa_pss_rsae_sha256);
     31 }
     32 
     33 TEST_P(TlsKeyExchangeTest13, Secp256r1Mlkem768Supported) {
     34  EnsureKeyShareSetup();
     35  ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768});
     36 
     37  Connect();
     38  CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp256r1mlkem768,
     39            ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
     40 }
     41 
     42 TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024Supported) {
     43  EnsureKeyShareSetup();
     44  ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024});
     45 
     46  Connect();
     47  CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp384r1mlkem1024,
     48            ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
     49 }
     50 
     51 TEST_P(TlsKeyExchangeTest, Tls12ClientMlkem768x25519NotSupported) {
     52  EnsureKeyShareSetup();
     53  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
     54                           SSL_LIBRARY_VERSION_TLS_1_2);
     55  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
     56                           SSL_LIBRARY_VERSION_TLS_1_3);
     57  client_->DisableAllCiphers();
     58  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
     59  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
     60  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(
     61                            client_->ssl_fd(),
     62                            kECDHEGroups.size() + kEcdhHybridGroups.size()));
     63 
     64  Connect();
     65  std::vector<SSLNamedGroup> groups = GetGroupDetails(groups_capture_);
     66  for (auto group : groups) {
     67    EXPECT_NE(group, ssl_grp_kem_mlkem768x25519);
     68    EXPECT_NE(group, ssl_grp_kem_secp256r1mlkem768);
     69    EXPECT_NE(group, ssl_grp_kem_secp384r1mlkem1024);
     70  }
     71 }
     72 
     73 TEST_P(TlsKeyExchangeTest13, Tls12ServerMlkem768x25519NotSupported) {
     74  EnsureKeyShareSetup();
     75 
     76  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
     77                           SSL_LIBRARY_VERSION_TLS_1_3);
     78  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
     79                           SSL_LIBRARY_VERSION_TLS_1_2);
     80 
     81  client_->DisableAllCiphers();
     82  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
     83  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
     84  client_->ConfigNamedGroups(
     85      {ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519});
     86  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
     87 
     88  server_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
     89  server_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
     90  server_->ConfigNamedGroups(
     91      {ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519});
     92 
     93  Connect();
     94  CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
     95            ssl_sig_rsa_pss_rsae_sha256);
     96 }
     97 
     98 TEST_P(TlsKeyExchangeTest13, Tls12ServerSecp256r1Mlkem768NotSupported) {
     99  EnsureKeyShareSetup();
    100 
    101  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
    102                           SSL_LIBRARY_VERSION_TLS_1_3);
    103  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
    104                           SSL_LIBRARY_VERSION_TLS_1_2);
    105 
    106  client_->DisableAllCiphers();
    107  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
    108  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
    109  client_->ConfigNamedGroups(
    110      {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    111  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    112 
    113  server_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
    114  server_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
    115  server_->ConfigNamedGroups(
    116      {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    117 
    118  Connect();
    119  CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
    120            ssl_sig_rsa_pss_rsae_sha256);
    121 }
    122 
    123 TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ClientDisabledByPolicy) {
    124  EnsureKeyShareSetup();
    125  client_->SetPolicy(SEC_OID_MLKEM768X25519, 0, NSS_USE_ALG_IN_SSL_KX);
    126  ConfigNamedGroups({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_secp256r1});
    127 
    128  Connect();
    129  CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
    130 }
    131 
    132 TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ServerDisabledByPolicy) {
    133  EnsureKeyShareSetup();
    134  server_->SetPolicy(SEC_OID_MLKEM768X25519, 0, NSS_USE_ALG_IN_SSL_KX);
    135  ConfigNamedGroups({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_secp256r1});
    136 
    137  Connect();
    138  CheckKEXDetails({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_secp256r1},
    139                  {ssl_grp_kem_mlkem768x25519}, ssl_grp_ec_secp256r1);
    140 }
    141 
    142 TEST_P(TlsKeyExchangeTest13, Secp256r1Mlkem768ClientDisabledByPolicy) {
    143  EnsureKeyShareSetup();
    144  client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
    145  ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    146 
    147  Connect();
    148  CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
    149 }
    150 
    151 TEST_P(TlsKeyExchangeTest13, Secp256r1Mlkem768ServerDisabledByPolicy) {
    152  EnsureKeyShareSetup();
    153  server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
    154  ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    155 
    156  Connect();
    157  CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1},
    158                  {ssl_grp_kem_secp256r1mlkem768}, ssl_grp_ec_secp256r1);
    159 }
    160 
    161 TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ClientDisabledByPolicy) {
    162  EnsureKeyShareSetup();
    163  client_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX);
    164  ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1});
    165 
    166  Connect();
    167  CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
    168 }
    169 
    170 TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ServerDisabledByPolicy) {
    171  EnsureKeyShareSetup();
    172  server_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX);
    173  ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1});
    174 
    175  Connect();
    176  CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1},
    177                  {ssl_grp_kem_secp384r1mlkem1024}, ssl_grp_ec_secp256r1);
    178 }
    179 
    180 static void CheckECDHShareReuse(
    181    const std::shared_ptr<TlsExtensionCapture>& capture) {
    182  EXPECT_TRUE(capture->captured());
    183  const DataBuffer& ext = capture->extension();
    184  const int max_count = 4;
    185  DataBuffer hybrid_share[max_count];
    186  DataBuffer ecdh_share[max_count];
    187  int hybrid_offset[max_count];
    188  SSLNamedGroup hybrid_ec_type[max_count];
    189  SSLNamedGroup ec_type[max_count];
    190  int ecdh_index[max_count];
    191  int nextHybrid = 0;
    192  int nextECDH = 0;
    193 
    194  size_t offset = 0;
    195  uint32_t ext_len;
    196  ext.Read(0, 2, &ext_len);
    197  EXPECT_EQ(ext.len() - 2, ext_len);
    198  offset += 2;
    199 
    200  uint32_t named_group;
    201  uint32_t named_group_len;
    202  ext.Read(offset, 2, &named_group);
    203  ext.Read(offset + 2, 2, &named_group_len);
    204  while (offset < ext.len()) {
    205    switch (named_group) {
    206      case ssl_grp_kem_mlkem768x25519:
    207        hybrid_share[nextHybrid] =
    208            DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
    209        hybrid_offset[nextHybrid] = KYBER768_PUBLIC_KEY_BYTES;
    210        hybrid_ec_type[nextHybrid] = ssl_grp_ec_curve25519;
    211        nextHybrid++;
    212        break;
    213      case ssl_grp_kem_secp256r1mlkem768:
    214        hybrid_share[nextHybrid] =
    215            DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
    216        hybrid_offset[nextHybrid] = 0;
    217        hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp256r1;
    218        nextHybrid++;
    219      case ssl_grp_ec_curve25519:
    220      case ssl_grp_ec_secp256r1:
    221        ecdh_share[nextECDH] =
    222            DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
    223        ec_type[nextECDH] = (SSLNamedGroup)named_group;
    224        nextECDH++;
    225    }
    226    offset += 2 + 2 + named_group_len;
    227    ext.Read(offset, 2, &named_group);
    228    ext.Read(offset + 2, 2, &named_group_len);
    229  }
    230  EXPECT_EQ(offset, ext.len());
    231 
    232  ASSERT_TRUE(nextECDH <= max_count);
    233  ASSERT_TRUE(nextHybrid <= max_count);
    234  /* setup the hybrid ecdh indeces */
    235  for (int i = 0; i < nextHybrid; i++) {
    236    ecdh_index[i] = -1;
    237    for (int j = 0; j < nextECDH; j++) {
    238      if (hybrid_ec_type[i] == ec_type[j]) {
    239        ecdh_index[i] = j;
    240        break;
    241      }
    242    }
    243    ASSERT_TRUE(ecdh_index[i] != -1);
    244  }
    245  for (int i = 0; i < nextECDH; i++) {
    246    ASSERT_TRUE(ecdh_share[i].data());
    247  }
    248  for (int i = 0; i < nextHybrid; i++) {
    249    int j = ecdh_index[i];
    250    ASSERT_TRUE(hybrid_share[i].data());
    251    ASSERT_GT(hybrid_share[i].len(), ecdh_share[j].len());
    252    EXPECT_EQ(0, memcmp(hybrid_share[i].data() + hybrid_offset[i],
    253                        ecdh_share[j].data(), ecdh_share[j].len()));
    254  }
    255 }
    256 
    257 TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ShareReuseFirst) {
    258  EnsureKeyShareSetup();
    259  ConfigNamedGroups({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519});
    260  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    261 
    262  Connect();
    263 
    264  CheckKEXDetails({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519},
    265                  {ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519});
    266  CheckECDHShareReuse(shares_capture_);
    267 }
    268 
    269 TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ShareReuseSecond) {
    270  EnsureKeyShareSetup();
    271  ConfigNamedGroups({ssl_grp_ec_curve25519, ssl_grp_kem_mlkem768x25519});
    272  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    273 
    274  Connect();
    275 
    276  CheckKEXDetails({ssl_grp_ec_curve25519, ssl_grp_kem_mlkem768x25519},
    277                  {ssl_grp_ec_curve25519, ssl_grp_kem_mlkem768x25519});
    278  CheckECDHShareReuse(shares_capture_);
    279 }
    280 
    281 TEST_P(TlsKeyExchangeTest13, Secp256r1Mlkem768ShareReuseFirst) {
    282  EnsureKeyShareSetup();
    283  ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    284  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    285 
    286  Connect();
    287 
    288  CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1},
    289                  {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
    290  CheckECDHShareReuse(shares_capture_);
    291 }
    292 
    293 TEST_P(TlsKeyExchangeTest13, Secp256r1Mlkem768ShareReuseSecond) {
    294  EnsureKeyShareSetup();
    295  ConfigNamedGroups({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768});
    296  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    297 
    298  Connect();
    299 
    300  CheckKEXDetails({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768},
    301                  {ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768});
    302  CheckECDHShareReuse(shares_capture_);
    303 }
    304 
    305 TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseFirst) {
    306  EnsureKeyShareSetup();
    307  ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1});
    308  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    309 
    310  Connect();
    311 
    312  CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1},
    313                  {ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1});
    314  CheckECDHShareReuse(shares_capture_);
    315 }
    316 
    317 TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseSecond) {
    318  EnsureKeyShareSetup();
    319  ConfigNamedGroups({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024});
    320  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    321 
    322  Connect();
    323 
    324  CheckKEXDetails({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024},
    325                  {ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024});
    326  CheckECDHShareReuse(shares_capture_);
    327 }
    328 
    329 class Mlkem768x25519ShareDamager : public TlsExtensionFilter {
    330 public:
    331  typedef enum {
    332    downgrade,
    333    extend,
    334    truncate,
    335    zero_ecdh,
    336    modify_ecdh,
    337    modify_mlkem,
    338    modify_mlkem_pubkey_mod_q,
    339  } damage_type;
    340 
    341  Mlkem768x25519ShareDamager(const std::shared_ptr<TlsAgent>& a,
    342                             damage_type damage)
    343      : TlsExtensionFilter(a), damage_(damage) {}
    344 
    345  virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
    346                                               const DataBuffer& input,
    347                                               DataBuffer* output) {
    348    if (extension_type != ssl_tls13_key_share_xtn) {
    349      return KEEP;
    350    }
    351 
    352    // Find the Mlkem768x25519 share
    353    size_t offset = 0;
    354    if (agent()->role() == TlsAgent::CLIENT) {
    355      offset += 2;  // skip KeyShareClientHello length
    356    }
    357 
    358    uint32_t named_group;
    359    uint32_t named_group_len;
    360    input.Read(offset, 2, &named_group);
    361    input.Read(offset + 2, 2, &named_group_len);
    362    while (named_group != ssl_grp_kem_mlkem768x25519) {
    363      offset += 2 + 2 + named_group_len;
    364      input.Read(offset, 2, &named_group);
    365      input.Read(offset + 2, 2, &named_group_len);
    366    }
    367    EXPECT_EQ(named_group, ssl_grp_kem_mlkem768x25519);
    368 
    369    DataBuffer hybrid_key_share(input.data() + offset, 2 + 2 + named_group_len);
    370 
    371    // Damage the Mlkem768x25519 share
    372    uint32_t mlkem_component_len =
    373        hybrid_key_share.len() - 2 - 2 - X25519_PUBLIC_KEY_BYTES;
    374    unsigned char* ecdh_component =
    375        hybrid_key_share.data() + 2 + 2 + mlkem_component_len;
    376    unsigned char* mlkem_component = hybrid_key_share.data() + 2 + 2;
    377    switch (damage_) {
    378      case Mlkem768x25519ShareDamager::downgrade:
    379        // Downgrade a Mlkem768x25519 share to X25519
    380        memcpy(mlkem_component, ecdh_component, X25519_PUBLIC_KEY_BYTES);
    381        hybrid_key_share.Truncate(2 + 2 + X25519_PUBLIC_KEY_BYTES);
    382        hybrid_key_share.Write(0, ssl_grp_ec_curve25519, 2);
    383        hybrid_key_share.Write(2, X25519_PUBLIC_KEY_BYTES, 2);
    384        break;
    385      case Mlkem768x25519ShareDamager::truncate:
    386        // Truncate a Mlkem768x25519 share before the X25519 component
    387        hybrid_key_share.Truncate(2 + 2 + mlkem_component_len);
    388        hybrid_key_share.Write(2, mlkem_component_len, 2);
    389        break;
    390      case Mlkem768x25519ShareDamager::extend:
    391        // Append 4 bytes to a Mlkem768x25519 share
    392        uint32_t current_len;
    393        hybrid_key_share.Read(2, 2, &current_len);
    394        hybrid_key_share.Write(hybrid_key_share.len(), current_len, 4);
    395        hybrid_key_share.Write(2, current_len + 4, 2);
    396        break;
    397      case Mlkem768x25519ShareDamager::zero_ecdh:
    398        // Replace an X25519 component with 0s
    399        memset(ecdh_component, 0, X25519_PUBLIC_KEY_BYTES);
    400        break;
    401      case Mlkem768x25519ShareDamager::modify_ecdh:
    402        // Flip a bit in the X25519 component
    403        ecdh_component[0] ^= 0x01;
    404        break;
    405      case Mlkem768x25519ShareDamager::modify_mlkem:
    406        // Flip a bit in the mlkem component
    407        mlkem_component[0] ^= 0x01;
    408        break;
    409      case Mlkem768x25519ShareDamager::modify_mlkem_pubkey_mod_q:
    410        if (agent()->role() == TlsAgent::CLIENT) {
    411          // Replace the client's public key with an sequence of 12-bit values
    412          // in the same equivalence class mod 3329. The FIPS-203 input
    413          // validation check should fail.
    414          for (size_t i = 0; i < mlkem_component_len - 32; i += 3) {
    415            // Pairs of 12-bit coefficients are packed into 3 bytes.
    416            // Unpack them, change equivalence class if possible, and repack.
    417            uint16_t coeff0 =
    418                mlkem_component[i] | ((mlkem_component[i + 1] & 0x0f) << 8);
    419            uint16_t coeff1 = (mlkem_component[i + 1] & 0xf0 >> 4) |
    420                              ((mlkem_component[i + 2]) << 4);
    421            if (coeff0 < 4096 - 3329) {
    422              coeff0 += 3329;
    423            }
    424            if (coeff1 < 4096 - 3329) {
    425              coeff1 += 3329;
    426            }
    427            mlkem_component[i] = coeff0;
    428            mlkem_component[i + 1] = (coeff0 >> 8) + ((coeff1 & 0x0f) << 4);
    429            mlkem_component[i + 2] = coeff1 >> 4;
    430          }
    431        }
    432        break;
    433    }
    434 
    435    *output = input;
    436    output->Splice(hybrid_key_share, offset, 2 + 2 + named_group_len);
    437 
    438    // Fix the KeyShareClientHello length if necessary
    439    if (agent()->role() == TlsAgent::CLIENT &&
    440        hybrid_key_share.len() != 2 + 2 + named_group_len) {
    441      output->Write(0, output->len() - 2, 2);
    442    }
    443 
    444    return CHANGE;
    445  }
    446 
    447 private:
    448  damage_type damage_;
    449 };
    450 
    451 class TlsMlkem768x25519DamageTest
    452    : public TlsConnectTestBase,
    453      public ::testing::WithParamInterface<
    454          Mlkem768x25519ShareDamager::damage_type> {
    455 public:
    456  TlsMlkem768x25519DamageTest()
    457      : TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
    458 
    459 protected:
    460  void Damage(const std::shared_ptr<TlsAgent>& agent) {
    461    EnsureTlsSetup();
    462    client_->ConfigNamedGroups(
    463        {ssl_grp_ec_curve25519, ssl_grp_kem_mlkem768x25519});
    464    server_->ConfigNamedGroups(
    465        {ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519});
    466    EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
    467    MakeTlsFilter<Mlkem768x25519ShareDamager>(agent, GetParam());
    468  }
    469 };
    470 
    471 TEST_P(TlsMlkem768x25519DamageTest, DamageClientShare) {
    472  Damage(client_);
    473 
    474  switch (GetParam()) {
    475    case Mlkem768x25519ShareDamager::extend:
    476    case Mlkem768x25519ShareDamager::truncate:
    477      ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
    478      server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
    479      break;
    480    case Mlkem768x25519ShareDamager::zero_ecdh:
    481      ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
    482      server_->CheckErrorCode(SEC_ERROR_INVALID_KEY);
    483      break;
    484    case Mlkem768x25519ShareDamager::modify_mlkem_pubkey_mod_q:
    485      ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
    486      server_->CheckErrorCode(SEC_ERROR_INVALID_ARGS);
    487      break;
    488    case Mlkem768x25519ShareDamager::downgrade:
    489    case Mlkem768x25519ShareDamager::modify_ecdh:
    490    case Mlkem768x25519ShareDamager::modify_mlkem:
    491      client_->ExpectSendAlert(kTlsAlertBadRecordMac);
    492      server_->ExpectSendAlert(kTlsAlertBadRecordMac);
    493      ConnectExpectFail();
    494      client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
    495      server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
    496      break;
    497  }
    498 }
    499 
    500 TEST_P(TlsMlkem768x25519DamageTest, DamageServerShare) {
    501  Damage(server_);
    502 
    503  switch (GetParam()) {
    504    case Mlkem768x25519ShareDamager::extend:
    505    case Mlkem768x25519ShareDamager::truncate:
    506      client_->ExpectSendAlert(kTlsAlertIllegalParameter);
    507      server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
    508      ConnectExpectFail();
    509      client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
    510      break;
    511    case Mlkem768x25519ShareDamager::zero_ecdh:
    512      client_->ExpectSendAlert(kTlsAlertIllegalParameter);
    513      server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
    514      ConnectExpectFail();
    515      client_->CheckErrorCode(SEC_ERROR_INVALID_KEY);
    516      break;
    517    case Mlkem768x25519ShareDamager::downgrade:
    518    case Mlkem768x25519ShareDamager::modify_ecdh:
    519    case Mlkem768x25519ShareDamager::modify_mlkem:
    520      client_->ExpectSendAlert(kTlsAlertBadRecordMac);
    521      server_->ExpectSendAlert(kTlsAlertBadRecordMac);
    522      ConnectExpectFail();
    523      client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
    524      server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
    525      break;
    526    case Mlkem768x25519ShareDamager::modify_mlkem_pubkey_mod_q:
    527      // The server doesn't send a public key, so nothing is changed.
    528      break;
    529  }
    530 }
    531 
    532 INSTANTIATE_TEST_SUITE_P(
    533    TlsMlkem768x25519DamageTest, TlsMlkem768x25519DamageTest,
    534    ::testing::Values(Mlkem768x25519ShareDamager::downgrade,
    535                      Mlkem768x25519ShareDamager::extend,
    536                      Mlkem768x25519ShareDamager::truncate,
    537                      Mlkem768x25519ShareDamager::zero_ecdh,
    538                      Mlkem768x25519ShareDamager::modify_ecdh,
    539                      Mlkem768x25519ShareDamager::modify_mlkem,
    540                      Mlkem768x25519ShareDamager::modify_mlkem_pubkey_mod_q));
    541 
    542 }  // namespace nss_test