| /* -*- 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 "sslerr.h" |
| #include "sslexp.h" |
| #include "sslproto.h" |
| |
| extern "C" { |
| // This is not something that should make you happy. |
| #include "libssl_internals.h" |
| } |
| |
| #include "cpputil.h" |
| #include "gtest_utils.h" |
| #include "nss_scoped_ptrs.h" |
| #include "tls_connect.h" |
| #include "tls_filter.h" |
| #include "tls_parser.h" |
| |
| namespace nss_test { |
| |
| TEST_P(TlsConnectTls13, ZeroRtt) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true); |
| Handshake(); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ZeroRttServerRejectByOption) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ZeroRttApplicationReject) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| |
| auto reject_0rtt = [](PRBool firstHello, const PRUint8* clientToken, |
| unsigned int clientTokenLen, PRUint8* appToken, |
| unsigned int* appTokenLen, unsigned int appTokenMax, |
| void* arg) { |
| auto* called = reinterpret_cast<bool*>(arg); |
| *called = true; |
| |
| EXPECT_TRUE(firstHello); |
| EXPECT_EQ(0U, clientTokenLen); |
| return ssl_hello_retry_reject_0rtt; |
| }; |
| |
| bool cb_run = false; |
| EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(), |
| reject_0rtt, &cb_run)); |
| ZeroRttSendReceive(true, false); |
| Handshake(); |
| EXPECT_TRUE(cb_run); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ZeroRttApparentReplayAfterRestart) { |
| // The test fixtures enable anti-replay in SetUp(). This results in 0-RTT |
| // being rejected until at least one window passes. SetupFor0Rtt() forces a |
| // rollover of the anti-replay filters, which clears that state and allows |
| // 0-RTT to work. Make the first connection manually to avoid that rollover |
| // and cause 0-RTT to be rejected. |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3); |
| server_->Set0RttEnabled(true); // So we signal that we allow 0-RTT. |
| Connect(); |
| SendReceive(); // Need to read so that we absorb the session ticket. |
| CheckKeys(); |
| |
| Reset(); |
| StartConnect(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| class TlsZeroRttReplayTest : public TlsConnectTls13 { |
| private: |
| class SaveFirstPacket : public PacketFilter { |
| public: |
| PacketFilter::Action Filter(const DataBuffer& input, |
| DataBuffer* output) override { |
| if (!packet_.len() && input.len()) { |
| packet_ = input; |
| } |
| return KEEP; |
| } |
| |
| const DataBuffer& packet() const { return packet_; } |
| |
| private: |
| DataBuffer packet_; |
| }; |
| |
| protected: |
| void RunTest(bool rollover, const ScopedPK11SymKey& epsk) { |
| // Now run a true 0-RTT handshake, but capture the first packet. |
| auto first_packet = std::make_shared<SaveFirstPacket>(); |
| client_->SetFilter(first_packet); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ZeroRttSendReceive(true, true); |
| Handshake(); |
| EXPECT_LT(0U, first_packet->packet().len()); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| |
| if (rollover) { |
| RolloverAntiReplay(); |
| } |
| |
| // Now replay that packet against the server. |
| Reset(); |
| server_->StartConnect(); |
| server_->Set0RttEnabled(true); |
| server_->SetAntiReplayContext(anti_replay_); |
| if (epsk) { |
| AddPsk(epsk, std::string("foo"), ssl_hash_sha256, |
| TLS_CHACHA20_POLY1305_SHA256); |
| } |
| |
| // Capture the early_data extension, which should not appear. |
| auto early_data_ext = |
| MakeTlsFilter<TlsExtensionCapture>(server_, ssl_tls13_early_data_xtn); |
| |
| // Finally, replay the ClientHello and force the server to consume it. Stop |
| // after the server sends its first flight; the client will not be able to |
| // complete this handshake. |
| server_->adapter()->PacketReceived(first_packet->packet()); |
| server_->Handshake(); |
| EXPECT_FALSE(early_data_ext->captured()); |
| } |
| |
| void RunResPskTest(bool rollover) { |
| // Run the initial handshake |
| SetupForZeroRtt(); |
| ExpectResumption(RESUME_TICKET); |
| RunTest(rollover, ScopedPK11SymKey(nullptr)); |
| } |
| |
| void RunExtPskTest(bool rollover) { |
| ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); |
| ASSERT_NE(nullptr, slot); |
| |
| const std::vector<uint8_t> kPskDummyVal(16, 0xFF); |
| SECItem psk_item = {siBuffer, toUcharPtr(kPskDummyVal.data()), |
| static_cast<unsigned int>(kPskDummyVal.size())}; |
| PK11SymKey* key = |
| PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap, |
| CKA_DERIVE, &psk_item, NULL); |
| ASSERT_NE(nullptr, key); |
| ScopedPK11SymKey scoped_psk(key); |
| RolloverAntiReplay(); |
| AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256, |
| TLS_CHACHA20_POLY1305_SHA256); |
| StartConnect(); |
| RunTest(rollover, scoped_psk); |
| } |
| }; |
| |
| TEST_P(TlsZeroRttReplayTest, ResPskZeroRttReplay) { RunResPskTest(false); } |
| |
| TEST_P(TlsZeroRttReplayTest, ExtPskZeroRttReplay) { RunExtPskTest(false); } |
| |
| TEST_P(TlsZeroRttReplayTest, ZeroRttReplayAfterRollover) { |
| RunResPskTest(true); |
| } |
| |
| // Test that we don't try to send 0-RTT data when the server sent |
| // us a ticket without the 0-RTT flags. |
| TEST_P(TlsConnectTls13, ZeroRttOptionsSetLate) { |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| Connect(); |
| SendReceive(); // Need to read so that we absorb the session ticket. |
| CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); |
| Reset(); |
| StartConnect(); |
| // Now turn on 0-RTT but too late for the ticket. |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(false, false); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // Make sure that a session ticket sent well after the original handshake |
| // can be used for 0-RTT. |
| // Stream because DTLS doesn't support SSL_SendSessionTicket. |
| TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicket) { |
| // Use a small-ish anti-replay window. |
| ResetAntiReplay(100 * PR_USEC_PER_MSEC); |
| RolloverAntiReplay(); |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| server_->Set0RttEnabled(true); |
| Connect(); |
| CheckKeys(); |
| |
| // Now move time forward 30s and send a ticket. |
| AdvanceTime(30 * PR_USEC_PER_SEC); |
| EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0)); |
| SendReceive(); |
| Reset(); |
| StartConnect(); |
| |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true); |
| Handshake(); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // Check that post-handshake authentication with a long RTT doesn't |
| // make things worse. |
| TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicketPha) { |
| // Use a small-ish anti-replay window. |
| ResetAntiReplay(100 * PR_USEC_PER_MSEC); |
| RolloverAntiReplay(); |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| server_->Set0RttEnabled(true); |
| client_->SetupClientAuth(); |
| client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE); |
| Connect(); |
| CheckKeys(); |
| |
| // Add post-handshake authentication, with some added delays. |
| AdvanceTime(10 * PR_USEC_PER_SEC); |
| EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd())); |
| AdvanceTime(10 * PR_USEC_PER_SEC); |
| server_->SendData(50); |
| client_->ReadBytes(50); |
| client_->SendData(50); |
| server_->ReadBytes(50); |
| |
| AdvanceTime(10 * PR_USEC_PER_SEC); |
| EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0)); |
| server_->SendData(100); |
| client_->ReadBytes(100); |
| Reset(); |
| StartConnect(); |
| |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true); |
| Handshake(); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // Same, but with client authentication on the first connection. |
| TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicketClientAuth) { |
| // Use a small-ish anti-replay window. |
| ResetAntiReplay(100 * PR_USEC_PER_MSEC); |
| RolloverAntiReplay(); |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| client_->SetupClientAuth(); |
| server_->RequestClientAuth(true); |
| server_->Set0RttEnabled(true); |
| Connect(); |
| CheckKeys(); |
| |
| // Now move time forward 30s and send a ticket. |
| AdvanceTime(30 * PR_USEC_PER_SEC); |
| EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0)); |
| SendReceive(); |
| Reset(); |
| StartConnect(); |
| |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true); |
| Handshake(); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ZeroRttServerForgetTicket) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ClearServerCache(); |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| ExpectResumption(RESUME_NONE); |
| ZeroRttSendReceive(true, false); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ZeroRttServerOnly) { |
| ExpectResumption(RESUME_NONE); |
| server_->Set0RttEnabled(true); |
| StartConnect(); |
| |
| // Client sends ordinary ClientHello. |
| client_->Handshake(); |
| |
| // Verify that the server doesn't get data. |
| uint8_t buf[100]; |
| PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf)); |
| EXPECT_EQ(SECFailure, rv); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| |
| // Now make sure that things complete. |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| CheckKeys(); |
| } |
| |
| // Advancing time after sending the ClientHello means that the ticket age that |
| // arrives at the server is too low. The server then rejects early data if this |
| // delay exceeds half the anti-replay window. |
| TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) { |
| static const PRTime kWindow = 10 * PR_USEC_PER_SEC; |
| ResetAntiReplay(kWindow); |
| SetupForZeroRtt(); |
| |
| Reset(); |
| StartConnect(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false, [this]() { |
| AdvanceTime(1 + kWindow / 2); |
| return true; |
| }); |
| Handshake(); |
| ExpectEarlyDataAccepted(false); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // In this test, we falsely inflate the estimate of the RTT by delaying the |
| // ServerHello on the first handshake. This results in the server estimating a |
| // higher value of the ticket age than the client ultimately provides. Add a |
| // small tolerance for variation in ticket age and the ticket will appear to |
| // arrive prematurely, causing the server to reject early data. |
| TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) { |
| static const PRTime kWindow = 10 * PR_USEC_PER_SEC; |
| ResetAntiReplay(kWindow); |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3); |
| server_->Set0RttEnabled(true); |
| StartConnect(); |
| client_->Handshake(); // ClientHello |
| server_->Handshake(); // ServerHello |
| AdvanceTime(1 + kWindow / 2); |
| Handshake(); // Remainder of handshake |
| CheckConnected(); |
| SendReceive(); |
| CheckKeys(); |
| |
| Reset(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ExpectEarlyDataAccepted(false); |
| StartConnect(); |
| ZeroRttSendReceive(true, false); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpn) { |
| EnableAlpn(); |
| SetupForZeroRtt(); |
| EnableAlpn(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ExpectEarlyDataAccepted(true); |
| ZeroRttSendReceive(true, true, [this]() { |
| client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a"); |
| return true; |
| }); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| CheckAlpn("a"); |
| } |
| |
| // NOTE: In this test and those below, the client always sends |
| // post-ServerHello alerts with the handshake keys, even if the server |
| // has accepted 0-RTT. In some cases, as with errors in |
| // EncryptedExtensions, the client can't know the server's behavior, |
| // and in others it's just simpler. What the server is expecting |
| // depends on whether it accepted 0-RTT or not. Eventually, we may |
| // make the server trial decrypt. |
| // |
| // Have the server negotiate a different ALPN value, and therefore |
| // reject 0-RTT. |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpnChangeServer) { |
| EnableAlpn(); |
| SetupForZeroRtt(); |
| static const uint8_t client_alpn[] = {0x01, 0x61, 0x01, 0x62}; // "a", "b" |
| static const uint8_t server_alpn[] = {0x01, 0x62}; // "b" |
| client_->EnableAlpn(client_alpn, sizeof(client_alpn)); |
| server_->EnableAlpn(server_alpn, sizeof(server_alpn)); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false, [this]() { |
| client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a"); |
| return true; |
| }); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| CheckAlpn("b"); |
| } |
| |
| // Check that the client validates the ALPN selection of the server. |
| // Stomp the ALPN on the client after sending the ClientHello so |
| // that the server selection appears to be incorrect. The client |
| // should then fail the connection. |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttNoAlpnServer) { |
| EnableAlpn(); |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| EnableAlpn(); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true, [this]() { |
| PRUint8 b[] = {'b'}; |
| client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a"); |
| EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b, sizeof(b))); |
| client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b"); |
| client_->ExpectSendAlert(kTlsAlertIllegalParameter); |
| return true; |
| }); |
| if (variant_ == ssl_variant_stream) { |
| server_->ExpectSendAlert(kTlsAlertBadRecordMac); |
| Handshake(); |
| server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); |
| } else { |
| client_->Handshake(); |
| } |
| client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
| } |
| |
| // Set up with no ALPN and then set the client so it thinks it has ALPN. |
| // The server responds without the extension and the client returns an |
| // error. |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttNoAlpnClient) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true, [this]() { |
| PRUint8 b[] = {'b'}; |
| EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b, 1)); |
| client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b"); |
| client_->ExpectSendAlert(kTlsAlertIllegalParameter); |
| return true; |
| }); |
| if (variant_ == ssl_variant_stream) { |
| server_->ExpectSendAlert(kTlsAlertBadRecordMac); |
| Handshake(); |
| server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); |
| } else { |
| client_->Handshake(); |
| } |
| client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); |
| } |
| |
| // Remove the old ALPN value and so the client will not offer early data. |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpnChangeBoth) { |
| EnableAlpn(); |
| SetupForZeroRtt(); |
| static const std::vector<uint8_t> alpn({0x01, 0x62}); // "b" |
| EnableAlpn(alpn); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false, [this]() { |
| client_->CheckAlpn(SSL_NEXT_PROTO_NO_SUPPORT); |
| return false; |
| }); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); |
| CheckAlpn("b"); |
| } |
| |
| // The client should abort the connection when sending a 0-rtt handshake but |
| // the servers responds with a TLS 1.2 ServerHello. (no app data sent) |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngrade) { |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| server_->Set0RttEnabled(true); // set ticket_allow_early_data |
| Connect(); |
| |
| SendReceive(); // Need to read so that we absorb the session tickets. |
| CheckKeys(); |
| |
| Reset(); |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| 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(); |
| // We will send the early data xtn without sending actual early data. Thus |
| // a 1.2 server shouldn't fail until the client sends an alert because the |
| // client sends end_of_early_data only after reading the server's flight. |
| client_->Set0RttEnabled(true); |
| |
| client_->ExpectSendAlert(kTlsAlertIllegalParameter); |
| if (variant_ == ssl_variant_stream) { |
| server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); |
| } |
| client_->Handshake(); |
| server_->Handshake(); |
| ASSERT_TRUE_WAIT( |
| (client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000); |
| |
| // DTLS will timeout as we bump the epoch when installing the early app data |
| // cipher suite. Thus the encrypted alert will be ignored. |
| if (variant_ == ssl_variant_stream) { |
| // The client sends an encrypted alert message. |
| ASSERT_TRUE_WAIT( |
| (server_->error_code() == SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA), |
| 2000); |
| } |
| } |
| |
| // The client should abort the connection when sending a 0-rtt handshake but |
| // the servers responds with a TLS 1.2 ServerHello. (with app data) |
| TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) { |
| const char* k0RttData = "ABCDEF"; |
| const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData)); |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| server_->Set0RttEnabled(true); // set ticket_allow_early_data |
| Connect(); |
| |
| SendReceive(); // Need to read so that we absorb the session tickets. |
| CheckKeys(); |
| |
| Reset(); |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| 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(); |
| // Send the early data xtn in the CH, followed by early app data. The server |
| // will fail right after sending its flight, when receiving the early data. |
| client_->Set0RttEnabled(true); |
| client_->Handshake(); // Send ClientHello. |
| PRInt32 rv = |
| PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen); // 0-RTT write. |
| EXPECT_EQ(k0RttDataLen, rv); |
| |
| if (variant_ == ssl_variant_stream) { |
| // When the server receives the early data, it will fail. |
| server_->ExpectSendAlert(kTlsAlertUnexpectedMessage); |
| server_->Handshake(); // Consume ClientHello |
| EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state()); |
| server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA); |
| } else { |
| // If it's datagram, we just discard the early data. |
| server_->Handshake(); // Consume ClientHello |
| EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state()); |
| } |
| |
| // The client now reads the ServerHello and fails. |
| ASSERT_EQ(TlsAgent::STATE_CONNECTING, client_->state()); |
| client_->ExpectSendAlert(kTlsAlertIllegalParameter); |
| client_->Handshake(); |
| client_->CheckErrorCode(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA); |
| } |
| |
| TEST_P(TlsConnectTls13, SendTooMuchEarlyData) { |
| EnsureTlsSetup(); |
| const char* big_message = "0123456789abcdef"; |
| const size_t short_size = strlen(big_message) - 1; |
| const PRInt32 short_length = static_cast<PRInt32>(short_size); |
| EXPECT_EQ(SECSuccess, |
| SSL_SetMaxEarlyDataSize(server_->ssl_fd(), |
| static_cast<PRUint32>(short_size))); |
| SetupForZeroRtt(); |
| |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| |
| client_->Handshake(); |
| CheckEarlyDataLimit(client_, short_size); |
| |
| PRInt32 sent; |
| // Writing more than the limit will succeed in TLS, but fail in DTLS. |
| if (variant_ == ssl_variant_stream) { |
| sent = PR_Write(client_->ssl_fd(), big_message, |
| static_cast<PRInt32>(strlen(big_message))); |
| } else { |
| sent = PR_Write(client_->ssl_fd(), big_message, |
| static_cast<PRInt32>(strlen(big_message))); |
| EXPECT_GE(0, sent); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| |
| // Try an exact-sized write now. |
| sent = PR_Write(client_->ssl_fd(), big_message, short_length); |
| } |
| EXPECT_EQ(short_length, sent); |
| |
| // Even a single octet write should now fail. |
| sent = PR_Write(client_->ssl_fd(), big_message, 1); |
| EXPECT_GE(0, sent); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| |
| // Process the ClientHello and read 0-RTT. |
| server_->Handshake(); |
| CheckEarlyDataLimit(server_, short_size); |
| |
| std::vector<uint8_t> buf(short_size + 1); |
| PRInt32 read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()); |
| EXPECT_EQ(short_length, read); |
| EXPECT_EQ(0, memcmp(big_message, buf.data(), short_size)); |
| |
| // Second read fails. |
| read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()); |
| EXPECT_EQ(SECFailure, read); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| |
| Handshake(); |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| TEST_P(TlsConnectTls13, ReceiveTooMuchEarlyData) { |
| EnsureTlsSetup(); |
| |
| const size_t limit = 5; |
| EXPECT_EQ(SECSuccess, SSL_SetMaxEarlyDataSize(server_->ssl_fd(), limit)); |
| SetupForZeroRtt(); |
| |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| |
| client_->Handshake(); // Send ClientHello |
| CheckEarlyDataLimit(client_, limit); |
| |
| server_->Handshake(); // Process ClientHello, send server flight. |
| |
| // Lift the limit on the client. |
| EXPECT_EQ(SECSuccess, |
| SSLInt_SetSocketMaxEarlyDataSize(client_->ssl_fd(), 1000)); |
| |
| // Send message |
| const char* message = "0123456789abcdef"; |
| const PRInt32 message_len = static_cast<PRInt32>(strlen(message)); |
| EXPECT_EQ(message_len, PR_Write(client_->ssl_fd(), message, message_len)); |
| |
| if (variant_ == ssl_variant_stream) { |
| // This error isn't fatal for DTLS. |
| ExpectAlert(server_, kTlsAlertUnexpectedMessage); |
| } |
| |
| server_->Handshake(); // This reads the early data and maybe throws an error. |
| if (variant_ == ssl_variant_stream) { |
| server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA); |
| } else { |
| EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state()); |
| } |
| CheckEarlyDataLimit(server_, limit); |
| |
| // Attempt to read early data. This will get an error. |
| std::vector<uint8_t> buf(strlen(message) + 1); |
| EXPECT_GT(0, PR_Read(server_->ssl_fd(), buf.data(), buf.capacity())); |
| if (variant_ == ssl_variant_stream) { |
| EXPECT_EQ(SSL_ERROR_HANDSHAKE_FAILED, PORT_GetError()); |
| } else { |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| } |
| |
| client_->Handshake(); // Process the server's first flight. |
| if (variant_ == ssl_variant_stream) { |
| client_->Handshake(); // Process the alert. |
| client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT); |
| } else { |
| server_->Handshake(); // Finish connecting. |
| EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); |
| } |
| } |
| |
| class PacketCoalesceFilter : public PacketFilter { |
| public: |
| PacketCoalesceFilter() : packet_data_() {} |
| |
| void SendCoalesced(std::shared_ptr<TlsAgent> agent) { |
| agent->SendDirect(packet_data_); |
| } |
| |
| protected: |
| PacketFilter::Action Filter(const DataBuffer& input, |
| DataBuffer* output) override { |
| packet_data_.Write(packet_data_.len(), input); |
| return DROP; |
| } |
| |
| private: |
| DataBuffer packet_data_; |
| }; |
| |
| TEST_P(TlsConnectTls13, ZeroRttOrdering) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| |
| // Send out the ClientHello. |
| client_->Handshake(); |
| |
| // Now, coalesce the next three things from the client: early data, second |
| // flight and 1-RTT data. |
| auto coalesce = std::make_shared<PacketCoalesceFilter>(); |
| client_->SetFilter(coalesce); |
| |
| // Send (and hold) early data. |
| static const std::vector<uint8_t> early_data = {3, 2, 1}; |
| EXPECT_EQ(static_cast<PRInt32>(early_data.size()), |
| PR_Write(client_->ssl_fd(), early_data.data(), early_data.size())); |
| |
| // Send (and hold) the second client handshake flight. |
| // The client sends EndOfEarlyData after seeing the server Finished. |
| server_->Handshake(); |
| client_->Handshake(); |
| |
| // Send (and hold) 1-RTT data. |
| static const std::vector<uint8_t> late_data = {7, 8, 9, 10}; |
| EXPECT_EQ(static_cast<PRInt32>(late_data.size()), |
| PR_Write(client_->ssl_fd(), late_data.data(), late_data.size())); |
| |
| // Now release them all at once. |
| coalesce->SendCoalesced(client_); |
| |
| // Now ensure that the three steps are exposed in the right order on the |
| // server: delivery of early data, handshake callback, delivery of 1-RTT. |
| size_t step = 0; |
| server_->SetHandshakeCallback([&step](TlsAgent*) { |
| EXPECT_EQ(1U, step); |
| ++step; |
| }); |
| |
| std::vector<uint8_t> buf(10); |
| PRInt32 read = PR_Read(server_->ssl_fd(), buf.data(), buf.size()); |
| ASSERT_EQ(static_cast<PRInt32>(early_data.size()), read); |
| buf.resize(read); |
| EXPECT_EQ(early_data, buf); |
| EXPECT_EQ(0U, step); |
| ++step; |
| |
| // The third read should be after the handshake callback and should return the |
| // data that was sent after the handshake completed. |
| buf.resize(10); |
| read = PR_Read(server_->ssl_fd(), buf.data(), buf.size()); |
| ASSERT_EQ(static_cast<PRInt32>(late_data.size()), read); |
| buf.resize(read); |
| EXPECT_EQ(late_data, buf); |
| EXPECT_EQ(2U, step); |
| } |
| |
| // Early data remains available after the handshake completes for TLS. |
| TEST_F(TlsConnectStreamTls13, ZeroRttLateReadTls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. |
| const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8}; |
| PRInt32 rv = PR_Write(client_->ssl_fd(), data, sizeof(data)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), rv); |
| |
| // Consume the ClientHello and generate ServerHello..Finished. |
| server_->Handshake(); |
| |
| // Read some of the data. |
| std::vector<uint8_t> small_buffer(1 + sizeof(data) / 2); |
| rv = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size()); |
| EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), rv); |
| EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size())); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| |
| // After the handshake, it should be possible to read the remainder. |
| uint8_t big_buf[100]; |
| rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - small_buffer.size()), rv); |
| EXPECT_EQ(0, memcmp(&data[small_buffer.size()], big_buf, |
| sizeof(data) - small_buffer.size())); |
| |
| // And that's all there is to read. |
| rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf)); |
| EXPECT_GT(0, rv); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| } |
| |
| // Early data that arrives before the handshake can be read after the handshake |
| // is complete. |
| TEST_F(TlsConnectDatagram13, ZeroRttLateReadDtls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. |
| const uint8_t data[] = {1, 2, 3}; |
| PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| |
| // Reading at the server should return the early data, which was buffered. |
| uint8_t buf[sizeof(data) + 1] = {0}; |
| PRInt32 read = PR_Read(server_->ssl_fd(), buf, sizeof(buf)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read); |
| EXPECT_EQ(0, memcmp(data, buf, sizeof(data))); |
| } |
| |
| class PacketHolder : public PacketFilter { |
| public: |
| PacketHolder() = default; |
| |
| virtual Action Filter(const DataBuffer& input, DataBuffer* output) { |
| packet_ = input; |
| Disable(); |
| return DROP; |
| } |
| |
| const DataBuffer& packet() const { return packet_; } |
| |
| private: |
| DataBuffer packet_; |
| }; |
| |
| // Early data that arrives late is discarded for DTLS. |
| TEST_F(TlsConnectDatagram13, ZeroRttLateArrivalDtls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. Twice, so that we can read bits of it. |
| const uint8_t data[] = {1, 2, 3}; |
| PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written); |
| |
| // Block and capture the next packet. |
| auto holder = std::make_shared<PacketHolder>(); |
| client_->SetFilter(holder); |
| written = PR_Write(client_->ssl_fd(), data, sizeof(data)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written); |
| EXPECT_FALSE(holder->enabled()) << "the filter should disable itself"; |
| |
| // Consume the ClientHello and generate ServerHello..Finished. |
| server_->Handshake(); |
| |
| // Read some of the data. |
| std::vector<uint8_t> small_buffer(sizeof(data)); |
| PRInt32 read = |
| PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size()); |
| |
| EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), read); |
| EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size())); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| |
| server_->SendDirect(holder->packet()); |
| |
| // Reading now should return nothing, even though a valid packet was |
| // delivered. |
| read = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size()); |
| EXPECT_GT(0, read); |
| EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError()); |
| } |
| |
| // Early data reads in TLS should be coalesced. |
| TEST_F(TlsConnectStreamTls13, ZeroRttCoalesceReadTls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. In two writes. |
| const uint8_t data[] = {1, 2, 3, 4, 5, 6}; |
| PRInt32 written = PR_Write(client_->ssl_fd(), data, 1); |
| EXPECT_EQ(1, written); |
| |
| written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written); |
| |
| // Consume the ClientHello and generate ServerHello..Finished. |
| server_->Handshake(); |
| |
| // Read all of the data. |
| std::vector<uint8_t> buffer(sizeof(data)); |
| PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size()); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read); |
| EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data))); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| } |
| |
| // Early data reads in DTLS should not be coalesced. |
| TEST_F(TlsConnectDatagram13, ZeroRttNoCoalesceReadDtls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. In two writes. |
| const uint8_t data[] = {1, 2, 3, 4, 5, 6}; |
| PRInt32 written = PR_Write(client_->ssl_fd(), data, 1); |
| EXPECT_EQ(1, written); |
| |
| written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written); |
| |
| // Consume the ClientHello and generate ServerHello..Finished. |
| server_->Handshake(); |
| |
| // Try to read all of the data. |
| std::vector<uint8_t> buffer(sizeof(data)); |
| PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size()); |
| EXPECT_EQ(1, read); |
| EXPECT_EQ(0, memcmp(data, buffer.data(), 1)); |
| |
| // Read the remainder. |
| read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size()); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), read); |
| EXPECT_EQ(0, memcmp(data + 1, buffer.data(), sizeof(data) - 1)); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| } |
| |
| // Early data reads in DTLS should fail if the buffer is too small. |
| TEST_F(TlsConnectDatagram13, ZeroRttShortReadDtls) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| client_->Handshake(); // ClientHello |
| |
| // Write some early data. In two writes. |
| const uint8_t data[] = {1, 2, 3, 4, 5, 6}; |
| PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data)); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written); |
| |
| // Consume the ClientHello and generate ServerHello..Finished. |
| server_->Handshake(); |
| |
| // Try to read all of the data into a small buffer. |
| std::vector<uint8_t> buffer(sizeof(data)); |
| PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), 1); |
| EXPECT_GT(0, read); |
| EXPECT_EQ(SSL_ERROR_RX_SHORT_DTLS_READ, PORT_GetError()); |
| |
| // Read again with more space. |
| read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size()); |
| EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read); |
| EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data))); |
| |
| Handshake(); // Complete the handshake. |
| ExpectEarlyDataAccepted(true); |
| CheckConnected(); |
| } |
| |
| // There are few ways in which TLS uses the clock and most of those operate on |
| // timescales that would be ridiculous to wait for in a test. This is the one |
| // test we have that uses the real clock. It tests that time passes by checking |
| // that a small sleep results in rejection of early data. 0-RTT has a |
| // configurable timer, which makes it ideal for this. |
| TEST_F(TlsConnectStreamTls13, TimePassesByDefault) { |
| // Calling EnsureTlsSetup() replaces the time function on client and server, |
| // and sets up anti-replay, which we don't want, so initialize each directly. |
| client_->EnsureTlsSetup(); |
| server_->EnsureTlsSetup(); |
| // StartConnect() calls EnsureTlsSetup(), so avoid that too. |
| client_->StartConnect(); |
| server_->StartConnect(); |
| |
| // Set a tiny anti-replay window. This has to be at least 2 milliseconds to |
| // have any chance of being relevant as that is the smallest window that we |
| // can detect. Anything smaller rounds to zero. |
| static const unsigned int kTinyWindowMs = 5; |
| ResetAntiReplay(static_cast<PRTime>(kTinyWindowMs * PR_USEC_PER_MSEC)); |
| server_->SetAntiReplayContext(anti_replay_); |
| |
| ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); |
| ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3); |
| server_->Set0RttEnabled(true); |
| Handshake(); |
| CheckConnected(); |
| SendReceive(); // Absorb a session ticket. |
| CheckKeys(); |
| |
| // Clear the first window. |
| PR_Sleep(PR_MillisecondsToInterval(kTinyWindowMs)); |
| |
| Reset(); |
| client_->EnsureTlsSetup(); |
| server_->EnsureTlsSetup(); |
| client_->StartConnect(); |
| server_->StartConnect(); |
| |
| // Early data is rejected by the server only if time passes for it as well. |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, false, []() { |
| // Sleep long enough that we minimize the risk of our RTT estimation being |
| // duped by stutters in test execution. This is very long to allow for |
| // flaky and low-end hardware, especially what our CI runs on. |
| PR_Sleep(PR_MillisecondsToInterval(1000)); |
| return true; |
| }); |
| Handshake(); |
| ExpectEarlyDataAccepted(false); |
| CheckConnected(); |
| } |
| |
| // Test that SSL_CreateAntiReplayContext doesn't pass bad inputs. |
| TEST_F(TlsConnectStreamTls13, BadAntiReplayArgs) { |
| SSLAntiReplayContext* p; |
| // Zero or negative window. |
| EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, -1, 1, 1, &p)); |
| EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); |
| EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 0, 1, 1, &p)); |
| EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); |
| // Zero k. |
| EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 0, 1, &p)); |
| EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); |
| // Zero bits. |
| EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 0, &p)); |
| EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); |
| EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 1, nullptr)); |
| EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); |
| |
| // Prove that these parameters do work, even if they are useless.. |
| EXPECT_EQ(SECSuccess, SSL_CreateAntiReplayContext(0, 1, 1, 1, &p)); |
| ASSERT_NE(nullptr, p); |
| ScopedSSLAntiReplayContext ctx(p); |
| |
| // The socket isn't a client or server until later, so configuring a client |
| // should work OK. |
| client_->EnsureTlsSetup(); |
| EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), ctx.get())); |
| EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), nullptr)); |
| } |
| |
| // See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher |
| TEST_P(TlsConnectTls13, ZeroRttDifferentCompatibleCipher) { |
| EnsureTlsSetup(); |
| server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256); |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| // Change the ciphersuite. Resumption is OK because the hash is the same, but |
| // early data will be rejected. |
| server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256); |
| ExpectResumption(RESUME_TICKET); |
| |
| StartConnect(); |
| ZeroRttSendReceive(true, false); |
| |
| Handshake(); |
| ExpectEarlyDataAccepted(false); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher |
| TEST_P(TlsConnectTls13, ZeroRttDifferentIncompatibleCipher) { |
| EnsureTlsSetup(); |
| server_->EnableSingleCipher(TLS_AES_256_GCM_SHA384); |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| // Resumption is rejected because the hash is different. |
| server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256); |
| ExpectResumption(RESUME_NONE); |
| |
| StartConnect(); |
| ZeroRttSendReceive(true, false); |
| |
| Handshake(); |
| ExpectEarlyDataAccepted(false); |
| CheckConnected(); |
| SendReceive(); |
| } |
| |
| // The client failing to provide EndOfEarlyData results in failure. |
| // After 0-RTT working perfectly, things fall apart later. |
| // The server is unable to detect the change in keys, so it fails decryption. |
| // The client thinks everything has worked until it gets the alert. |
| TEST_F(TlsConnectStreamTls13, SuppressEndOfEarlyDataClientOnly) { |
| SetupForZeroRtt(); |
| client_->Set0RttEnabled(true); |
| server_->Set0RttEnabled(true); |
| client_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true); |
| ExpectResumption(RESUME_TICKET); |
| ZeroRttSendReceive(true, true); |
| ExpectAlert(server_, kTlsAlertBadRecordMac); |
| Handshake(); |
| EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state()); |
| EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state()); |
| server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ); |
| client_->Handshake(); |
| EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state()); |
| client_->CheckErrorCode(SSL_ERROR_BAD_MAC_ALERT); |
| } |
| |
| TEST_P(TlsConnectGeneric, SuppressEndOfEarlyDataNoZeroRtt) { |
| EnsureTlsSetup(); |
| client_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true); |
| server_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true); |
| Connect(); |
| SendReceive(); |
| } |
| |
| #ifndef NSS_DISABLE_TLS_1_3 |
| INSTANTIATE_TEST_SUITE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest, |
| TlsConnectTestBase::kTlsVariantsAll); |
| #endif |
| |
| } // namespace nss_test |