tls_xyber_unittest.cc (11887B)
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, Xyber768d00Supported) { 25 EnsureKeyShareSetup(); 26 ConfigNamedGroups({ssl_grp_kem_xyber768d00}); 27 28 Connect(); 29 CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_xyber768d00, ssl_auth_rsa_sign, 30 ssl_sig_rsa_pss_rsae_sha256); 31 } 32 33 TEST_P(TlsKeyExchangeTest, Tls12ClientXyber768d00NotSupported) { 34 EnsureKeyShareSetup(); 35 client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, 36 SSL_LIBRARY_VERSION_TLS_1_2); 37 server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, 38 SSL_LIBRARY_VERSION_TLS_1_3); 39 client_->DisableAllCiphers(); 40 client_->EnableCiphersByKeyExchange(ssl_kea_ecdh); 41 client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid); 42 EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares( 43 client_->ssl_fd(), 44 kECDHEGroups.size() + kEcdhHybridGroups.size())); 45 46 Connect(); 47 std::vector<SSLNamedGroup> groups = GetGroupDetails(groups_capture_); 48 for (auto group : groups) { 49 EXPECT_NE(group, ssl_grp_kem_xyber768d00); 50 } 51 } 52 53 TEST_P(TlsKeyExchangeTest13, Tls12ServerXyber768d00NotSupported) { 54 if (variant_ == ssl_variant_datagram) { 55 /* Bug 1874451 - reenable this test */ 56 return; 57 } 58 59 EnsureKeyShareSetup(); 60 61 client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, 62 SSL_LIBRARY_VERSION_TLS_1_3); 63 server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, 64 SSL_LIBRARY_VERSION_TLS_1_2); 65 66 client_->DisableAllCiphers(); 67 client_->EnableCiphersByKeyExchange(ssl_kea_ecdh); 68 client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid); 69 client_->ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}); 70 EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); 71 72 server_->EnableCiphersByKeyExchange(ssl_kea_ecdh); 73 server_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid); 74 server_->ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}); 75 76 Connect(); 77 CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign, 78 ssl_sig_rsa_pss_rsae_sha256); 79 } 80 81 TEST_P(TlsKeyExchangeTest13, Xyber768d00ClientDisabledByPolicy) { 82 EnsureKeyShareSetup(); 83 client_->SetPolicy(SEC_OID_XYBER768D00, 0, NSS_USE_ALG_IN_SSL_KX); 84 ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_secp256r1}); 85 86 Connect(); 87 CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1}); 88 } 89 90 TEST_P(TlsKeyExchangeTest13, Xyber768d00ServerDisabledByPolicy) { 91 EnsureKeyShareSetup(); 92 server_->SetPolicy(SEC_OID_XYBER768D00, 0, NSS_USE_ALG_IN_SSL_KX); 93 ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_secp256r1}); 94 95 Connect(); 96 CheckKEXDetails({ssl_grp_kem_xyber768d00, ssl_grp_ec_secp256r1}, 97 {ssl_grp_kem_xyber768d00}, ssl_grp_ec_secp256r1); 98 } 99 100 void CheckECDHShareReuse(const std::shared_ptr<TlsExtensionCapture>& capture) { 101 EXPECT_TRUE(capture->captured()); 102 const DataBuffer& ext = capture->extension(); 103 DataBuffer xyber_share; 104 DataBuffer x25519_share; 105 106 size_t offset = 0; 107 uint32_t ext_len; 108 ext.Read(0, 2, &ext_len); 109 EXPECT_EQ(ext.len() - 2, ext_len); 110 offset += 2; 111 112 uint32_t named_group; 113 uint32_t named_group_len; 114 ext.Read(offset, 2, &named_group); 115 ext.Read(offset + 2, 2, &named_group_len); 116 while (offset < ext.len()) { 117 if (named_group == ssl_grp_kem_xyber768d00) { 118 xyber_share = DataBuffer(ext.data() + offset + 2 + 2, named_group_len); 119 } 120 if (named_group == ssl_grp_ec_curve25519) { 121 x25519_share = DataBuffer(ext.data() + offset + 2 + 2, named_group_len); 122 } 123 offset += 2 + 2 + named_group_len; 124 ext.Read(offset, 2, &named_group); 125 ext.Read(offset + 2, 2, &named_group_len); 126 } 127 EXPECT_EQ(offset, ext.len()); 128 129 ASSERT_TRUE(xyber_share.data()); 130 ASSERT_TRUE(x25519_share.data()); 131 ASSERT_GT(xyber_share.len(), x25519_share.len()); 132 EXPECT_EQ( 133 0, memcmp(xyber_share.data(), x25519_share.data(), x25519_share.len())); 134 } 135 136 TEST_P(TlsKeyExchangeTest13, XyberShareReuseFirst) { 137 if (variant_ == ssl_variant_datagram) { 138 /* Bug 1874451 - reenable this test */ 139 return; 140 } 141 EnsureKeyShareSetup(); 142 ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}); 143 EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); 144 145 Connect(); 146 147 CheckKEXDetails({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}, 148 {ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}); 149 CheckECDHShareReuse(shares_capture_); 150 } 151 152 TEST_P(TlsKeyExchangeTest13, XyberShareReuseSecond) { 153 if (variant_ == ssl_variant_datagram) { 154 /* Bug 1874451 - reenable this test */ 155 return; 156 } 157 EnsureKeyShareSetup(); 158 ConfigNamedGroups({ssl_grp_ec_curve25519, ssl_grp_kem_xyber768d00}); 159 EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); 160 161 Connect(); 162 163 CheckKEXDetails({ssl_grp_ec_curve25519, ssl_grp_kem_xyber768d00}, 164 {ssl_grp_ec_curve25519, ssl_grp_kem_xyber768d00}); 165 CheckECDHShareReuse(shares_capture_); 166 } 167 168 class XyberShareDamager : public TlsExtensionFilter { 169 public: 170 typedef enum { 171 downgrade, 172 extend, 173 truncate, 174 zero_ecdh, 175 modify_ecdh, 176 modify_kyber, 177 } damage_type; 178 179 XyberShareDamager(const std::shared_ptr<TlsAgent>& a, damage_type damage) 180 : TlsExtensionFilter(a), damage_(damage) {} 181 182 virtual PacketFilter::Action FilterExtension(uint16_t extension_type, 183 const DataBuffer& input, 184 DataBuffer* output) { 185 if (extension_type != ssl_tls13_key_share_xtn) { 186 return KEEP; 187 } 188 189 // Find the Xyber768d00 share 190 size_t offset = 0; 191 if (agent()->role() == TlsAgent::CLIENT) { 192 offset += 2; // skip KeyShareClientHello length 193 } 194 195 uint32_t named_group; 196 uint32_t named_group_len; 197 input.Read(offset, 2, &named_group); 198 input.Read(offset + 2, 2, &named_group_len); 199 while (named_group != ssl_grp_kem_xyber768d00) { 200 offset += 2 + 2 + named_group_len; 201 input.Read(offset, 2, &named_group); 202 input.Read(offset + 2, 2, &named_group_len); 203 } 204 EXPECT_EQ(named_group, ssl_grp_kem_xyber768d00); 205 206 DataBuffer xyber_key_share(input.data() + offset, 2 + 2 + named_group_len); 207 208 // Damage the Xyber768d00 share 209 unsigned char* ecdh_component = xyber_key_share.data() + 2 + 2; 210 unsigned char* kyber_component = 211 xyber_key_share.data() + 2 + 2 + X25519_PUBLIC_KEY_BYTES; 212 switch (damage_) { 213 case XyberShareDamager::downgrade: 214 // Downgrade a Xyber768d00 share to X25519 215 xyber_key_share.Truncate(2 + 2 + X25519_PUBLIC_KEY_BYTES); 216 xyber_key_share.Write(0, ssl_grp_ec_curve25519, 2); 217 xyber_key_share.Write(2, X25519_PUBLIC_KEY_BYTES, 2); 218 break; 219 case XyberShareDamager::truncate: 220 // Truncate a Xyber768d00 share after the X25519 component 221 xyber_key_share.Truncate(2 + 2 + X25519_PUBLIC_KEY_BYTES); 222 xyber_key_share.Write(2, X25519_PUBLIC_KEY_BYTES, 2); 223 break; 224 case XyberShareDamager::extend: 225 // Append 4 bytes to a Xyber768d00 share 226 uint32_t current_len; 227 xyber_key_share.Read(2, 2, ¤t_len); 228 xyber_key_share.Write(xyber_key_share.len(), current_len, 4); 229 xyber_key_share.Write(2, current_len + 4, 2); 230 break; 231 case XyberShareDamager::zero_ecdh: 232 // Replace an X25519 component with 0s 233 memset(ecdh_component, 0, X25519_PUBLIC_KEY_BYTES); 234 break; 235 case XyberShareDamager::modify_ecdh: 236 // Flip a bit in the X25519 component 237 ecdh_component[0] ^= 0x01; 238 break; 239 case XyberShareDamager::modify_kyber: 240 // Flip a bit in the Kyber component 241 kyber_component[0] ^= 0x01; 242 break; 243 } 244 245 *output = input; 246 output->Splice(xyber_key_share, offset, 2 + 2 + named_group_len); 247 248 // Fix the KeyShareClientHello length if necessary 249 if (agent()->role() == TlsAgent::CLIENT && 250 xyber_key_share.len() != 2 + 2 + named_group_len) { 251 output->Write(0, output->len() - 2, 2); 252 } 253 254 return CHANGE; 255 } 256 257 private: 258 damage_type damage_; 259 }; 260 261 class TlsXyberDamageTest 262 : public TlsConnectTestBase, 263 public ::testing::WithParamInterface<XyberShareDamager::damage_type> { 264 public: 265 TlsXyberDamageTest() 266 : TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {} 267 268 protected: 269 void Damage(const std::shared_ptr<TlsAgent>& agent) { 270 EnsureTlsSetup(); 271 client_->ConfigNamedGroups( 272 {ssl_grp_ec_curve25519, ssl_grp_kem_xyber768d00}); 273 server_->ConfigNamedGroups( 274 {ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519}); 275 EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1)); 276 MakeTlsFilter<XyberShareDamager>(agent, GetParam()); 277 } 278 }; 279 280 TEST_P(TlsXyberDamageTest, DamageClientShare) { 281 Damage(client_); 282 283 switch (GetParam()) { 284 case XyberShareDamager::extend: 285 case XyberShareDamager::truncate: 286 ConnectExpectAlert(server_, kTlsAlertIllegalParameter); 287 server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); 288 break; 289 case XyberShareDamager::zero_ecdh: 290 ConnectExpectAlert(server_, kTlsAlertIllegalParameter); 291 server_->CheckErrorCode(SEC_ERROR_INVALID_KEY); 292 break; 293 case XyberShareDamager::downgrade: 294 case XyberShareDamager::modify_ecdh: 295 case XyberShareDamager::modify_kyber: 296 client_->ExpectSendAlert(kTlsAlertBadRecordMac); 297 server_->ExpectSendAlert(kTlsAlertBadRecordMac); 298 ConnectExpectFail(); 299 client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); 300 server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); 301 break; 302 } 303 } 304 305 TEST_P(TlsXyberDamageTest, DamageServerShare) { 306 Damage(server_); 307 308 switch (GetParam()) { 309 case XyberShareDamager::extend: 310 case XyberShareDamager::truncate: 311 client_->ExpectSendAlert(kTlsAlertIllegalParameter); 312 server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); 313 ConnectExpectFail(); 314 client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE); 315 break; 316 case XyberShareDamager::zero_ecdh: 317 client_->ExpectSendAlert(kTlsAlertIllegalParameter); 318 server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); 319 ConnectExpectFail(); 320 client_->CheckErrorCode(SEC_ERROR_INVALID_KEY); 321 break; 322 case XyberShareDamager::downgrade: 323 case XyberShareDamager::modify_ecdh: 324 case XyberShareDamager::modify_kyber: 325 client_->ExpectSendAlert(kTlsAlertBadRecordMac); 326 server_->ExpectSendAlert(kTlsAlertBadRecordMac); 327 ConnectExpectFail(); 328 client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); 329 server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); 330 break; 331 } 332 } 333 334 INSTANTIATE_TEST_SUITE_P(TlsXyberDamageTest, TlsXyberDamageTest, 335 ::testing::Values(XyberShareDamager::downgrade, 336 XyberShareDamager::extend, 337 XyberShareDamager::truncate, 338 XyberShareDamager::zero_ecdh, 339 XyberShareDamager::modify_ecdh, 340 XyberShareDamager::modify_kyber)); 341 342 } // namespace nss_test