summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc1513
1 files changed, 1513 insertions, 0 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
new file mode 100644
index 0000000000..eb45e71422
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -0,0 +1,1513 @@
+/* -*- 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 "ssl.h"
+#include "ssl3prot.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+// This is only to get DTLS_1_3_DRAFT_VERSION
+#include "ssl3prot.h"
+
+#include <memory>
+
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+class Dtls13LegacyCookieInjector : public TlsHandshakeFilter {
+ public:
+ Dtls13LegacyCookieInjector(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeClientHello}) {}
+
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ const uint8_t cookie_bytes[] = {0x03, 0x0A, 0x0B, 0x0C};
+ uint32_t offset = 2 /* version */ + 32 /* random */;
+
+ if (agent()->variant() != ssl_variant_datagram) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+
+ if (header.handshake_type() != ssl_hs_client_hello) {
+ return KEEP;
+ }
+
+ DataBuffer cookie(cookie_bytes, sizeof(cookie_bytes));
+ *output = input;
+
+ // Add the SID length (if any) to locate the cookie.
+ uint32_t sid_len = 0;
+ if (!output->Read(offset, 1, &sid_len)) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+ offset += 1 + sid_len;
+ output->Splice(cookie, offset, 1);
+
+ return CHANGE;
+ }
+
+ private:
+ DataBuffer cookie_;
+};
+
+class TlsExtensionTruncator : public TlsExtensionFilter {
+ public:
+ TlsExtensionTruncator(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
+ size_t length)
+ : TlsExtensionFilter(a), extension_(extension), length_(length) {}
+ virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ if (extension_type != extension_) {
+ return KEEP;
+ }
+ if (input.len() <= length_) {
+ return KEEP;
+ }
+
+ output->Assign(input.data(), length_);
+ return CHANGE;
+ }
+
+ private:
+ uint16_t extension_;
+ size_t length_;
+};
+
+class TlsExtensionTestBase : public TlsConnectTestBase {
+ protected:
+ TlsExtensionTestBase(SSLProtocolVariant variant, uint16_t version)
+ : TlsConnectTestBase(variant, version) {}
+
+ void ClientHelloErrorTest(std::shared_ptr<PacketFilter> filter,
+ uint8_t desc = kTlsAlertDecodeError) {
+ client_->SetFilter(filter);
+ ConnectExpectAlert(server_, desc);
+ }
+
+ void ServerHelloErrorTest(std::shared_ptr<PacketFilter> filter,
+ uint8_t desc = kTlsAlertDecodeError) {
+ server_->SetFilter(filter);
+ ConnectExpectAlert(client_, desc);
+ }
+
+ static void InitSimpleSni(DataBuffer* extension) {
+ const char* name = "host.name";
+ const size_t namelen = PL_strlen(name);
+ extension->Allocate(namelen + 5);
+ extension->Write(0, namelen + 3, 2);
+ extension->Write(2, static_cast<uint32_t>(0), 1); // 0 == hostname
+ extension->Write(3, namelen, 2);
+ extension->Write(5, reinterpret_cast<const uint8_t*>(name), namelen);
+ }
+
+ void HrrThenRemoveExtensionsTest(SSLExtensionType type, PRInt32 client_error,
+ PRInt32 server_error) {
+ static const std::vector<SSLNamedGroup> client_groups = {
+ ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
+ static const std::vector<SSLNamedGroup> server_groups = {
+ ssl_grp_ec_curve25519, ssl_grp_ec_secp384r1};
+ client_->ConfigNamedGroups(client_groups);
+ server_->ConfigNamedGroups(server_groups);
+ EnsureTlsSetup();
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ server_->Handshake(); // Send HRR.
+ MakeTlsFilter<TlsExtensionDropper>(client_, type);
+ Handshake();
+ client_->CheckErrorCode(client_error);
+ server_->CheckErrorCode(server_error);
+ }
+};
+
+class TlsExtensionTestDtls : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<uint16_t> {
+ public:
+ TlsExtensionTestDtls()
+ : TlsExtensionTestBase(ssl_variant_datagram, GetParam()) {}
+};
+
+class TlsExtensionTest12Plus : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsExtensionTest12Plus()
+ : TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
+ }
+};
+
+class TlsExtensionTest12 : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsExtensionTest12()
+ : TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
+ }
+};
+
+class TlsExtensionTest13
+ : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<SSLProtocolVariant> {
+ public:
+ TlsExtensionTest13()
+ : TlsExtensionTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
+
+ void ConnectWithBogusVersionList(const uint8_t* buf, size_t len) {
+ DataBuffer versions_buf(buf, len);
+ MakeTlsFilter<TlsExtensionReplacer>(
+ client_, ssl_tls13_supported_versions_xtn, versions_buf);
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ }
+
+ void ConnectWithReplacementVersionList(uint16_t version) {
+ // Convert the version encoding for DTLS, if needed.
+ if (variant_ == ssl_variant_datagram) {
+ switch (version) {
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+#ifdef DTLS_1_3_DRAFT_VERSION
+ version = 0x7f00 | DTLS_1_3_DRAFT_VERSION;
+#else
+ version = SSL_LIBRARY_VERSION_DTLS_1_3_WIRE;
+#endif
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ version = SSL_LIBRARY_VERSION_DTLS_1_2_WIRE;
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ /* TLS_1_1 maps to DTLS_1_0, see sslproto.h. */
+ version = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+ break;
+ default:
+ PORT_Assert(0);
+ }
+ }
+
+ DataBuffer versions_buf;
+ size_t index = versions_buf.Write(0, 2, 1);
+ versions_buf.Write(index, version, 2);
+ MakeTlsFilter<TlsExtensionReplacer>(
+ client_, ssl_tls13_supported_versions_xtn, versions_buf);
+ ConnectExpectFail();
+ }
+};
+
+class TlsExtensionTest13Stream : public TlsExtensionTestBase {
+ public:
+ TlsExtensionTest13Stream()
+ : TlsExtensionTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
+};
+
+class TlsExtensionTestGeneric : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsExtensionTestGeneric()
+ : TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
+ }
+};
+
+class TlsExtensionTestPre13 : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsExtensionTestPre13()
+ : TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
+ }
+};
+
+TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDamager>(client_, ssl_server_name_xtn, 1));
+}
+
+TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDamager>(client_, ssl_server_name_xtn, 4));
+}
+
+TEST_P(TlsExtensionTestGeneric, TruncateSni) {
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionTruncator>(client_, ssl_server_name_xtn, 7));
+}
+
+// A valid extension that appears twice will be reported as unsupported.
+TEST_P(TlsExtensionTestGeneric, RepeatSni) {
+ DataBuffer extension;
+ InitSimpleSni(&extension);
+ ClientHelloErrorTest(std::make_shared<TlsExtensionInjector>(
+ client_, ssl_server_name_xtn, extension),
+ kTlsAlertIllegalParameter);
+}
+
+// An SNI entry with zero length is considered invalid (strangely, not if it is
+// the last entry, which is probably a bug).
+TEST_P(TlsExtensionTestGeneric, BadSni) {
+ DataBuffer simple;
+ InitSimpleSni(&simple);
+ DataBuffer extension;
+ extension.Allocate(simple.len() + 3);
+ extension.Write(0, static_cast<uint32_t>(0), 3);
+ extension.Write(3, simple);
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_server_name_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, EmptySni) {
+ DataBuffer extension;
+ extension.Allocate(2);
+ extension.Write(0, static_cast<uint32_t>(0), 2);
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_server_name_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
+ EnableAlpn();
+ DataBuffer extension;
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertIllegalParameter);
+}
+
+// An empty ALPN isn't considered bad, though it does lead to there being no
+// protocol for the server to select.
+TEST_P(TlsExtensionTestGeneric, EmptyAlpnList) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertNoApplicationProtocol);
+}
+
+TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
+ EnableAlpn();
+ ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
+ client_, ssl_app_layer_protocol_xtn, 1));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
+ EnableAlpn();
+ // This will leave the length of the second entry, but no value.
+ ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
+ client_, ssl_app_layer_protocol_xtn, 5));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnLengthOverflow) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x01};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
+ const uint8_t client_alpn[] = {0x01, 0x61};
+ client_->EnableAlpn(client_alpn, sizeof(client_alpn));
+ const uint8_t server_alpn[] = {0x02, 0x61, 0x62};
+ server_->EnableAlpn(server_alpn, sizeof(server_alpn));
+
+ ClientHelloErrorTest(nullptr, kTlsAlertNoApplicationProtocol);
+ client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnDisabledServer) {
+ const uint8_t client_alpn[] = {0x01, 0x61};
+ client_->EnableAlpn(client_alpn, sizeof(client_alpn));
+ server_->EnableAlpn(nullptr, 0);
+
+ ClientHelloErrorTest(nullptr, kTlsAlertUnsupportedExtension);
+}
+
+TEST_P(TlsConnectGeneric, AlpnDisabled) {
+ server_->EnableAlpn(nullptr, 0);
+ Connect();
+
+ SSLNextProtoState state;
+ uint8_t buf[255] = {0};
+ unsigned int buf_len = 3;
+ EXPECT_EQ(SECSuccess, SSL_GetNextProto(client_->ssl_fd(), &state, buf,
+ &buf_len, sizeof(buf)));
+ EXPECT_EQ(SSL_NEXT_PROTO_NO_SUPPORT, state);
+ EXPECT_EQ(0U, buf_len);
+}
+
+// Many of these tests fail in TLS 1.3 because the extension is encrypted, which
+// prevents modification of the value from the ServerHello.
+TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyList) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyName) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x01, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedListTrailingData) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x02, 0x01, 0x61, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedExtraEntry) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x04, 0x01, 0x61, 0x01, 0x62};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedBadListLength) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x99, 0x01, 0x61, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedBadNameLength) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x02, 0x99, 0x61};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedUnknownName) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x02, 0x01, 0x67};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ server_, ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertIllegalParameter);
+}
+
+TEST_P(TlsExtensionTestDtls, SrtpShort) {
+ EnableSrtp();
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionTruncator>(client_, ssl_use_srtp_xtn, 3));
+}
+
+TEST_P(TlsExtensionTestDtls, SrtpOdd) {
+ EnableSrtp();
+ const uint8_t val[] = {0x00, 0x01, 0xff, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_use_srtp_xtn, extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
+ const uint8_t val[] = {0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
+ // make sure the test uses an algorithm that is legal for
+ // tls 1.3 (or tls 1.3 will throw a handshake failure alert
+ // instead of a decode error alert)
+ const uint8_t val[] = {0x00, 0x02, 0x08, 0x09, 0x00}; // sha-256, rsa-pss-pss
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
+ const uint8_t val[] = {0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension),
+ kTlsAlertHandshakeFailure);
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsNoOverlap) {
+ const uint8_t val[] = {0x00, 0x02, 0xff, 0xff};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension),
+ kTlsAlertHandshakeFailure);
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
+ const uint8_t val[] = {0x00, 0x01, 0x04};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension));
+}
+
+TEST_F(TlsExtensionTest13Stream, SignatureAlgorithmsPrecedingGarbage) {
+ // 31 unknown signature algorithms followed by sha-256, rsa-pss
+ const uint8_t val[] = {
+ 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x04};
+ DataBuffer extension(val, sizeof(val));
+ MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_signature_algorithms_xtn,
+ extension);
+ client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+ client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+}
+
+TEST_P(TlsExtensionTestGeneric, NoSupportedGroups) {
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDropper>(client_, ssl_supported_groups_xtn),
+ version_ < SSL_LIBRARY_VERSION_TLS_1_3 ? kTlsAlertDecryptError
+ : kTlsAlertMissingExtension);
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
+ const uint8_t val[] = {0x00, 0x01, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_elliptic_curves_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
+ const uint8_t val[] = {0x09, 0x99, 0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_elliptic_curves_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
+ const uint8_t val[] = {0x00, 0x02, 0x00, 0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_elliptic_curves_xtn, extension));
+}
+
+TEST_P(TlsExtensionTest12, SupportedCurvesDisableX25519) {
+ // Disable session resumption.
+ ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+
+ // Ensure that we can enable its use in the key exchange.
+ SECStatus rv =
+ NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, NSS_USE_ALG_IN_SSL_KX, 0);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+ 0);
+ ASSERT_EQ(SECSuccess, rv);
+
+ auto capture1 =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
+ Connect();
+
+ EXPECT_TRUE(capture1->captured());
+ const DataBuffer& ext1 = capture1->extension();
+
+ uint32_t count;
+ ASSERT_TRUE(ext1.Read(0, 2, &count));
+
+ // Whether or not we've seen x25519 offered in this handshake.
+ bool seen1_x25519 = false;
+ for (size_t offset = 2; offset <= count; offset++) {
+ uint32_t val;
+ ASSERT_TRUE(ext1.Read(offset, 2, &val));
+ if (val == ssl_grp_ec_curve25519) {
+ seen1_x25519 = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(seen1_x25519);
+
+ // Ensure that we can disable its use in the key exchange.
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, 0, NSS_USE_ALG_IN_SSL_KX);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+ 0);
+ ASSERT_EQ(SECSuccess, rv);
+
+ // Clean up after the last run.
+ Reset();
+ auto capture2 =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
+ Connect();
+
+ EXPECT_TRUE(capture2->captured());
+ const DataBuffer& ext2 = capture2->extension();
+
+ ASSERT_TRUE(ext2.Read(0, 2, &count));
+
+ // Whether or not we've seen x25519 offered in this handshake.
+ bool seen2_x25519 = false;
+ for (size_t offset = 2; offset <= count; offset++) {
+ uint32_t val;
+ ASSERT_TRUE(ext2.Read(offset, 2, &val));
+
+ if (val == ssl_grp_ec_curve25519) {
+ seen2_x25519 = true;
+ break;
+ }
+ }
+
+ ASSERT_FALSE(seen2_x25519);
+}
+
+TEST_P(TlsExtensionTestPre13, SupportedPointsEmpty) {
+ const uint8_t val[] = {0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_ec_point_formats_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, SupportedPointsBadLength) {
+ const uint8_t val[] = {0x99, 0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_ec_point_formats_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, SupportedPointsTrailingData) {
+ const uint8_t val[] = {0x01, 0x00, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_ec_point_formats_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, SupportedPointsCompressed) {
+ const uint8_t val[] = {0x01, 0x02};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_ec_point_formats_xtn, extension),
+ kTlsAlertIllegalParameter);
+}
+
+TEST_P(TlsExtensionTestPre13, SupportedPointsUndefined) {
+ const uint8_t val[] = {0x01, 0xAA};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_ec_point_formats_xtn, extension),
+ kTlsAlertIllegalParameter);
+}
+
+TEST_P(TlsExtensionTestPre13, RenegotiationInfoBadLength) {
+ const uint8_t val[] = {0x99};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_renegotiation_info_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, RenegotiationInfoMismatch) {
+ const uint8_t val[] = {0x01, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_renegotiation_info_xtn, extension));
+}
+
+// The extension has to contain a length.
+TEST_P(TlsExtensionTestPre13, RenegotiationInfoExtensionEmpty) {
+ DataBuffer extension;
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_renegotiation_info_xtn, extension));
+}
+
+// This only works on TLS 1.2, since it relies on static RSA; otherwise libssl
+// picks the wrong cipher suite.
+TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
+ const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_rsae_sha512,
+ ssl_sig_rsa_pss_rsae_sha384};
+
+ auto capture =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+ client_->SetSignatureSchemes(schemes, PR_ARRAY_SIZE(schemes));
+ EnableOnlyStaticRsaCiphers();
+ Connect();
+
+ const DataBuffer& ext = capture->extension();
+ EXPECT_EQ(2 + PR_ARRAY_SIZE(schemes) * 2, ext.len());
+ for (size_t i = 0, cursor = 2;
+ i < PR_ARRAY_SIZE(schemes) && cursor < ext.len(); ++i) {
+ uint32_t v = 0;
+ EXPECT_TRUE(ext.Read(cursor, 2, &v));
+ cursor += 2;
+ EXPECT_EQ(schemes[i], static_cast<SSLSignatureScheme>(v));
+ }
+}
+
+// This only works on TLS 1.2, since it relies on DSA.
+TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
+ const std::vector<SSLSignatureScheme> schemes = {
+ ssl_sig_dsa_sha1, ssl_sig_dsa_sha256, ssl_sig_dsa_sha384,
+ ssl_sig_dsa_sha512, ssl_sig_rsa_pss_rsae_sha256};
+
+ // Connect with DSA enabled by policy.
+ SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
+ NSS_USE_ALG_IN_SSL_KX, 0);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+ 0);
+ ASSERT_EQ(SECSuccess, rv);
+
+ Reset(TlsAgent::kServerDsa);
+ auto capture1 =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+ client_->SetSignatureSchemes(schemes.data(), schemes.size());
+ Connect();
+
+ // Check if all the signature algorithms are advertised.
+ EXPECT_TRUE(capture1->captured());
+ const DataBuffer& ext1 = capture1->extension();
+ EXPECT_EQ(2U + 2U * schemes.size(), ext1.len());
+
+ // Connect with DSA disabled by policy.
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, 0,
+ NSS_USE_ALG_IN_SSL_KX);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+ 0);
+ ASSERT_EQ(SECSuccess, rv);
+
+ Reset(TlsAgent::kServerDsa);
+ auto capture2 =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+ client_->SetSignatureSchemes(schemes.data(), schemes.size());
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+ server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+
+ // Check if no DSA algorithms are advertised.
+ EXPECT_TRUE(capture2->captured());
+ const DataBuffer& ext2 = capture2->extension();
+ EXPECT_EQ(2U + 2U, ext2.len());
+ uint32_t v = 0;
+ EXPECT_TRUE(ext2.Read(2, 2, &v));
+ EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, v);
+}
+
+// Temporary test to verify that we choke on an empty ClientKeyShare.
+// This test will fail when we implement HelloRetryRequest.
+TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
+ ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
+ client_, ssl_tls13_key_share_xtn, 2),
+ kTlsAlertHandshakeFailure);
+}
+
+// These tests only work in stream mode because the client sends a
+// cleartext alert which causes a MAC error on the server. With
+// stream this causes handshake failure but with datagram, the
+// packet gets dropped.
+TEST_F(TlsExtensionTest13Stream, DropServerKeyShare) {
+ EnsureTlsSetup();
+ MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_key_share_xtn);
+ client_->ExpectSendAlert(kTlsAlertMissingExtension);
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+}
+
+TEST_F(TlsExtensionTest13Stream, WrongServerKeyShare) {
+ const uint16_t wrong_group = ssl_grp_ec_secp384r1;
+
+ static const uint8_t key_share[] = {
+ wrong_group >> 8,
+ wrong_group & 0xff, // Group we didn't offer.
+ 0x00,
+ 0x02, // length = 2
+ 0x01,
+ 0x02};
+ DataBuffer buf(key_share, sizeof(key_share));
+ EnsureTlsSetup();
+ MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_key_share_xtn, buf);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+}
+
+TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
+ const uint16_t wrong_group = 0xffff;
+
+ static const uint8_t key_share[] = {
+ wrong_group >> 8,
+ wrong_group & 0xff, // Group we didn't offer.
+ 0x00,
+ 0x02, // length = 2
+ 0x01,
+ 0x02};
+ DataBuffer buf(key_share, sizeof(key_share));
+ EnsureTlsSetup();
+ MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_key_share_xtn, buf);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+}
+
+TEST_F(TlsExtensionTest13Stream, AddServerSignatureAlgorithmsOnResumption) {
+ SetupForResume();
+ DataBuffer empty;
+ MakeTlsFilter<TlsExtensionInjector>(server_, ssl_signature_algorithms_xtn,
+ empty);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ EXPECT_EQ(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, client_->error_code());
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+}
+
+struct PskIdentity {
+ DataBuffer identity;
+ uint32_t obfuscated_ticket_age;
+};
+
+class TlsPreSharedKeyReplacer;
+
+typedef std::function<void(TlsPreSharedKeyReplacer*)>
+ TlsPreSharedKeyReplacerFunc;
+
+class TlsPreSharedKeyReplacer : public TlsExtensionFilter {
+ public:
+ TlsPreSharedKeyReplacer(const std::shared_ptr<TlsAgent>& a,
+ TlsPreSharedKeyReplacerFunc function)
+ : TlsExtensionFilter(a), identities_(), binders_(), function_(function) {}
+
+ static size_t CopyAndMaybeReplace(TlsParser* parser, size_t size,
+ const std::unique_ptr<DataBuffer>& replace,
+ size_t index, DataBuffer* output) {
+ DataBuffer tmp;
+ bool ret = parser->ReadVariable(&tmp, size);
+ EXPECT_EQ(true, ret);
+ if (!ret) return 0;
+ if (replace) {
+ tmp = *replace;
+ }
+
+ return WriteVariable(output, index, tmp, size);
+ }
+
+ PacketFilter::Action FilterExtension(uint16_t extension_type,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ if (extension_type != ssl_tls13_pre_shared_key_xtn) {
+ return KEEP;
+ }
+
+ if (!Decode(input)) {
+ return KEEP;
+ }
+
+ // Call the function.
+ function_(this);
+
+ Encode(output);
+
+ return CHANGE;
+ }
+
+ std::vector<PskIdentity> identities_;
+ std::vector<DataBuffer> binders_;
+
+ private:
+ bool Decode(const DataBuffer& input) {
+ std::unique_ptr<TlsParser> parser(new TlsParser(input));
+ DataBuffer identities;
+
+ if (!parser->ReadVariable(&identities, 2)) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ DataBuffer binders;
+ if (!parser->ReadVariable(&binders, 2)) {
+ ADD_FAILURE();
+ return false;
+ }
+ EXPECT_EQ(0UL, parser->remaining());
+
+ // Now parse the inner sections.
+ parser.reset(new TlsParser(identities));
+ while (parser->remaining()) {
+ PskIdentity identity;
+
+ if (!parser->ReadVariable(&identity.identity, 2)) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ if (!parser->Read(&identity.obfuscated_ticket_age, 4)) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ identities_.push_back(identity);
+ }
+
+ parser.reset(new TlsParser(binders));
+ while (parser->remaining()) {
+ DataBuffer binder;
+
+ if (!parser->ReadVariable(&binder, 1)) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ binders_.push_back(binder);
+ }
+
+ return true;
+ }
+
+ void Encode(DataBuffer* output) {
+ DataBuffer identities;
+ size_t index = 0;
+ for (auto id : identities_) {
+ index = WriteVariable(&identities, index, id.identity, 2);
+ index = identities.Write(index, id.obfuscated_ticket_age, 4);
+ }
+
+ DataBuffer binders;
+ index = 0;
+ for (auto binder : binders_) {
+ index = WriteVariable(&binders, index, binder, 1);
+ }
+
+ output->Truncate(0);
+ index = 0;
+ index = WriteVariable(output, index, identities, 2);
+ index = WriteVariable(output, index, binders, 2);
+ }
+
+ TlsPreSharedKeyReplacerFunc function_;
+};
+
+TEST_F(TlsExtensionTest13Stream, ResumeEmptyPskLabel) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->identities_[0].identity.Truncate(0);
+ });
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+// Flip the first byte of the binder.
+TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderValue) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
+ });
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
+ client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+}
+
+// Do the same with an External PSK.
+TEST_P(TlsConnectTls13, TestTls13PskInvalidBinderValue) {
+ 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, std::string("foo"), ssl_hash_sha256);
+ StartConnect();
+ ASSERT_TRUE(client_->MaybeSetResumptionToken());
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
+ });
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
+ client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+}
+
+// Extend the binder by one.
+TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderLength) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->binders_[0].Write(r->binders_[0].len(), 0xff, 1);
+ });
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+// Binders must be at least 32 bytes.
+TEST_F(TlsExtensionTest13Stream, ResumeBinderTooShort) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) { r->binders_[0].Truncate(31); });
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+// Duplicate the identity and binder. This will fail with an error
+// processing the binder (because we extended the identity list.)
+TEST_F(TlsExtensionTest13Stream, ResumeTwoPsks) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->identities_.push_back(r->identities_[0]);
+ r->binders_.push_back(r->binders_[0]);
+ });
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
+ client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+}
+
+// The next two tests have mismatches in the number of identities
+// and binders. This generates an illegal parameter alert.
+TEST_F(TlsExtensionTest13Stream, ResumeTwoIdentitiesOneBinder) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->identities_.push_back(r->identities_[0]);
+ });
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+TEST_F(TlsExtensionTest13Stream, ResumeOneIdentityTwoBinders) {
+ SetupForResume();
+
+ MakeTlsFilter<TlsPreSharedKeyReplacer>(
+ client_, [](TlsPreSharedKeyReplacer* r) {
+ r->binders_.push_back(r->binders_[0]);
+ });
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+TEST_F(TlsExtensionTest13Stream, ResumePskExtensionNotLast) {
+ SetupForResume();
+
+ const uint8_t empty_buf[] = {0};
+ DataBuffer empty(empty_buf, 0);
+ // Inject an unused extension after the PSK extension.
+ MakeTlsFilter<TlsExtensionAppender>(client_, kTlsHandshakeClientHello, 0xffff,
+ empty);
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+TEST_F(TlsExtensionTest13Stream, ResumeNoKeModes) {
+ SetupForResume();
+
+ DataBuffer empty;
+ MakeTlsFilter<TlsExtensionDropper>(client_,
+ ssl_tls13_psk_key_exchange_modes_xtn);
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
+ client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES);
+}
+
+// The following test contains valid but unacceptable PreSharedKey
+// modes and therefore produces non-resumption followed by MAC
+// errors.
+TEST_F(TlsExtensionTest13Stream, ResumeBogusKeModes) {
+ SetupForResume();
+ const static uint8_t ke_modes[] = {1, // Length
+ kTls13PskKe};
+
+ DataBuffer modes(ke_modes, sizeof(ke_modes));
+ MakeTlsFilter<TlsExtensionReplacer>(
+ client_, ssl_tls13_psk_key_exchange_modes_xtn, modes);
+ client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+ client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+}
+
+TEST_P(TlsExtensionTest13, NoKeModesIfResumptionOff) {
+ ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+ auto capture = MakeTlsFilter<TlsExtensionCapture>(
+ client_, ssl_tls13_psk_key_exchange_modes_xtn);
+ Connect();
+ EXPECT_FALSE(capture->captured());
+}
+
+// In these tests, we downgrade to TLS 1.2, causing the
+// server to negotiate TLS 1.2.
+// 1. Both sides only support TLS 1.3, so we get a cipher version
+// error.
+TEST_P(TlsExtensionTest13, RemoveTls13FromVersionList) {
+ ExpectAlert(server_, kTlsAlertProtocolVersion);
+ ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
+ client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+}
+
+// 2. Server supports 1.2 and 1.3, client supports 1.2, so we
+// can't negotiate any ciphers.
+TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListServerV12) {
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ ExpectAlert(server_, kTlsAlertHandshakeFailure);
+ ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+// 3. Server supports 1.2 and 1.3, client supports 1.2 and 1.3
+// but advertises 1.2 (because we changed things).
+TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListBothV12) {
+ client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
+ 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_3);
+// The downgrade check is disabled in DTLS 1.3, so all that happens when we
+// tamper with the supported versions is that the Finished check fails.
+#ifdef DTLS_1_3_DRAFT_VERSION
+ if (variant_ == ssl_variant_datagram) {
+ ExpectAlert(server_, kTlsAlertDecryptError);
+ } else
+#endif
+ {
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
+ }
+ ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
+#ifdef DTLS_1_3_DRAFT_VERSION
+ if (variant_ == ssl_variant_datagram) {
+ client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ } else
+#endif
+ {
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ }
+}
+
+TEST_P(TlsExtensionTest13, HrrThenRemoveSignatureAlgorithms) {
+ ExpectAlert(server_, kTlsAlertMissingExtension);
+ HrrThenRemoveExtensionsTest(ssl_signature_algorithms_xtn,
+ SSL_ERROR_MISSING_EXTENSION_ALERT,
+ SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
+}
+
+TEST_P(TlsExtensionTest13, HrrThenRemoveKeyShare) {
+ ExpectAlert(server_, kTlsAlertIllegalParameter);
+ HrrThenRemoveExtensionsTest(ssl_tls13_key_share_xtn,
+ SSL_ERROR_ILLEGAL_PARAMETER_ALERT,
+ SSL_ERROR_BAD_2ND_CLIENT_HELLO);
+}
+
+TEST_P(TlsExtensionTest13, HrrThenRemoveSupportedGroups) {
+ ExpectAlert(server_, kTlsAlertMissingExtension);
+ HrrThenRemoveExtensionsTest(ssl_supported_groups_xtn,
+ SSL_ERROR_MISSING_EXTENSION_ALERT,
+ SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
+}
+
+TEST_P(TlsExtensionTest13, EmptyVersionList) {
+ static const uint8_t kExt[] = {0x00, 0x00};
+ ConnectWithBogusVersionList(kExt, sizeof(kExt));
+}
+
+TEST_P(TlsExtensionTest13, OddVersionList) {
+ static const uint8_t kExt[] = {0x00, 0x01, 0x00};
+ ConnectWithBogusVersionList(kExt, sizeof(kExt));
+}
+
+TEST_P(TlsExtensionTest13, SignatureAlgorithmsInvalidTls13) {
+ // testing the case where we ask for a invalid parameter for tls13
+ const uint8_t val[] = {0x00, 0x02, 0x04, 0x01}; // sha-256, rsa-pkcs1
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_signature_algorithms_xtn, extension),
+ kTlsAlertHandshakeFailure);
+}
+
+// Use the stream version number for TLS 1.3 (0x0304) in DTLS.
+TEST_F(TlsConnectDatagram13, TlsVersionInDtls) {
+ static const uint8_t kExt[] = {0x02, 0x03, 0x04};
+
+ DataBuffer versions_buf(kExt, sizeof(kExt));
+ MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_tls13_supported_versions_xtn,
+ versions_buf);
+ ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
+ client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+}
+
+// TODO: this only tests extensions in server messages. The client can extend
+// Certificate messages, which is not checked here.
+class TlsBogusExtensionTest : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsBogusExtensionTest()
+ : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
+
+ protected:
+ virtual void ConnectAndFail(uint8_t message) = 0;
+
+ void AddFilter(uint8_t message, uint16_t extension) {
+ static uint8_t empty_buf[1] = {0};
+ DataBuffer empty(empty_buf, 0);
+ auto filter =
+ MakeTlsFilter<TlsExtensionAppender>(server_, message, extension, empty);
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ filter->EnableDecryption();
+ }
+ }
+
+ void Run(uint8_t message, uint16_t extension = 0xff) {
+ EnsureTlsSetup();
+ AddFilter(message, extension);
+ ConnectAndFail(message);
+ }
+};
+
+class TlsBogusExtensionTestPre13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t) override {
+ ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
+ }
+};
+
+class TlsBogusExtensionTest13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t message) override {
+ if (message != kTlsHandshakeServerHello) {
+ ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
+ return;
+ }
+
+ FailWithAlert(kTlsAlertUnsupportedExtension);
+ }
+
+ void FailWithAlert(uint8_t alert) {
+ StartConnect();
+ client_->Handshake(); // ClientHello
+ server_->Handshake(); // ServerHello
+
+ client_->ExpectSendAlert(alert);
+ client_->Handshake();
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ }
+ server_->Handshake();
+ }
+};
+
+TEST_P(TlsBogusExtensionTestPre13, AddBogusExtensionServerHello) {
+ Run(kTlsHandshakeServerHello);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionServerHello) {
+ Run(kTlsHandshakeServerHello);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionEncryptedExtensions) {
+ Run(kTlsHandshakeEncryptedExtensions);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificate) {
+ Run(kTlsHandshakeCertificate);
+}
+
+// It's perfectly valid to set unknown extensions in CertificateRequest.
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificateRequest) {
+ server_->RequestClientAuth(false);
+ AddFilter(kTlsHandshakeCertificateRequest, 0xff);
+ ConnectExpectAlert(client_, kTlsAlertDecryptError);
+ client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
+ static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
+ server_->ConfigNamedGroups(groups);
+
+ Run(kTlsHandshakeHelloRetryRequest);
+}
+
+// NewSessionTicket allows unknown extensions AND it isn't protected by the
+// Finished. So adding an unknown extension doesn't cause an error.
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionNewSessionTicket) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+
+ AddFilter(kTlsHandshakeNewSessionTicket, 0xff);
+ Connect();
+ SendReceive();
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+ Connect();
+ SendReceive();
+}
+
+class TlsDisallowedExtensionTest13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t message) override {
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ }
+};
+
+TEST_P(TlsDisallowedExtensionTest13, AddVersionExtensionEncryptedExtensions) {
+ Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsDisallowedExtensionTest13, AddVersionExtensionCertificate) {
+ Run(kTlsHandshakeCertificate, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsDisallowedExtensionTest13, AddVersionExtensionCertificateRequest) {
+ server_->RequestClientAuth(false);
+ Run(kTlsHandshakeCertificateRequest, ssl_tls13_supported_versions_xtn);
+}
+
+/* For unadvertised disallowed extensions an unsupported_extension alert is
+ * thrown since NSS checks for unadvertised extensions before its disallowed
+ * extension check. */
+class TlsDisallowedUnadvertisedExtensionTest13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t message) override {
+ uint8_t alert = kTlsAlertUnsupportedExtension;
+ if (message == kTlsHandshakeCertificateRequest) {
+ alert = kTlsAlertIllegalParameter;
+ }
+ ConnectExpectAlert(client_, alert);
+ }
+};
+
+TEST_P(TlsDisallowedUnadvertisedExtensionTest13,
+ AddPSKExtensionEncryptedExtensions) {
+ Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_pre_shared_key_xtn);
+}
+
+TEST_P(TlsDisallowedUnadvertisedExtensionTest13, AddPSKExtensionCertificate) {
+ Run(kTlsHandshakeCertificate, ssl_tls13_pre_shared_key_xtn);
+}
+
+TEST_P(TlsDisallowedUnadvertisedExtensionTest13,
+ AddPSKExtensionCertificateRequest) {
+ server_->RequestClientAuth(false);
+ Run(kTlsHandshakeCertificateRequest, ssl_tls13_pre_shared_key_xtn);
+}
+
+TEST_P(TlsConnectStream, IncludePadding) {
+ EnsureTlsSetup();
+ SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE); // Don't GREASE
+
+ // This needs to be long enough to push a TLS 1.0 ClientHello over 255, but
+ // short enough not to push a TLS 1.3 ClientHello over 511.
+ static const char* long_name =
+ "chickenchickenchickenchickenchickenchickenchickenchicken."
+ "chickenchickenchickenchickenchickenchickenchickenchicken."
+ "chickenchickenchickenchickenchicken.";
+ SECStatus rv = SSL_SetURL(client_->ssl_fd(), long_name);
+ EXPECT_EQ(SECSuccess, rv);
+
+ auto capture = MakeTlsFilter<TlsExtensionCapture>(client_, ssl_padding_xtn);
+ client_->StartConnect();
+ client_->Handshake();
+ EXPECT_TRUE(capture->captured());
+}
+
+TEST_F(TlsConnectDatagram13, Dtls13RejectLegacyCookie) {
+ EnsureTlsSetup();
+ MakeTlsFilter<Dtls13LegacyCookieInjector>(client_);
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+TEST_P(TlsConnectGeneric, ClientHelloExtensionPermutation) {
+ EnsureTlsSetup();
+ PR_ASSERT(SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_CH_EXTENSION_PERMUTATION,
+ PR_TRUE) == SECSuccess);
+ Connect();
+}
+
+TEST_F(TlsConnectStreamTls13, ClientHelloExtensionPermutationWithPSK) {
+ EnsureTlsSetup();
+
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ SECItem psk_item;
+ psk_item.type = siBuffer;
+ psk_item.len = sizeof(kPskDummyVal_);
+ psk_item.data = const_cast<uint8_t*>(kPskDummyVal_);
+ PK11SymKey* key =
+ PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
+ CKA_DERIVE, &psk_item, NULL);
+
+ ScopedPK11SymKey scoped_psk_(key);
+ const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
+ const SSLHashType kPskHash_ = ssl_hash_sha384;
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+
+ PR_ASSERT(SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_CH_EXTENSION_PERMUTATION,
+ PR_TRUE) == SECSuccess);
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+/* This test checks that the ClientHello extension order is actually permuted
+ * if ss->opt.chXtnPermutation is set. It is asserted that at least one out of
+ * 10 extension orders differs from the others.
+ *
+ * This is a probabilistic test: The default TLS 1.3 ClientHello contains 8
+ * extensions, leading to a 1/8! probability for any extension order and the
+ * same probability for two drawn extension orders to coincide.
+ * Since all sequences are compared against each other this leads to a false
+ * positive rate of (1/8!)^(n^2-n).
+ * To achieve a spurious failure rate << 1/2^64, we compare n=10 drawn orders.
+ *
+ * This test assures that randomisation is happening but does not check quality
+ * of the used Fisher-Yates shuffle. */
+TEST_F(TlsConnectStreamTls13,
+ ClientHelloExtensionPermutationProbabilisticTest) {
+ std::vector<std::vector<uint16_t>> orders;
+
+ /* Capture the extension order of 10 ClientHello messages. */
+ for (size_t i = 0; i < 10; i++) {
+ client_->StartConnect();
+ /* Enable ClientHello extension permutation. */
+ ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_CH_EXTENSION_PERMUTATION,
+ PR_TRUE) == SECSuccess);
+ /* Capture extension order filter. */
+ auto filter = MakeTlsFilter<TlsExtensionOrderCapture>(
+ client_, kTlsHandshakeClientHello);
+ /* Send ClientHello. */
+ client_->Handshake();
+ /* Remember extension order. */
+ orders.push_back(filter->order);
+ /* Reset client / server state. */
+ Reset();
+ }
+
+ /* Check for extension order inequality. */
+ size_t inequal = 0;
+ for (auto& outerOrders : orders) {
+ for (auto& innerOrders : orders) {
+ if (outerOrders != innerOrders) {
+ inequal++;
+ }
+ }
+ }
+ ASSERT_TRUE(inequal >= 1);
+}
+
+// The certificate_authorities xtn can be included in a ClientHello [RFC 8446,
+// Section 4.2]
+TEST_F(TlsConnectStreamTls13, ClientHelloCertAuthXtnToleration) {
+ EnsureTlsSetup();
+ uint8_t bodyBuf[3] = {0x00, 0x01, 0xff};
+ DataBuffer body(bodyBuf, sizeof(bodyBuf));
+ auto ch = MakeTlsFilter<TlsExtensionAppender>(
+ client_, kTlsHandshakeClientHello, ssl_tls13_certificate_authorities_xtn,
+ body);
+ // The Connection will fail because the added extension isn't in the client's
+ // transcript not because the extension is unsupported (Bug 1815167).
+ server_->ExpectSendAlert(bad_record_mac);
+ client_->ExpectSendAlert(bad_record_mac);
+ ConnectExpectFail();
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+ client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ExtensionStream, TlsExtensionTestGeneric,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll));
+INSTANTIATE_TEST_SUITE_P(
+ ExtensionDatagram, TlsExtensionTestGeneric,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+ TlsConnectTestBase::kTlsV11Plus));
+INSTANTIATE_TEST_SUITE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
+ TlsConnectTestBase::kTlsV11Plus);
+
+INSTANTIATE_TEST_SUITE_P(ExtensionTls12, TlsExtensionTest12,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV12));
+
+INSTANTIATE_TEST_SUITE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV12Plus));
+
+INSTANTIATE_TEST_SUITE_P(
+ ExtensionPre13Stream, TlsExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12));
+INSTANTIATE_TEST_SUITE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV11V12));
+
+INSTANTIATE_TEST_SUITE_P(ExtensionTls13, TlsExtensionTest13,
+ TlsConnectTestBase::kTlsVariantsAll);
+
+INSTANTIATE_TEST_SUITE_P(
+ BogusExtensionStream, TlsBogusExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12));
+INSTANTIATE_TEST_SUITE_P(
+ BogusExtensionDatagram, TlsBogusExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+ TlsConnectTestBase::kTlsV11V12));
+
+INSTANTIATE_TEST_SUITE_P(BogusExtension13, TlsBogusExtensionTest13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
+
+INSTANTIATE_TEST_SUITE_P(DisallowedExtension13, TlsDisallowedExtensionTest13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
+
+INSTANTIATE_TEST_SUITE_P(DisallowedUnadvertisedExtension13,
+ TlsDisallowedUnadvertisedExtensionTest13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
+
+} // namespace nss_test