Bug 1348720 - Test alerts more thoroughly, r=ttaubert
authorMartin Thomson <martin.thomson@gmail.com>
Mon, 20 Mar 2017 14:38:26 +1100
changeset 13242 85e168b055dbd4130dfacc218374b808f063c4fa
parent 13241 2799578a8acf2e22184f6d9701d264c55d41b34a
child 13243 d8efc3d7a72f7080c9a86bc678a096f559aea2a4
push id2111
push usermartin.thomson@gmail.com
push dateThu, 23 Mar 2017 11:00:50 +0000
reviewersttaubert
bugs1348720
Bug 1348720 - Test alerts more thoroughly, r=ttaubert This adds alert expectations to all tests that generate them. I've chosen to retain the alert recording that is done on a small number of tests, because that allows us to verify that the alerts actually hit the wire. However, the primary means of testing alerts will be through the new TlsAgent::ExpectAlert method and the TlsConnectTestBase::ExpectAlert and TlsConnectTestBase::ConnectExpectAlert methods which are wrappers around the basic function (the latter wraps ConnectExpectFail as well). There are a few places where this change wasn't mechanical, but for the most part this only required adding a call to the right version of ExpectAlert.
gtests/ssl_gtest/ssl_0rtt_unittest.cc
gtests/ssl_gtest/ssl_agent_unittest.cc
gtests/ssl_gtest/ssl_auth_unittest.cc
gtests/ssl_gtest/ssl_cert_ext_unittest.cc
gtests/ssl_gtest/ssl_damage_unittest.cc
gtests/ssl_gtest/ssl_dhe_unittest.cc
gtests/ssl_gtest/ssl_ecdh_unittest.cc
gtests/ssl_gtest/ssl_ems_unittest.cc
gtests/ssl_gtest/ssl_exporter_unittest.cc
gtests/ssl_gtest/ssl_extension_unittest.cc
gtests/ssl_gtest/ssl_gather_unittest.cc
gtests/ssl_gtest/ssl_hrr_unittest.cc
gtests/ssl_gtest/ssl_loopback_unittest.cc
gtests/ssl_gtest/ssl_resumption_unittest.cc
gtests/ssl_gtest/ssl_skip_unittest.cc
gtests/ssl_gtest/ssl_staticrsa_unittest.cc
gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
gtests/ssl_gtest/ssl_version_unittest.cc
gtests/ssl_gtest/tls_agent.cc
gtests/ssl_gtest/tls_agent.h
gtests/ssl_gtest/tls_connect.cc
gtests/ssl_gtest/tls_connect.h
gtests/ssl_gtest/tls_parser.h
--- a/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -19,18 +19,16 @@ extern "C" {
 #include "tls_connect.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
 
 namespace nss_test {
 
 TEST_P(TlsConnectTls13, ZeroRtt) {
   SetupForZeroRtt();
-  client_->SetExpectedAlertSentCount(1);
-  server_->SetExpectedAlertReceivedCount(1);
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
   ZeroRttSendReceive(true, true);
   Handshake();
   ExpectEarlyDataAccepted(true);
   CheckConnected();
   SendReceive();
@@ -100,18 +98,16 @@ TEST_P(TlsConnectTls13, ZeroRttServerOnl
   SendReceive();
   CheckKeys();
 }
 
 TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpn) {
   EnableAlpn();
   SetupForZeroRtt();
   EnableAlpn();
-  client_->SetExpectedAlertSentCount(1);
-  server_->SetExpectedAlertReceivedCount(1);
   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;
   });
@@ -154,16 +150,17 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
   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");
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
     return true;
   });
   Handshake();
   client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 // Set up with no ALPN and then set the client so it thinks it has ALPN.
@@ -173,16 +170,17 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
   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");
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
     return true;
   });
   Handshake();
   client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 // Remove the old ALPN value and so the client will not offer early data.
@@ -223,16 +221,20 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
   client_->StartConnect();
   server_->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 (mode_ == 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 (mode_ == STREAM) {
@@ -260,17 +262,23 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   client_->StartConnect();
   server_->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);
-  ZeroRttSendReceive(true, false);
+  ZeroRttSendReceive(true, false, [this]() {
+    client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+    if (mode_ == STREAM) {
+      server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+    }
+    return true;
+  });
 
   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.
@@ -296,19 +304,18 @@ TEST_P(TlsConnectTls13, SendTooMuchEarly
   const size_t short_size = strlen(big_message) - 1;
   const PRInt32 short_length = static_cast<PRInt32>(short_size);
   SSLInt_SetMaxEarlyDataSize(static_cast<PRUint32>(short_size));
   SetupForZeroRtt();
 
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
-  client_->SetExpectedAlertSentCount(1);
-  server_->SetExpectedAlertReceivedCount(1);
 
+  ExpectAlert(client_, kTlsAlertEndOfEarlyData);
   client_->Handshake();
   CheckEarlyDataLimit(client_, short_size);
 
   PRInt32 sent;
   // Writing more than the limit will succeed in TLS, but fail in DTLS.
   if (mode_ == STREAM) {
     sent = PR_Write(client_->ssl_fd(), big_message,
                     static_cast<PRInt32>(strlen(big_message)));
@@ -352,37 +359,41 @@ TEST_P(TlsConnectTls13, ReceiveTooMuchEa
   const size_t limit = 5;
   SSLInt_SetMaxEarlyDataSize(limit);
   SetupForZeroRtt();
 
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
 
+  client_->ExpectSendAlert(kTlsAlertEndOfEarlyData);
   client_->Handshake();  // Send ClientHello
   CheckEarlyDataLimit(client_, limit);
 
   // 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 (mode_ == STREAM) {
+    // This error isn't fatal for DTLS.
+    ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+  }
   server_->Handshake();  // Process ClientHello, send server flight.
   server_->Handshake();  // Just to make sure that we don't read ahead.
   CheckEarlyDataLimit(server_, limit);
 
   // Attempt to read early data.
   std::vector<uint8_t> buf(strlen(message) + 1);
   EXPECT_GT(0, PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()));
   if (mode_ == STREAM) {
-    // This error isn't fatal for DTLS.
     server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA);
   }
 
   client_->Handshake();  // Process the handshake.
   client_->Handshake();  // Process the alert.
   if (mode_ == STREAM) {
     client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
   }
--- a/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -51,23 +51,25 @@ const static uint8_t kCannedTls13ServerH
     0x23, 0x17, 0x64, 0x23, 0x03, 0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65,
     0x24, 0xa1, 0x6c, 0xa9, 0x80, 0x8f, 0x2c, 0xac, 0x0a, 0xea, 0x53, 0x3a,
     0xcb, 0xe3, 0x08, 0x84, 0xae, 0x19};
 static const char *k0RttData = "ABCDEF";
 
 TEST_P(TlsAgentTest, EarlyFinished) {
   DataBuffer buffer;
   MakeTrivialHandshakeRecord(kTlsHandshakeFinished, 0, &buffer);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
 
 TEST_P(TlsAgentTest, EarlyCertificateVerify) {
   DataBuffer buffer;
   MakeTrivialHandshakeRecord(kTlsHandshakeCertificateVerify, 0, &buffer);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
 }
 
 TEST_P(TlsAgentTestClient13, CannedHello) {
   DataBuffer buffer;
   EnsureInit();
   DataBuffer server_hello;
@@ -85,16 +87,17 @@ TEST_P(TlsAgentTestClient13, EncryptedEx
   DataBuffer encrypted_extensions;
   MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
                        &encrypted_extensions, 1);
   server_hello.Append(encrypted_extensions);
   DataBuffer buffer;
   MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
              server_hello.data(), server_hello.len(), &buffer);
   EnsureInit();
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
 }
 
 TEST_F(TlsAgentStreamTestClient, EncryptedExtensionsInClearTwoPieces) {
   DataBuffer server_hello;
   MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
                        sizeof(kCannedTls13ServerHello), &server_hello);
@@ -109,16 +112,17 @@ TEST_F(TlsAgentStreamTestClient, Encrypt
   DataBuffer buffer2;
   MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
              server_hello.data() + 20, server_hello.len() - 20, &buffer2);
 
   EnsureInit();
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
                           SSL_LIBRARY_VERSION_TLS_1_3);
   ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
 }
 
 TEST_F(TlsAgentDgramTestClient, EncryptedExtensionsInClearTwoPieces) {
   DataBuffer server_hello_frag1;
   MakeHandshakeMessageFragment(
       kTlsHandshakeServerHello, kCannedTls13ServerHello,
@@ -139,16 +143,17 @@ TEST_F(TlsAgentDgramTestClient, Encrypte
   DataBuffer buffer2;
   MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
              server_hello_frag2.data(), server_hello_frag2.len(), &buffer2, 1);
 
   EnsureInit();
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
                           SSL_LIBRARY_VERSION_TLS_1_3);
   ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
 }
 
 TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
   EnsureInit();
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                           SSL_LIBRARY_VERSION_TLS_1_3);
@@ -169,16 +174,17 @@ TEST_F(TlsAgentStreamTestClient, Set0Rtt
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                           SSL_LIBRARY_VERSION_TLS_1_3);
   agent_->StartConnect();
   agent_->Set0RttEnabled(true);
   DataBuffer buffer;
   MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
              reinterpret_cast<const uint8_t *>(k0RttData), strlen(k0RttData),
              &buffer);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
 }
 
 // The server is allowing 0-RTT but the client doesn't offer it,
 // so trial decryption isn't engaged and 0-RTT messages cause
 // an error.
 TEST_F(TlsAgentStreamTestServer, Set0RttOptionClientHelloThenRead) {
@@ -189,16 +195,17 @@ TEST_F(TlsAgentStreamTestServer, Set0Rtt
   agent_->Set0RttEnabled(true);
   DataBuffer buffer;
   MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
              kCannedTls13ClientHello, sizeof(kCannedTls13ClientHello), &buffer);
   ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
   MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
              reinterpret_cast<const uint8_t *>(k0RttData), strlen(k0RttData),
              &buffer);
+  ExpectAlert(kTlsAlertBadRecordMac);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR, SSL_ERROR_BAD_MAC_READ);
 }
 
 INSTANTIATE_TEST_CASE_P(AgentTests, TlsAgentTest,
                         ::testing::Combine(TlsAgentTestBase::kTlsRolesAll,
                                            TlsConnectTestBase::kTlsModesStream,
                                            TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(ClientTests, TlsAgentTestClient,
--- a/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -193,17 +193,17 @@ TEST_P(TlsConnectTls12, ClientAuthNoSigA
   server_->SetPacketFilter(filter);
   auto capture_cert_verify =
       std::make_shared<TlsInspectorRecordHandshakeMessage>(
           kTlsHandshakeCertificateVerify);
   client_->SetPacketFilter(capture_cert_verify);
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
 
   // We're expecting a bad signature here because we tampered with a handshake
   // message (CertReq). Previously, without the SHA-1 fallback, we would've
   // seen a malformed record alert.
   server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
 
   CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pkcs1_sha1, 1024);
@@ -279,17 +279,17 @@ TEST_P(TlsConnectTls12, SignatureSchemeC
   Connect();
 }
 
 // In TLS 1.3, curve and hash are coupled.
 TEST_P(TlsConnectTls13, SignatureSchemeCurveMismatch) {
   Reset(TlsAgent::kServerEcdsa256);
   client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 // Configuring a P-256 cert with only SHA-384 signatures is OK in TLS 1.2.
 TEST_P(TlsConnectTls12, SignatureSchemeBadConfig) {
   Reset(TlsAgent::kServerEcdsa256);  // P-256 cert can't be used.
   server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
@@ -297,17 +297,17 @@ TEST_P(TlsConnectTls12, SignatureSchemeB
   Connect();
 }
 
 // A P-256 certificate in TLS 1.3 needs a SHA-256 signature scheme.
 TEST_P(TlsConnectTls13, SignatureSchemeBadConfig) {
   Reset(TlsAgent::kServerEcdsa256);  // P-256 cert can't be used.
   server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 // Where there is no overlap on signature schemes, we still connect successfully
 // if we aren't going to use a signature.
 TEST_P(TlsConnectGenericPre13, SignatureAlgorithmNoOverlapStaticRsa) {
   client_->SetSignatureSchemes(SignatureSchemeRsaSha384,
@@ -320,17 +320,17 @@ TEST_P(TlsConnectGenericPre13, Signature
 }
 
 TEST_P(TlsConnectTls12Plus, SignatureAlgorithmNoOverlapEcdsa) {
   Reset(TlsAgent::kServerEcdsa256);
   client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
   server_->SetSignatureSchemes(SignatureSchemeEcdsaSha256,
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
 }
 
 // Pre 1.2, a mismatch on signature algorithms shouldn't affect anything.
 TEST_P(TlsConnectPre12, SignatureAlgorithmNoOverlapEcdsa) {
   Reset(TlsAgent::kServerEcdsa256);
   client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
@@ -339,27 +339,27 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256));
   Connect();
 }
 
 // The signature_algorithms extension is mandatory in TLS 1.3.
 TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) {
   client_->SetPacketFilter(
       std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertMissingExtension);
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
 }
 
 // TLS 1.2 has trouble detecting this sort of modification: it uses SHA1 and
 // only fails when the Finished is checked.
 TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) {
   client_->SetPacketFilter(
       std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) {
   server_->SetSignatureSchemes(SignatureSchemeRsaSha384,
                                PR_ARRAY_SIZE(SignatureSchemeRsaSha384));
   server_->RequestClientAuth(false);
--- a/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -185,17 +185,17 @@ TEST_P(TlsConnectGenericPre13, OcspMangl
                                       SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
   EXPECT_TRUE(
       server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData));
 
   static const uint8_t val[] = {1};
   auto replacer = std::make_shared<TlsExtensionReplacer>(
       ssl_cert_status_xtn, DataBuffer(val, sizeof(val)));
   server_->SetPacketFilter(replacer);
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 TEST_P(TlsConnectGeneric, OcspSuccess) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
--- a/gtests/ssl_gtest/ssl_damage_unittest.cc
+++ b/gtests/ssl_gtest/ssl_damage_unittest.cc
@@ -28,32 +28,37 @@ TEST_F(TlsConnectTest, DamageSecretHandl
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->StartConnect();
   client_->StartConnect();
   client_->Handshake();
   server_->Handshake();
-  std::cerr << "Damaging HS secret\n";
+  std::cerr << "Damaging HS secret" << std::endl;
   SSLInt_DamageClientHsTrafficSecret(server_->ssl_fd());
   client_->Handshake();
-  server_->Handshake();
   // The client thinks it has connected.
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+
+  ExpectAlert(server_, kTlsAlertDecryptError);
+  server_->Handshake();
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
   client_->Handshake();
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
 }
 
 TEST_F(TlsConnectTest, DamageSecretHandleServerFinished) {
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
+  client_->ExpectSendAlert(kTlsAlertDecryptError);
+  // The server can't read the client's alert, so it also sends an alert.
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   server_->SetPacketFilter(std::make_shared<AfterRecordN>(
       server_, client_,
       0,  // ServerHello.
       [this]() { SSLInt_DamageServerHsTrafficSecret(client_->ssl_fd()); }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
 }
--- a/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -92,17 +92,17 @@ TEST_P(TlsConnectGenericPre13, ConnectFf
   EnableOnlyDheCiphers();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(),
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
 
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     Connect();
     CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
   } else {
-    ConnectExpectFail();
+    ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
     client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
     server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   }
 }
 
 class TlsDheServerKeyExchangeDamager : public TlsHandshakeFilter {
  public:
   TlsDheServerKeyExchangeDamager() {}
@@ -125,17 +125,17 @@ class TlsDheServerKeyExchangeDamager : p
 // invalidate the signature over the ServerKeyShare. That's ok, NSS won't check
 // the signature until everything else has been checked.
 TEST_P(TlsConnectGenericPre13, DamageServerKeyShare) {
   EnableOnlyDheCiphers();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   server_->SetPacketFilter(std::make_shared<TlsDheServerKeyExchangeDamager>());
 
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
 
   client_->CheckErrorCode(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 class TlsDheSkeChangeY : public TlsHandshakeFilter {
  public:
   enum ChangeYTo {
@@ -290,16 +290,21 @@ TEST_P(TlsDamageDHYTest, DamageServerY) 
   if (std::get<3>(GetParam())) {
     EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                         SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   }
   TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
   server_->SetPacketFilter(
       std::make_shared<TlsDheSkeChangeYServer>(change, true));
 
+  if (change == TlsDheSkeChangeY::kYZeroPad) {
+    ExpectAlert(client_, kTlsAlertDecryptError);
+  } else {
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
+  }
   ConnectExpectFail();
   if (change == TlsDheSkeChangeY::kYZeroPad) {
     // Zero padding Y only manifests in a signature failure.
     // In TLS 1.0 and 1.1, the client reports a device error.
     if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
       client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
     } else {
       client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
@@ -322,16 +327,21 @@ TEST_P(TlsDamageDHYTest, DamageClientY) 
       std::make_shared<TlsDheSkeChangeYServer>(TlsDheSkeChangeY::kYZero, false);
   server_->SetPacketFilter(server_filter);
 
   // The client filter does the damage.
   TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
   client_->SetPacketFilter(
       std::make_shared<TlsDheSkeChangeYClient>(change, server_filter));
 
+  if (change == TlsDheSkeChangeY::kYZeroPad) {
+    ExpectAlert(server_, kTlsAlertDecryptError);
+  } else {
+    ExpectAlert(server_, kTlsAlertHandshakeFailure);
+  }
   ConnectExpectFail();
   if (change == TlsDheSkeChangeY::kYZeroPad) {
     // Zero padding Y only manifests in a finished error.
     client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
     server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
   } else {
     client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
     server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
@@ -380,17 +390,17 @@ class TlsDheSkeMakePEven : public TlsHan
   }
 };
 
 // Even without requiring named groups, an even value for p is bad news.
 TEST_P(TlsConnectGenericPre13, MakeDhePEven) {
   EnableOnlyDheCiphers();
   server_->SetPacketFilter(std::make_shared<TlsDheSkeMakePEven>());
 
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
 
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 class TlsDheSkeZeroPadP : public TlsHandshakeFilter {
  public:
   virtual PacketFilter::Action FilterHandshake(
@@ -411,17 +421,17 @@ class TlsDheSkeZeroPadP : public TlsHand
   }
 };
 
 // Zero padding only causes signature failure.
 TEST_P(TlsConnectGenericPre13, PadDheP) {
   EnableOnlyDheCiphers();
   server_->SetPacketFilter(std::make_shared<TlsDheSkeZeroPadP>());
 
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertDecryptError);
 
   // In TLS 1.0 and 1.1, the client reports a device error.
   if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
     client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
   } else {
     client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
   }
   server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
@@ -470,17 +480,17 @@ TEST_P(TlsConnectGenericPre13, NamedGrou
 TEST_P(TlsConnectTls13, NamedGroupMismatch13) {
   EnableOnlyDheCiphers();
   static const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ffdhe_3072};
   static const std::vector<SSLNamedGroup> client_groups = {
       ssl_grp_ec_secp256r1};
   server_->ConfigNamedGroups(server_groups);
   client_->ConfigNamedGroups(client_groups);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 // Even though the client doesn't have DHE groups enabled the server assumes it
 // does. The client requires named groups and thus does not accept FF3072 as
 // custom group in contrast to the previous test.
 TEST_P(TlsConnectGenericPre13, RequireNamedGroupsMismatchPre13) {
@@ -488,17 +498,17 @@ TEST_P(TlsConnectGenericPre13, RequireNa
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   static const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ffdhe_3072};
   static const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1,
                                                            ssl_grp_ffdhe_2048};
   server_->ConfigNamedGroups(server_groups);
   client_->ConfigNamedGroups(client_groups);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 TEST_P(TlsConnectGenericPre13, PreferredFfdhe) {
   EnableOnlyDheCiphers();
   static const SSLDHEGroupType groups[] = {ssl_ff_dhe_3072_group,
                                            ssl_ff_dhe_2048_group};
@@ -518,17 +528,17 @@ TEST_P(TlsConnectGenericPre13, MismatchD
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   static const SSLDHEGroupType serverGroups[] = {ssl_ff_dhe_3072_group};
   EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(server_->ssl_fd(), serverGroups,
                                             PR_ARRAY_SIZE(serverGroups)));
   static const SSLDHEGroupType clientGroups[] = {ssl_ff_dhe_2048_group};
   EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(client_->ssl_fd(), clientGroups,
                                             PR_ARRAY_SIZE(clientGroups)));
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 TEST_P(TlsConnectTls13, ResumeFfdhe) {
   EnableOnlyDheCiphers();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
@@ -602,13 +612,13 @@ TEST_P(TlsConnectGenericPre13, InvalidDE
   Reset(TlsAgent::kServerDsa);
 
   const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ffdhe_2048};
   client_->ConfigNamedGroups(client_groups);
 
   server_->SetPacketFilter(std::make_shared<TlsDheSkeChangeSignature>(
       version_, kBogusDheSignature, sizeof(kBogusDheSignature)));
 
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertDecryptError);
   client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 }  // namespace nss_test
--- a/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -223,29 +223,29 @@ class TlsKeyExchangeGroupCapture : publi
 // P-256 is supported by the client (<= 1.2 only).
 TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
   EnsureTlsSetup();
   client_->SetPacketFilter(
       std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
   auto group_capture = std::make_shared<TlsKeyExchangeGroupCapture>();
   server_->SetPacketFilter(group_capture);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 
   EXPECT_EQ(ssl_grp_ec_secp256r1, group_capture->group());
 }
 
 // Supported groups is mandatory in TLS 1.3.
 TEST_P(TlsConnectTls13, DropSupportedGroupExtension) {
   EnsureTlsSetup();
   client_->SetPacketFilter(
       std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertMissingExtension);
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
 }
 
 // If we only have a lame group, we fall back to static RSA.
 TEST_P(TlsConnectGenericPre13, UseLameGroup) {
   const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp192r1};
   client_->ConfigNamedGroups(groups);
@@ -480,17 +480,17 @@ TEST_P(TlsConnectGeneric, P256ClientAndC
 
   // The client sends a P256 key share while the server prefers 25519.
   const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1};
   const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_curve25519};
 
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 TEST_P(TlsKeyExchangeTest13, MultipleClientShares) {
   EnsureKeyShareSetup();
 
   // The client sends 25519 and P256 key shares. The server prefers P256,
@@ -557,24 +557,24 @@ class ECCServerKEXFilter : public TlsHan
     output->Write(3, 0U, 1);                // point length 0
     return CHANGE;
   }
 };
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyServerPoint) {
   // add packet filter
   server_->SetPacketFilter(std::make_shared<ECCServerKEXFilter>());
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
   // add packet filter
   client_->SetPacketFilter(std::make_shared<ECCClientKEXFilter>());
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
 }
 
 INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
                                            TlsConnectTestBase::kTlsV11Plus));
 
 #ifndef NSS_DISABLE_TLS_1_3
--- a/gtests/ssl_gtest/ssl_ems_unittest.cc
+++ b/gtests/ssl_gtest/ssl_ems_unittest.cc
@@ -74,21 +74,17 @@ TEST_P(TlsConnectGenericPre13, ConnectEx
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretResumeWithout) {
   EnableExtendedMasterSecret();
   Connect();
 
   Reset();
   server_->EnableExtendedMasterSecret();
-  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
-  server_->SetPacketFilter(alert_recorder);
-  ConnectExpectFail();
-  EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-  EXPECT_EQ(kTlsAlertHandshakeFailure, alert_recorder->description());
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectNormalResumeWithExtendedMasterSecret) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
   ExpectExtendedMasterSecret(false);
   Connect();
 
   Reset();
--- a/gtests/ssl_gtest/ssl_exporter_unittest.cc
+++ b/gtests/ssl_gtest/ssl_exporter_unittest.cc
@@ -86,18 +86,17 @@ int32_t RegularExporterShouldFail(TlsAge
                             strlen(kExporterLabel), PR_TRUE, kExporterContext,
                             sizeof(kExporterContext), val, sizeof(val)))
       << "regular exporter should fail";
   return 0;
 }
 
 TEST_P(TlsConnectTls13, EarlyExporter) {
   SetupForZeroRtt();
-  client_->SetExpectedAlertSentCount(1);
-  server_->SetExpectedAlertReceivedCount(1);
+  ExpectAlert(client_, kTlsAlertEndOfEarlyData);
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
 
   client_->Handshake();  // Send ClientHello.
   uint8_t client_value[10] = {0};
   RegularExporterShouldFail(client_.get(), nullptr, 0);
   EXPECT_EQ(SECSuccess,
--- a/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -163,74 +163,24 @@ class TlsExtensionTestBase : public TlsC
  protected:
   TlsExtensionTestBase(Mode mode, uint16_t version)
       : TlsConnectTestBase(mode, version) {}
   TlsExtensionTestBase(const std::string& mode, uint16_t version)
       : TlsConnectTestBase(mode, version) {}
 
   void ClientHelloErrorTest(std::shared_ptr<PacketFilter> filter,
                             uint8_t desc = kTlsAlertDecodeError) {
-    SSLAlert alert;
-
-    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
-    server_->SetPacketFilter(alert_recorder);
     client_->SetPacketFilter(filter);
-    ConnectExpectFail();
-
-    EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-    EXPECT_EQ(desc, alert_recorder->description());
-
-    // verify no alerts received by the server
-    EXPECT_EQ(0U, server_->alert_received_count());
-
-    // verify the alert sent by the server
-    EXPECT_EQ(1U, server_->alert_sent_count());
-    EXPECT_TRUE(server_->GetLastAlertSent(&alert));
-    EXPECT_EQ(kTlsAlertFatal, alert.level);
-    EXPECT_EQ(desc, alert.description);
-
-    // verify the alert received by the client
-    EXPECT_EQ(1U, client_->alert_received_count());
-    EXPECT_TRUE(client_->GetLastAlertReceived(&alert));
-    EXPECT_EQ(kTlsAlertFatal, alert.level);
-    EXPECT_EQ(desc, alert.description);
-
-    // verify no alerts sent by the client
-    EXPECT_EQ(0U, client_->alert_sent_count());
+    ConnectExpectAlert(server_, desc);
   }
 
   void ServerHelloErrorTest(std::shared_ptr<PacketFilter> filter,
                             uint8_t desc = kTlsAlertDecodeError) {
-    SSLAlert alert;
-
-    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
-    client_->SetPacketFilter(alert_recorder);
     server_->SetPacketFilter(filter);
-    ConnectExpectFail();
-
-    EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-    EXPECT_EQ(desc, alert_recorder->description());
-
-    // verify no alerts received by the client
-    EXPECT_EQ(0U, client_->alert_received_count());
-
-    // verify the alert sent by the client
-    EXPECT_EQ(1U, client_->alert_sent_count());
-    EXPECT_TRUE(client_->GetLastAlertSent(&alert));
-    EXPECT_EQ(kTlsAlertFatal, alert.level);
-    EXPECT_EQ(desc, alert.description);
-
-    // verify the alert received by the server
-    EXPECT_EQ(1U, server_->alert_received_count());
-    EXPECT_TRUE(server_->GetLastAlertReceived(&alert));
-    EXPECT_EQ(kTlsAlertFatal, alert.level);
-    EXPECT_EQ(desc, alert.description);
-
-    // verify no alerts sent by the server
-    EXPECT_EQ(0U, server_->alert_sent_count());
+    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
@@ -287,17 +237,17 @@ class TlsExtensionTest13 : public TlsExt
  public:
   TlsExtensionTest13()
       : TlsExtensionTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
 
   void ConnectWithBogusVersionList(const uint8_t* buf, size_t len) {
     DataBuffer versions_buf(buf, len);
     client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
         ssl_tls13_supported_versions_xtn, versions_buf));
-    ConnectExpectFail();
+    ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
     client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
     server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
   }
 
   void ConnectWithReplacementVersionList(uint16_t version) {
     DataBuffer versions_buf;
 
     size_t index = versions_buf.Write(0, 2, 1);
@@ -632,16 +582,18 @@ TEST_P(TlsExtensionTest13, EmptyClientKe
 // 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();
   server_->SetPacketFilter(
       std::make_shared<TlsExtensionDropper>(ssl_tls13_key_share_xtn));
+  client_->ExpectSendAlert(kTlsAlertMissingExtension);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 TEST_F(TlsExtensionTest13Stream, WrongServerKeyShare) {
   const uint16_t wrong_group = ssl_grp_ec_secp384r1;
 
@@ -651,16 +603,18 @@ TEST_F(TlsExtensionTest13Stream, WrongSe
       0x00,
       0x02,  // length = 2
       0x01,
       0x02};
   DataBuffer buf(key_share, sizeof(key_share));
   EnsureTlsSetup();
   server_->SetPacketFilter(
       std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
+  client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 // TODO(ekr@rtfm.com): This is the wrong error code. See bug 1307269.
 TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
   const uint16_t wrong_group = 0xffff;
@@ -671,26 +625,30 @@ TEST_F(TlsExtensionTest13Stream, Unknown
       0x00,
       0x02,  // length = 2
       0x01,
       0x02};
   DataBuffer buf(key_share, sizeof(key_share));
   EnsureTlsSetup();
   server_->SetPacketFilter(
       std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
+  client_->ExpectSendAlert(kTlsAlertMissingExtension);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 TEST_F(TlsExtensionTest13Stream, AddServerSignatureAlgorithmsOnResumption) {
   SetupForResume();
   DataBuffer empty;
   server_->SetPacketFilter(std::make_shared<TlsExtensionInjector>(
       ssl_signature_algorithms_xtn, empty));
+  client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 struct PskIdentity {
   DataBuffer identity;
   uint32_t obfuscated_ticket_age;
@@ -815,132 +773,134 @@ class TlsPreSharedKeyReplacer : public T
   TlsPreSharedKeyReplacerFunc function_;
 };
 
 TEST_F(TlsExtensionTest13Stream, ResumeEmptyPskLabel) {
   SetupForResume();
 
   client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
       TlsPreSharedKeyReplacer* r) { r->identities_[0].identity.Truncate(0); }));
-  ConnectExpectFail();
+  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();
 
   client_->SetPacketFilter(
       std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
       }));
-  ConnectExpectFail();
+  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();
 
   client_->SetPacketFilter(
       std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->binders_[0].Write(r->binders_[0].len(), 0xff, 1);
       }));
-  ConnectExpectFail();
+  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();
 
   client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>(
       [](TlsPreSharedKeyReplacer* r) { r->binders_[0].Truncate(31); }));
-  ConnectExpectFail();
+  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();
 
   client_->SetPacketFilter(
       std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->identities_.push_back(r->identities_[0]);
         r->binders_.push_back(r->binders_[0]);
       }));
-  ConnectExpectFail();
+  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();
 
   client_->SetPacketFilter(
       std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->identities_.push_back(r->identities_[0]);
       }));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 TEST_F(TlsExtensionTest13Stream, ResumeOneIdentityTwoBinders) {
   SetupForResume();
 
   client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
       TlsPreSharedKeyReplacer* r) { r->binders_.push_back(r->binders_[0]); }));
-  ConnectExpectFail();
+  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);
   client_->SetPacketFilter(
       // Inject an unused extension.
       std::make_shared<TlsExtensionAppender>(0xffff, empty));
-  ConnectExpectFail();
+  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;
   client_->SetPacketFilter(std::make_shared<TlsExtensionDropper>(
       ssl_tls13_psk_key_exchange_modes_xtn));
-  ConnectExpectFail();
+  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));
   client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
       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 = std::make_shared<TlsExtensionCapture>(
@@ -950,61 +910,71 @@ TEST_P(TlsExtensionTest13, NoKeModesIfRe
   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_->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);
+#ifndef TLS_1_3_DRAFT_VERSION
+  ExpectAlert(server_, kTlsAlertIllegalParameter);
+#else
+  ExpectAlert(server_, kTlsAlertDecryptError);
+#endif
   ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
 #ifndef TLS_1_3_DRAFT_VERSION
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 #else
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 #endif
 }
 
 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 ext[] = {0x00, 0x00};
   ConnectWithBogusVersionList(ext, sizeof(ext));
--- a/gtests/ssl_gtest/ssl_gather_unittest.cc
+++ b/gtests/ssl_gtest/ssl_gather_unittest.cc
@@ -10,28 +10,28 @@
 namespace nss_test {
 
 class GatherV2ClientHelloTest : public TlsConnectTestBase {
  public:
   GatherV2ClientHelloTest() : TlsConnectTestBase(STREAM, 0) {}
 
   void ConnectExpectMalformedClientHello(const DataBuffer &data) {
     EnsureTlsSetup();
-
+    server_->ExpectSendAlert(kTlsAlertIllegalParameter);
     auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     server_->SetPacketFilter(alert_recorder);
 
     client_->SendDirect(data);
     server_->StartConnect();
     server_->Handshake();
     ASSERT_TRUE_WAIT(
         (server_->error_code() == SSL_ERROR_RX_MALFORMED_CLIENT_HELLO), 2000);
 
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-    EXPECT_EQ(illegal_parameter, alert_recorder->description());
+    EXPECT_EQ(kTlsAlertIllegalParameter, alert_recorder->description());
   }
 };
 
 // Gather a 5-byte v3 record, with a zero fragment length. The empty handshake
 // message should be ignored, and the connection will succeed afterwards.
 TEST_F(TlsConnectTest, GatherEmptyV3Record) {
   DataBuffer buffer;
 
@@ -50,26 +50,27 @@ TEST_F(TlsConnectTest, GatherExcessiveV3
   DataBuffer buffer;
 
   size_t idx = 0;
   idx = buffer.Write(idx, 0x16, 1);                            // handshake
   idx = buffer.Write(idx, 0x0301, 2);                          // record_version
   (void)buffer.Write(idx, MAX_FRAGMENT_LENGTH + 2048 + 1, 2);  // length=max+1
 
   EnsureTlsSetup();
+  server_->ExpectSendAlert(kTlsAlertRecordOverflow);
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   client_->SendDirect(buffer);
   server_->StartConnect();
   server_->Handshake();
   ASSERT_TRUE_WAIT((server_->error_code() == SSL_ERROR_RX_RECORD_TOO_LONG),
                    2000);
 
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-  EXPECT_EQ(record_overflow, alert_recorder->description());
+  EXPECT_EQ(kTlsAlertRecordOverflow, alert_recorder->description());
 }
 
 // Gather a 3-byte v2 header, with a fragment length of 2.
 TEST_F(GatherV2ClientHelloTest, GatherV2RecordLongHeader) {
   DataBuffer buffer;
 
   size_t idx = 0;
   idx = buffer.Write(idx, 0x0002, 2);  // length=2 (long header)
--- a/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -139,16 +139,17 @@ TEST_P(TlsConnectTls13, SecondClientHell
   client_->Handshake();
 
   // Send 0-RTT data.
   const char* k0RttData = "ABCDEF";
   const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
   PRInt32 rv = PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen);
   EXPECT_EQ(k0RttDataLen, rv);
 
+  ExpectAlert(server_, kTlsAlertUnsupportedExtension);
   Handshake();
   client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT);
 }
 
 class KeyShareReplayer : public TlsExtensionFilter {
  public:
   KeyShareReplayer() {}
 
@@ -176,17 +177,17 @@ class KeyShareReplayer : public TlsExten
 // the second ClientHello is modified so that it omits the requested share.  The
 // server should reject this.
 TEST_P(TlsConnectTls13, RetryWithSameKeyShare) {
   EnsureTlsSetup();
   client_->SetPacketFilter(std::make_shared<KeyShareReplayer>());
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
                                                     ssl_grp_ec_secp521r1};
   server_->ConfigNamedGroups(groups);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_BAD_2ND_CLIENT_HELLO, server_->error_code());
   EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, client_->error_code());
 }
 
 // This tests that the second attempt at sending a ClientHello (after receiving
 // a HelloRetryRequest) is correctly retransmitted.
 TEST_F(TlsConnectDatagram13, DropClientSecondFlightWithHelloRetry) {
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
@@ -253,16 +254,17 @@ TEST_F(TlsConnectTest, Select12AfterHell
   // Here we replace the TLS server with one that does TLS 1.2 only.
   // This will happily send the client a TLS 1.2 ServerHello.
   server_.reset(new TlsAgent(server_->name(), TlsAgent::SERVER, mode_));
   client_->SetPeer(server_);
   server_->SetPeer(client_);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   server_->StartConnect();
+  ExpectAlert(client_, kTlsAlertIllegalParameter);
   Handshake();
   EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, server_->error_code());
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
 }
 
 class HelloRetryRequestAgentTest : public TlsAgentTestClient {
  protected:
   void SetUp() override {
@@ -304,32 +306,35 @@ class HelloRetryRequestAgentTest : publi
 // Send two HelloRetryRequest messages in response to the ClientHello.  The are
 // constructed to appear legitimate by asking for a new share in each, so that
 // the client has to count to work out that the server is being unreasonable.
 TEST_P(HelloRetryRequestAgentTest, SendSecondHelloRetryRequest) {
   DataBuffer hrr;
   MakeGroupHrr(ssl_grp_ec_secp384r1, &hrr, 0);
   ProcessMessage(hrr, TlsAgent::STATE_CONNECTING);
   MakeGroupHrr(ssl_grp_ec_secp521r1, &hrr, 1);
+  ExpectAlert(kTlsAlertUnexpectedMessage);
   ProcessMessage(hrr, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST);
 }
 
 // Here the client receives a HelloRetryRequest with a group that they already
 // provided a share for.
 TEST_P(HelloRetryRequestAgentTest, HandleBogusHelloRetryRequest) {
   DataBuffer hrr;
   MakeGroupHrr(ssl_grp_ec_curve25519, &hrr);
+  ExpectAlert(kTlsAlertIllegalParameter);
   ProcessMessage(hrr, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
 }
 
 TEST_P(HelloRetryRequestAgentTest, HandleNoopHelloRetryRequest) {
   DataBuffer hrr;
   MakeCannedHrr(nullptr, 0U, &hrr);
+  ExpectAlert(kTlsAlertDecodeError);
   ProcessMessage(hrr, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
 }
 
 TEST_P(HelloRetryRequestAgentTest, HandleHelloRetryRequestCookie) {
   const uint8_t canned_cookie_hrr[] = {
       static_cast<uint8_t>(ssl_tls13_cookie_xtn >> 8),
       static_cast<uint8_t>(ssl_tls13_cookie_xtn),
--- a/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -43,17 +43,17 @@ TEST_P(TlsConnectGenericPre13, CipherSui
   EnsureTlsSetup();
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
     server_->EnableSingleCipher(TLS_AES_256_GCM_SHA384);
   } else {
     client_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
     server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
   }
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectFalseStart) {
   client_->EnableFalseStart();
   Connect();
   SendReceive();
@@ -173,41 +173,47 @@ class TlsPreCCSHeaderInjector : public T
     *offset = nhdr.Write(output, *offset, hhdr_buf);
     *offset = record_header.Write(output, *offset, input);
     return CHANGE;
   }
 };
 
 TEST_P(TlsConnectStreamPre13, ClientFinishedHeaderBeforeCCS) {
   client_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertUnexpectedMessage);
   client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
 }
 
 TEST_P(TlsConnectStreamPre13, ServerFinishedHeaderBeforeCCS) {
   server_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
   client_->StartConnect();
   server_->StartConnect();
+  ExpectAlert(client_, kTlsAlertUnexpectedMessage);
   Handshake();
   EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
+  server_->Handshake();  // Make sure alert is consumed.
 }
 
 TEST_P(TlsConnectTls13, UnknownAlert) {
   Connect();
+  server_->ExpectSendAlert(0xff, kTlsAlertWarning);
+  client_->ExpectReceiveAlert(0xff, kTlsAlertWarning);
   SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
                    0xff);  // Unknown value.
   client_->ExpectReadWriteError();
   client_->WaitForErrorCode(SSL_ERROR_RX_UNKNOWN_ALERT, 2000);
 }
 
 TEST_P(TlsConnectTls13, AlertWrongLevel) {
   Connect();
+  server_->ExpectSendAlert(kTlsAlertUnexpectedMessage, kTlsAlertWarning);
+  client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage, kTlsAlertWarning);
   SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
                    kTlsAlertUnexpectedMessage);
   client_->ExpectReadWriteError();
   client_->WaitForErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, 2000);
 }
 
 TEST_F(TlsConnectStreamTls13, Tls13FailedWriteSecondFlight) {
   EnsureTlsSetup();
--- a/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -476,16 +476,22 @@ TEST_P(TlsConnectStream, TestResumptionO
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   server_->SetPacketFilter(std::make_shared<SelectedCipherSuiteReplacer>(
       ChooseAnotherCipher(version_)));
 
+  if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+    server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+  } else {
+    ExpectAlert(client_, kTlsAlertHandshakeFailure);
+  }
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     // The reason this test is stream only: the server is unable to decrypt
     // the alert that the client sends, see bug 1304603.
     server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   } else {
     server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
@@ -548,17 +554,17 @@ TEST_P(TlsConnectGenericPre13, TestResum
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   // Enable the lower version on the client.
   client_->SetVersionRange(version_ - 1, version_);
   server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
   server_->SetPacketFilter(
       std::make_shared<SelectedVersionReplacer>(override_version));
 
-  ConnectExpectFail();
+  ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
 }
 
 // Test that two TLS resumptions work and produce the same ticket.
 // This will change after bug 1257047 is fixed.
 TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -686,14 +692,16 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
   // We will eventually fail the (sid.version == SH.version) check.
   std::vector<std::shared_ptr<PacketFilter>> filters;
   filters.push_back(std::make_shared<SelectedCipherSuiteReplacer>(
       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256));
   filters.push_back(
       std::make_shared<SelectedVersionReplacer>(SSL_LIBRARY_VERSION_TLS_1_2));
   server_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(filters));
 
+  client_->ExpectSendAlert(kTlsAlertDecodeError);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);  // Server can't read
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
 }
 
 }  // namespace nss_test
--- a/gtests/ssl_gtest/ssl_skip_unittest.cc
+++ b/gtests/ssl_gtest/ssl_skip_unittest.cc
@@ -85,49 +85,52 @@ class TlsSkipTest
   TlsSkipTest()
       : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
   void ServerSkipTest(std::shared_ptr<PacketFilter> filter,
                       uint8_t alert = kTlsAlertUnexpectedMessage) {
     auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     client_->SetPacketFilter(alert_recorder);
     server_->SetPacketFilter(filter);
-    ConnectExpectFail();
+    ConnectExpectAlert(client_, alert);
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
     EXPECT_EQ(alert, alert_recorder->description());
   }
 };
 
 class Tls13SkipTest : public TlsConnectTestBase,
                       public ::testing::WithParamInterface<std::string> {
  protected:
   Tls13SkipTest()
       : TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
 
   void ServerSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
     EnsureTlsSetup();
     server_->SetTlsRecordFilter(filter);
     filter->EnableDecryption();
+    client_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
     if (mode_ == STREAM) {
+      server_->ExpectSendAlert(kTlsAlertBadRecordMac);
       ConnectExpectFail();
     } else {
       ConnectExpectFailOneSide(TlsAgent::CLIENT);
     }
     client_->CheckErrorCode(error);
     if (mode_ == STREAM) {
       server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
     } else {
       ASSERT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
     }
   }
 
   void ClientSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
     EnsureTlsSetup();
     client_->SetTlsRecordFilter(filter);
     filter->EnableDecryption();
+    server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
     ConnectExpectFailOneSide(TlsAgent::SERVER);
 
     server_->CheckErrorCode(error);
     ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
   }
 };
 
 TEST_P(TlsSkipTest, SkipCertificateRsa) {
@@ -206,27 +209,31 @@ TEST_P(Tls13SkipTest, SkipServerCertific
   ServerSkipTest(
       std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
       SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
 
 TEST_P(Tls13SkipTest, SkipClientCertificate) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
+  client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
   ClientSkipTest(
       std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate),
       SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+  client_->Handshake();  // Make sure to consume the alert.
 }
 
 TEST_P(Tls13SkipTest, SkipClientCertificateVerify) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
+  client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
   ClientSkipTest(
       std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
       SSL_ERROR_RX_UNEXPECTED_FINISHED);
+  client_->Handshake();  // Make sure to consume the alert.
 }
 
 INSTANTIATE_TEST_CASE_P(SkipTls10, TlsSkipTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
                                            TlsConnectTestBase::kTlsV10));
 INSTANTIATE_TEST_CASE_P(SkipVariants, TlsSkipTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
                                            TlsConnectTestBase::kTlsV11V12));
--- a/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -49,30 +49,30 @@ TEST_P(TlsConnectGenericPre13, ConnectSt
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
   EnableOnlyStaticRsaCiphers();
   auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
       kTlsHandshakeClientKeyExchange,
       DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(i1);
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
   EnableOnlyStaticRsaCiphers();
   client_->SetPacketFilter(
       std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is ignored when
 // rollback detection is disabled. This is a positive control for
 // ConnectStaticRSABogusPMSVersionDetect.
 TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) {
@@ -88,31 +88,31 @@ TEST_P(TlsConnectStreamPre13, ConnectExt
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   auto inspect = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
       kTlsHandshakeClientKeyExchange,
       DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(inspect);
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13,
        ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   client_->SetPacketFilter(
       std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 TEST_P(TlsConnectStreamPre13,
        ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
--- a/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
+++ b/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
@@ -215,30 +215,30 @@ TEST_P(SSLv2ClientHelloTest, ConnectAfte
   EnsureTlsSetup();
   client_->SendDirect(buffer);
 
   // Need padding so the connection doesn't just time out. With a v2
   // ClientHello parsed as a v3 record we will use the record version
   // as the record length.
   SetPadding(255);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_BAD_CLIENT, server_->error_code());
 }
 
 // Test negotiating TLS 1.3.
 TEST_F(SSLv2ClientHelloTestF, Connect13) {
   EnsureTlsSetup();
   SetExpectedVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
 
   std::vector<uint16_t> cipher_suites = {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256};
   SetAvailableCipherSuites(cipher_suites);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
 }
 
 // Test negotiating an EC suite.
 TEST_P(SSLv2ClientHelloTest, NegotiateECSuite) {
   SetAvailableCipherSuite(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
   Connect();
 }
@@ -255,49 +255,49 @@ TEST_P(SSLv2ClientHelloTest, SendSecurit
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
 
   // Send a security escape.
   SetSendEscape(true);
 
   // Set a big padding so that the server fails instead of timing out.
   SetPadding(255);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
 }
 
 // Invalid SSLv2 client hello padding must fail the handshake.
 TEST_P(SSLv2ClientHelloTest, AddErroneousPadding) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
 
   // Append 5 bytes of padding but say it's only 4.
   SetPadding(5, 4);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
 }
 
 // Invalid SSLv2 client hello padding must fail the handshake.
 TEST_P(SSLv2ClientHelloTest, AddErroneousPadding2) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
 
   // Append 5 bytes of padding but say it's 6.
   SetPadding(5, 6);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
 }
 
 // Wrong amount of bytes for the ClientRandom must fail the handshake.
 TEST_P(SSLv2ClientHelloTest, SmallClientRandom) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
 
   // Send a ClientRandom that's too small.
   SetClientRandomLength(15);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
 }
 
 // Test sending the maximum accepted number of ClientRandom bytes.
 TEST_P(SSLv2ClientHelloTest, MaxClientRandom) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
   SetClientRandomLength(32);
   Connect();
@@ -305,26 +305,26 @@ TEST_P(SSLv2ClientHelloTest, MaxClientRa
 
 // Wrong amount of bytes for the ClientRandom must fail the handshake.
 TEST_P(SSLv2ClientHelloTest, BigClientRandom) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
 
   // Send a ClientRandom that's too big.
   SetClientRandomLength(33);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
 }
 
 // Connection must fail if we require safe renegotiation but the client doesn't
 // include TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the list of cipher suites.
 TEST_P(SSLv2ClientHelloTest, RequireSafeRenegotiation) {
   RequireSafeRenegotiation();
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   EXPECT_EQ(SSL_ERROR_UNSAFE_NEGOTIATION, server_->error_code());
 }
 
 // Connection must succeed when requiring safe renegotiation and the client
 // includes TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the list of cipher suites.
 TEST_P(SSLv2ClientHelloTest, RequireSafeRenegotiationWithSCSV) {
   RequireSafeRenegotiation();
   std::vector<uint16_t> cipher_suites = {TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
@@ -356,17 +356,17 @@ TEST_F(SSLv2ClientHelloTestF, Inappropri
                            SSL_LIBRARY_VERSION_TLS_1_1);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_2);
 
   std::vector<uint16_t> cipher_suites = {TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                                          TLS_FALLBACK_SCSV};
   SetAvailableCipherSuites(cipher_suites);
 
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertInappropriateFallback);
   EXPECT_EQ(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, server_->error_code());
 }
 
 INSTANTIATE_TEST_CASE_P(VersionsStream10Pre13, SSLv2ClientHelloTest,
                         TlsConnectTestBase::kTlsV10);
 INSTANTIATE_TEST_CASE_P(VersionsStreamPre13, SSLv2ClientHelloTest,
                         TlsConnectTestBase::kTlsV11V12);
 
--- a/gtests/ssl_gtest/ssl_version_unittest.cc
+++ b/gtests/ssl_gtest/ssl_version_unittest.cc
@@ -130,17 +130,17 @@ TEST_F(TlsConnectTest, TestFallbackFromT
 TEST_P(TlsConnectGeneric, TestFallbackSCSVVersionMatch) {
   client_->SetFallbackSCSVEnabled(true);
   Connect();
 }
 
 TEST_P(TlsConnectGenericPre13, TestFallbackSCSVVersionMismatch) {
   client_->SetFallbackSCSVEnabled(true);
   server_->SetVersionRange(version_, version_ + 1);
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertInappropriateFallback);
   client_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT);
 }
 
 // The TLS v1.3 spec section C.4 states that 'Implementations MUST NOT send or
 // accept any records with a version less than { 3, 0 }'. Thus we will not
 // allow version ranges including both SSL v3 and TLS v1.3.
 TEST_F(TlsConnectTest, DisallowSSLv3HelloWithTLSv13Enabled) {
   SECStatus rv;
@@ -172,16 +172,23 @@ TEST_P(TlsConnectStream, ConnectTls10And
   // Now renegotiate, with the server being set to do
   // |version_|.
   client_->PrepareForRenegotiate();
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, test_version);
   // Reset version and cipher suite so that the preinfo callback
   // doesn't fail.
   server_->ResetPreliminaryInfo();
   server_->StartRenegotiate();
+
+  if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+  } else {
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
+  }
+
   Handshake();
   if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
     // In TLS 1.3, the server detects this problem.
     client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
     server_->CheckErrorCode(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
   } else {
     client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
     server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@@ -205,16 +212,21 @@ TEST_P(TlsConnectStream, ConnectTls10And
   // Now renegotiate, with the server being set to do
   // |version_|.
   server_->PrepareForRenegotiate();
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0, test_version);
   // Reset version and cipher suite so that the preinfo callback
   // doesn't fail.
   server_->ResetPreliminaryInfo();
   client_->StartRenegotiate();
+  if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+  } else {
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
+  }
   Handshake();
   if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
     // In TLS 1.3, the server detects this problem.
     client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
     server_->CheckErrorCode(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
   } else {
     client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
     server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@@ -236,17 +248,17 @@ TEST_F(TlsConnectTest, Tls13RejectsRehan
   Connect();
   SECStatus rv = SSL_ReHandshake(server_->ssl_fd(), PR_TRUE);
   EXPECT_EQ(SECFailure, rv);
   EXPECT_EQ(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, PORT_GetError());
 }
 
 TEST_P(TlsConnectGeneric, AlertBeforeServerHello) {
   EnsureTlsSetup();
-  client_->SetExpectedAlertReceivedCount(1);
+  client_->ExpectReceiveAlert(kTlsAlertUnrecognizedName, kTlsAlertWarning);
   client_->StartConnect();
   server_->StartConnect();
   client_->Handshake();  // Send ClientHello.
   static const uint8_t kWarningAlert[] = {kTlsAlertWarning,
                                           kTlsAlertUnrecognizedName};
   DataBuffer alert;
   TlsAgentTestBase::MakeRecord(mode_, kTlsAlertType,
                                SSL_LIBRARY_VERSION_TLS_1_0, kWarningAlert,
@@ -263,17 +275,17 @@ class Tls13NoSupportedVersions : public 
                              SSL_LIBRARY_VERSION_TLS_1_2);
     server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, max_server_version);
     client_->SetPacketFilter(
         std::make_shared<TlsInspectorClientHelloVersionSetter>(
             overwritten_client_version));
     auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
         kTlsHandshakeServerHello);
     server_->SetPacketFilter(capture);
-    ConnectExpectFail();
+    ConnectExpectAlert(server_, kTlsAlertDecryptError);
     client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
     server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
     const DataBuffer& server_hello = capture->buffer();
     ASSERT_GT(server_hello.len(), 2U);
     uint32_t ver;
     ASSERT_TRUE(server_hello.Read(0, 2, &ver));
     ASSERT_EQ(static_cast<uint32_t>(SSL_LIBRARY_VERSION_TLS_1_2), ver);
   }
@@ -300,16 +312,18 @@ TEST_F(Tls13NoSupportedVersions,
 // causes a bad MAC error when we read EncryptedExtensions.
 TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) {
   client_->SetPacketFilter(
       std::make_shared<TlsInspectorClientHelloVersionSetter>(
           SSL_LIBRARY_VERSION_TLS_1_3 + 1));
   auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
       kTlsHandshakeServerHello);
   server_->SetPacketFilter(capture);
+  client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   const DataBuffer& server_hello = capture->buffer();
   ASSERT_GT(server_hello.len(), 2U);
   uint32_t ver;
   ASSERT_TRUE(server_hello.Read(0, 2, &ver));
   // This way we don't need to change with new draft version.
--- a/gtests/ssl_gtest/tls_agent.cc
+++ b/gtests/ssl_gtest/tls_agent.cc
@@ -55,22 +55,20 @@ TlsAgent::TlsAgent(const std::string& na
       falsestart_enabled_(false),
       expected_version_(0),
       expected_cipher_suite_(0),
       expect_resumption_(false),
       expect_client_auth_(false),
       can_falsestart_hook_called_(false),
       sni_hook_called_(false),
       auth_certificate_hook_called_(false),
-      alert_received_count_(0),
-      expected_alert_received_count_(0),
-      last_alert_received_({0, 0}),
-      alert_sent_count_(0),
-      expected_alert_sent_count_(0),
-      last_alert_sent_({0, 0}),
+      expected_received_alert_(kTlsAlertCloseNotify),
+      expected_received_alert_level_(kTlsAlertWarning),
+      expected_sent_alert_(kTlsAlertCloseNotify),
+      expected_sent_alert_level_(kTlsAlertWarning),
       handshake_callback_called_(false),
       error_code_(0),
       send_ctr_(0),
       recv_ctr_(0),
       expect_readwrite_error_(false),
       handshake_callback_(),
       auth_certificate_callback_(),
       sni_callback_(),
@@ -85,16 +83,21 @@ TlsAgent::TlsAgent(const std::string& na
 TlsAgent::~TlsAgent() {
   if (timer_handle_) {
     timer_handle_->Cancel();
   }
 
   if (adapter_) {
     Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
   }
+
+  EXPECT_EQ(expected_received_alert_, kTlsAlertCloseNotify);
+  EXPECT_EQ(expected_received_alert_level_, kTlsAlertWarning);
+  EXPECT_EQ(expected_sent_alert_, kTlsAlertCloseNotify);
+  EXPECT_EQ(expected_sent_alert_level_, kTlsAlertWarning);
 }
 
 void TlsAgent::SetState(State state) {
   if (state_ == state) return;
 
   LOG("Changing state from " << state_ << " to " << state);
   state_ = state;
 }
@@ -602,19 +605,63 @@ void TlsAgent::CheckSrtp() const {
 
 void TlsAgent::CheckErrorCode(int32_t expected) const {
   EXPECT_EQ(STATE_ERROR, state_);
   EXPECT_EQ(expected, error_code_)
       << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
       << PORT_ErrorToName(expected) << std::endl;
 }
 
-void TlsAgent::CheckAlerts() const {
-  EXPECT_EQ(expected_alert_received_count_, alert_received_count_);
-  EXPECT_EQ(expected_alert_sent_count_, alert_sent_count_);
+static uint8_t GetExpectedAlertLevel(uint8_t alert) {
+  switch (alert) {
+    case kTlsAlertCloseNotify:
+    case kTlsAlertEndOfEarlyData:
+      return kTlsAlertWarning;
+    default:
+      break;
+  }
+  return kTlsAlertFatal;
+}
+
+void TlsAgent::ExpectReceiveAlert(uint8_t alert, uint8_t level) {
+  expected_received_alert_ = alert;
+  if (level == 0) {
+    expected_received_alert_level_ = GetExpectedAlertLevel(alert);
+  } else {
+    expected_received_alert_level_ = level;
+  }
+}
+
+void TlsAgent::ExpectSendAlert(uint8_t alert, uint8_t level) {
+  expected_sent_alert_ = alert;
+  if (level == 0) {
+    expected_sent_alert_level_ = GetExpectedAlertLevel(alert);
+  } else {
+    expected_sent_alert_level_ = level;
+  }
+}
+
+void TlsAgent::CheckAlert(bool sent, const SSLAlert* alert) {
+  LOG(((alert->level == kTlsAlertWarning) ? "Warning" : "Fatal")
+      << " alert " << (sent ? "sent" : "received") << ": "
+      << static_cast<int>(alert->description));
+
+  auto& expected = sent ? expected_sent_alert_ : expected_received_alert_;
+  auto& expected_level =
+      sent ? expected_sent_alert_level_ : expected_received_alert_level_;
+  /* Silently pass close_notify in case the test has already ended. */
+  if (expected == kTlsAlertCloseNotify && expected_level == kTlsAlertWarning &&
+      alert->description == expected && alert->level == expected_level) {
+    return;
+  }
+
+  EXPECT_EQ(expected, alert->description);
+  EXPECT_EQ(expected_level, alert->level);
+  expected = kTlsAlertCloseNotify;
+  expected_level = kTlsAlertWarning;
 }
 
 void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
   ASSERT_EQ(0, error_code_);
   WAIT_(error_code_ != 0, delay);
   EXPECT_EQ(expected, error_code_)
       << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
       << PORT_ErrorToName(expected) << std::endl;
@@ -941,16 +988,21 @@ void TlsAgentTestBase::EnsureInit() {
     Reset();
   }
   const std::vector<SSLNamedGroup> groups = {
       ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
       ssl_grp_ffdhe_2048};
   agent_->ConfigNamedGroups(groups);
 }
 
+void TlsAgentTestBase::ExpectAlert(uint8_t alert) {
+  EnsureInit();
+  agent_->ExpectSendAlert(alert);
+}
+
 void TlsAgentTestBase::ProcessMessage(const DataBuffer& buffer,
                                       TlsAgent::State expected_state,
                                       int32_t error_code) {
   std::cerr << "Process message: " << buffer << std::endl;
   EnsureInit();
   agent_->adapter()->PacketReceived(buffer);
   agent_->Handshake();
 
--- a/gtests/ssl_gtest/tls_agent.h
+++ b/gtests/ssl_gtest/tls_agent.h
@@ -139,17 +139,16 @@ class TlsAgent : public PollTarget {
   void ExpectShortHeaders();
   void SetSignatureSchemes(const SSLSignatureScheme* schemes, size_t count);
   void EnableAlpn(const uint8_t* val, size_t len);
   void CheckAlpn(SSLNextProtoState expected_state,
                  const std::string& expected = "") const;
   void EnableSrtp();
   void CheckSrtp() const;
   void CheckErrorCode(int32_t expected) const;
-  void CheckAlerts() const;
   void WaitForErrorCode(int32_t expected, uint32_t delay) const;
   // Send data on the socket, encrypting it.
   void SendData(size_t bytes, size_t blocksize = 1024);
   void SendBuffer(const DataBuffer& buf);
   // Send data directly to the underlying socket, skipping the TLS layer.
   void SendDirect(const DataBuffer& buf);
   void ReadBytes();
   void ResetSentBytes();  // Hack to test drops.
@@ -241,43 +240,18 @@ class TlsAgent : public PollTarget {
       AuthCertificateCallbackFunction auth_certificate_callback) {
     auth_certificate_callback_ = auth_certificate_callback;
   }
 
   void SetSniCallback(SniCallbackFunction sni_callback) {
     sni_callback_ = sni_callback;
   }
 
-  size_t alert_received_count() const { return alert_received_count_; }
-
-  void SetExpectedAlertReceivedCount(size_t count) {
-    expected_alert_received_count_ = count;
-  }
-
-  bool GetLastAlertReceived(SSLAlert* alert) const {
-    if (!alert_received_count_) {
-      return false;
-    }
-    *alert = last_alert_received_;
-    return true;
-  }
-
-  size_t alert_sent_count() const { return alert_sent_count_; }
-
-  void SetExpectedAlertSentCount(size_t count) {
-    expected_alert_sent_count_ = count;
-  }
-
-  bool GetLastAlertSent(SSLAlert* alert) const {
-    if (!alert_sent_count_) {
-      return false;
-    }
-    *alert = last_alert_sent_;
-    return true;
-  }
+  void ExpectReceiveAlert(uint8_t alert, uint8_t level = 0);
+  void ExpectSendAlert(uint8_t alert, uint8_t level = 0);
 
  private:
   const static char* states[];
 
   void SetState(State state);
 
   // Dummy auth certificate hook.
   static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
@@ -350,38 +324,26 @@ class TlsAgent : public PollTarget {
     agent->CheckPreliminaryInfo();
     EXPECT_TRUE(agent->falsestart_enabled_);
     EXPECT_FALSE(agent->can_falsestart_hook_called_);
     agent->can_falsestart_hook_called_ = true;
     *canFalseStart = true;
     return SECSuccess;
   }
 
+  void CheckAlert(bool sent, const SSLAlert* alert);
+
   static void AlertReceivedCallback(const PRFileDesc* fd, void* arg,
                                     const SSLAlert* alert) {
-    TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
-
-    std::cerr << agent->role_str()
-              << ": Alert received: level=" << static_cast<int>(alert->level)
-              << " desc=" << static_cast<int>(alert->description) << std::endl;
-
-    ++agent->alert_received_count_;
-    agent->last_alert_received_ = *alert;
+    reinterpret_cast<TlsAgent*>(arg)->CheckAlert(false, alert);
   }
 
   static void AlertSentCallback(const PRFileDesc* fd, void* arg,
                                 const SSLAlert* alert) {
-    TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
-
-    std::cerr << agent->role_str()
-              << ": Alert sent: level=" << static_cast<int>(alert->level)
-              << " desc=" << static_cast<int>(alert->description) << std::endl;
-
-    ++agent->alert_sent_count_;
-    agent->last_alert_sent_ = *alert;
+    reinterpret_cast<TlsAgent*>(arg)->CheckAlert(true, alert);
   }
 
   static void HandshakeCallback(PRFileDesc* fd, void* arg) {
     TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
     agent->handshake_callback_called_ = true;
     agent->Connected();
     if (agent->handshake_callback_) {
       agent->handshake_callback_(agent);
@@ -405,22 +367,20 @@ class TlsAgent : public PollTarget {
   bool falsestart_enabled_;
   uint16_t expected_version_;
   uint16_t expected_cipher_suite_;
   bool expect_resumption_;
   bool expect_client_auth_;
   bool can_falsestart_hook_called_;
   bool sni_hook_called_;
   bool auth_certificate_hook_called_;
-  size_t alert_received_count_;
-  size_t expected_alert_received_count_;
-  SSLAlert last_alert_received_;
-  size_t alert_sent_count_;
-  size_t expected_alert_sent_count_;
-  SSLAlert last_alert_sent_;
+  uint8_t expected_received_alert_;
+  uint8_t expected_received_alert_level_;
+  uint8_t expected_sent_alert_;
+  uint8_t expected_sent_alert_level_;
   bool handshake_callback_called_;
   SSLChannelInfo info_;
   SSLCipherSuiteInfo csinfo_;
   SSLVersionRange vrange_;
   PRErrorCode error_code_;
   size_t send_ctr_;
   size_t recv_ctr_;
   bool expect_readwrite_error_;
@@ -445,16 +405,18 @@ class TlsAgentTestBase : public ::testin
         mode_(mode),
         version_(version),
         sink_adapter_(new DummyPrSocket("sink", mode)) {}
   virtual ~TlsAgentTestBase() {}
 
   void SetUp();
   void TearDown();
 
+  void ExpectAlert(uint8_t alert);
+
   static void MakeRecord(Mode mode, uint8_t type, uint16_t version,
                          const uint8_t* buf, size_t len, DataBuffer* out,
                          uint64_t seq_num = 0);
   void MakeRecord(uint8_t type, uint16_t version, const uint8_t* buf,
                   size_t len, DataBuffer* out, uint64_t seq_num = 0) const;
   void MakeHandshakeMessage(uint8_t hs_type, const uint8_t* data, size_t hs_len,
                             DataBuffer* out, uint64_t seq_num = 0) const;
   void MakeHandshakeMessageFragment(uint8_t hs_type, const uint8_t* data,
--- a/gtests/ssl_gtest/tls_connect.cc
+++ b/gtests/ssl_gtest/tls_connect.cc
@@ -296,19 +296,16 @@ void TlsConnectTestBase::CheckConnected(
     session_ids_.push_back(sid_c1);
   }
 
   CheckExtendedMasterSecret();
   CheckEarlyDataAccepted();
   CheckResumption(expected_resumption_mode_);
   client_->CheckSecretsDestroyed();
   server_->CheckSecretsDestroyed();
-
-  client_->CheckAlerts();
-  server_->CheckAlerts();
 }
 
 void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
                                    SSLAuthType auth_type,
                                    SSLSignatureScheme sig_scheme) const {
   client_->CheckKEA(kea_type, kea_group);
   server_->CheckKEA(kea_type, kea_group);
   client_->CheckAuthType(auth_type, sig_scheme);
@@ -370,16 +367,30 @@ void TlsConnectTestBase::CheckKeys() con
 void TlsConnectTestBase::ConnectExpectFail() {
   server_->StartConnect();
   client_->StartConnect();
   Handshake();
   ASSERT_EQ(TlsAgent::STATE_ERROR, client_->state());
   ASSERT_EQ(TlsAgent::STATE_ERROR, server_->state());
 }
 
+void TlsConnectTestBase::ExpectAlert(std::shared_ptr<TlsAgent>& sender,
+                                     uint8_t alert) {
+  EnsureTlsSetup();
+  auto receiver = (sender == client_) ? server_ : client_;
+  sender->ExpectSendAlert(alert);
+  receiver->ExpectReceiveAlert(alert);
+}
+
+void TlsConnectTestBase::ConnectExpectAlert(std::shared_ptr<TlsAgent>& sender,
+                                            uint8_t alert) {
+  ExpectAlert(sender, alert);
+  ConnectExpectFail();
+}
+
 void TlsConnectTestBase::ConnectExpectFailOneSide(TlsAgent::Role failing_side) {
   server_->StartConnect();
   client_->StartConnect();
   client_->SetServerKeyBits(server_->server_key_bits());
   client_->Handshake();
   server_->Handshake();
 
   auto failing_agent = server_;
@@ -556,16 +567,20 @@ void TlsConnectTestBase::SetupForResume(
 }
 
 void TlsConnectTestBase::ZeroRttSendReceive(
     bool expect_writable, bool expect_readable,
     std::function<bool()> post_clienthello_check) {
   const char* k0RttData = "ABCDEF";
   const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
 
+  if (expect_writable && expect_readable) {
+    ExpectAlert(client_, kTlsAlertEndOfEarlyData);
+  }
+
   client_->Handshake();  // Send ClientHello.
   if (post_clienthello_check) {
     if (!post_clienthello_check()) return;
   }
   PRInt32 rv =
       PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen);  // 0-RTT write.
   if (expect_writable) {
     EXPECT_EQ(k0RttDataLen, rv);
--- a/gtests/ssl_gtest/tls_connect.h
+++ b/gtests/ssl_gtest/tls_connect.h
@@ -63,16 +63,18 @@ class TlsConnectTestBase : public ::test
   // Run the handshake.
   void Handshake();
   // Connect and check that it works.
   void Connect();
   // Check that the connection was successfully established.
   void CheckConnected();
   // Connect and expect it to fail.
   void ConnectExpectFail();
+  void ExpectAlert(std::shared_ptr<TlsAgent>& sender, uint8_t alert);
+  void ConnectExpectAlert(std::shared_ptr<TlsAgent>& sender, uint8_t alert);
   void ConnectExpectFailOneSide(TlsAgent::Role failingSide);
   void ConnectWithCipherSuite(uint16_t cipher_suite);
   // Check that the keys used in the handshake match expectations.
   void CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
                  SSLAuthType auth_type, SSLSignatureScheme sig_scheme) const;
   // This version guesses some of the values.
   void CheckKeys(SSLKEAType kea_type, SSLAuthType auth_type) const;
   // This version assumes defaults.
--- a/gtests/ssl_gtest/tls_parser.h
+++ b/gtests/ssl_gtest/tls_parser.h
@@ -34,22 +34,27 @@ const uint8_t kTlsHandshakeServerKeyExch
 const uint8_t kTlsHandshakeCertificateRequest = 13;
 const uint8_t kTlsHandshakeCertificateVerify = 15;
 const uint8_t kTlsHandshakeClientKeyExchange = 16;
 const uint8_t kTlsHandshakeFinished = 20;
 
 const uint8_t kTlsAlertWarning = 1;
 const uint8_t kTlsAlertFatal = 2;
 
+const uint8_t kTlsAlertCloseNotify = 0;
+const uint8_t kTlsAlertEndOfEarlyData = 1;
 const uint8_t kTlsAlertUnexpectedMessage = 10;
 const uint8_t kTlsAlertBadRecordMac = 20;
+const uint8_t kTlsAlertRecordOverflow = 22;
 const uint8_t kTlsAlertHandshakeFailure = 40;
 const uint8_t kTlsAlertIllegalParameter = 47;
 const uint8_t kTlsAlertDecodeError = 50;
 const uint8_t kTlsAlertDecryptError = 51;
+const uint8_t kTlsAlertProtocolVersion = 70;
+const uint8_t kTlsAlertInappropriateFallback = 86;
 const uint8_t kTlsAlertMissingExtension = 109;
 const uint8_t kTlsAlertUnsupportedExtension = 110;
 const uint8_t kTlsAlertUnrecognizedName = 112;
 const uint8_t kTlsAlertNoApplicationProtocol = 120;
 
 const uint8_t kTlsFakeChangeCipherSpec[] = {
     kTlsChangeCipherSpecType,  // Type
     0xfe,