summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc199
1 files changed, 194 insertions, 5 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
index 5adbd9dc7..12c2496a6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -18,7 +18,7 @@ extern "C" {
}
#include "gtest_utils.h"
-#include "scoped_ptrs.h"
+#include "nss_scoped_ptrs.h"
#include "tls_connect.h"
#include "tls_filter.h"
#include "tls_parser.h"
@@ -65,7 +65,7 @@ class TlsAlertRecorder : public TlsRecordFilter {
if (level_ != 255) { // Already captured.
return KEEP;
}
- if (header.content_type() != kTlsAlertType) {
+ if (header.content_type() != ssl_ct_alert) {
return KEEP;
}
@@ -130,7 +130,7 @@ TEST_P(TlsConnectTls13, CaptureAlertClient) {
client_->Handshake();
if (variant_ == ssl_variant_stream) {
// DTLS just drops the alert it can't decrypt.
- server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
}
server_->Handshake();
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
@@ -320,6 +320,53 @@ TEST_F(TlsConnectStreamTls13, DropRecordClient) {
SendReceive();
}
+// Check that a server can use 0.5 RTT if client authentication isn't enabled.
+TEST_P(TlsConnectTls13, WriteBeforeClientFinished) {
+ EnsureTlsSetup();
+ StartConnect();
+ client_->Handshake(); // ClientHello
+ server_->Handshake(); // ServerHello
+
+ server_->SendData(10);
+ client_->ReadBytes(10); // Client should emit the Finished as a side-effect.
+ server_->Handshake(); // Server consumes the Finished.
+ CheckConnected();
+}
+
+// We don't allow 0.5 RTT if client authentication is requested.
+TEST_P(TlsConnectTls13, WriteBeforeClientFinishedClientAuth) {
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(false);
+ StartConnect();
+ client_->Handshake(); // ClientHello
+ server_->Handshake(); // ServerHello
+
+ static const uint8_t data[] = {1, 2, 3};
+ EXPECT_GT(0, PR_Write(server_->ssl_fd(), data, sizeof(data)));
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ Handshake();
+ CheckConnected();
+ SendReceive();
+}
+
+// 0.5 RTT should fail with client authentication required.
+TEST_P(TlsConnectTls13, WriteBeforeClientFinishedClientAuthRequired) {
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+ StartConnect();
+ client_->Handshake(); // ClientHello
+ server_->Handshake(); // ServerHello
+
+ static const uint8_t data[] = {1, 2, 3};
+ EXPECT_GT(0, PR_Write(server_->ssl_fd(), data, sizeof(data)));
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ Handshake();
+ CheckConnected();
+ SendReceive();
+}
+
// The next two tests takes advantage of the fact that we
// automatically read the first 1024 bytes, so if
// we provide 1200 bytes, they overrun the read buffer
@@ -426,13 +473,15 @@ class TlsPreCCSHeaderInjector : public TlsRecordFilter {
virtual PacketFilter::Action FilterRecord(
const TlsRecordHeader& record_header, const DataBuffer& input,
size_t* offset, DataBuffer* output) override {
- if (record_header.content_type() != kTlsChangeCipherSpecType) return KEEP;
+ if (record_header.content_type() != ssl_ct_change_cipher_spec) {
+ return KEEP;
+ }
std::cerr << "Injecting Finished header before CCS\n";
const uint8_t hhdr[] = {kTlsHandshakeFinished, 0x00, 0x00, 0x0c};
DataBuffer hhdr_buf(hhdr, sizeof(hhdr));
TlsRecordHeader nhdr(record_header.variant(), record_header.version(),
- kTlsHandshakeType, 0);
+ ssl_ct_handshake, 0);
*offset = nhdr.Write(output, *offset, hhdr_buf);
*offset = record_header.Write(output, *offset, input);
return CHANGE;
@@ -477,6 +526,26 @@ TEST_P(TlsConnectTls13, AlertWrongLevel) {
client_->WaitForErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, 2000);
}
+TEST_P(TlsConnectTls13, UnknownRecord) {
+ static const uint8_t kUknownRecord[] = {
+ 0xff, SSL_LIBRARY_VERSION_TLS_1_2 >> 8,
+ SSL_LIBRARY_VERSION_TLS_1_2 & 0xff, 0, 0};
+
+ Connect();
+ if (variant_ == ssl_variant_stream) {
+ // DTLS just drops the record with an invalid type.
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ }
+ client_->SendDirect(DataBuffer(kUknownRecord, sizeof(kUknownRecord)));
+ server_->ExpectReadWriteError();
+ server_->ReadBytes();
+ if (variant_ == ssl_variant_stream) {
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+ } else {
+ EXPECT_EQ(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, server_->error_code());
+ }
+}
+
TEST_F(TlsConnectStreamTls13, Tls13FailedWriteSecondFlight) {
EnsureTlsSetup();
StartConnect();
@@ -539,6 +608,126 @@ TEST_F(TlsConnectTest, OneNRecordSplitting) {
EXPECT_EQ(ExpectedCbcLen(20), records->record(2).buffer.len());
}
+// We can't test for randomness easily here, but we can test that we don't
+// produce a zero value, or produce the same value twice. There are 5 values
+// here: two ClientHello.random, two ServerHello.random, and one zero value.
+// Matrix them and fail if any are the same.
+TEST_P(TlsConnectGeneric, CheckRandoms) {
+ ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+
+ static const size_t random_len = 32;
+ uint8_t crandom1[random_len], srandom1[random_len];
+ uint8_t z[random_len] = {0};
+
+ auto ch = MakeTlsFilter<TlsHandshakeRecorder>(client_, ssl_hs_client_hello);
+ auto sh = MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_server_hello);
+ Connect();
+ ASSERT_TRUE(ch->buffer().len() > (random_len + 2));
+ ASSERT_TRUE(sh->buffer().len() > (random_len + 2));
+ memcpy(crandom1, ch->buffer().data() + 2, random_len);
+ memcpy(srandom1, sh->buffer().data() + 2, random_len);
+ EXPECT_NE(0, memcmp(crandom1, srandom1, random_len));
+ EXPECT_NE(0, memcmp(crandom1, z, random_len));
+ EXPECT_NE(0, memcmp(srandom1, z, random_len));
+
+ Reset();
+ ch = MakeTlsFilter<TlsHandshakeRecorder>(client_, ssl_hs_client_hello);
+ sh = MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_server_hello);
+ Connect();
+ ASSERT_TRUE(ch->buffer().len() > (random_len + 2));
+ ASSERT_TRUE(sh->buffer().len() > (random_len + 2));
+ const uint8_t* crandom2 = ch->buffer().data() + 2;
+ const uint8_t* srandom2 = sh->buffer().data() + 2;
+
+ EXPECT_NE(0, memcmp(crandom2, srandom2, random_len));
+ EXPECT_NE(0, memcmp(crandom2, z, random_len));
+ EXPECT_NE(0, memcmp(srandom2, z, random_len));
+
+ EXPECT_NE(0, memcmp(crandom1, crandom2, random_len));
+ EXPECT_NE(0, memcmp(crandom1, srandom2, random_len));
+ EXPECT_NE(0, memcmp(srandom1, crandom2, random_len));
+ EXPECT_NE(0, memcmp(srandom1, srandom2, random_len));
+}
+
+void FailOnCloseNotify(const PRFileDesc* fd, void* arg, const SSLAlert* alert) {
+ ADD_FAILURE() << "received alert " << alert->description;
+}
+
+void CheckCloseNotify(const PRFileDesc* fd, void* arg, const SSLAlert* alert) {
+ *reinterpret_cast<bool*>(arg) = true;
+ EXPECT_EQ(close_notify, alert->description);
+ EXPECT_EQ(alert_warning, alert->level);
+}
+
+TEST_P(TlsConnectGeneric, ShutdownOneSide) {
+ Connect();
+
+ // Setup to check alerts.
+ EXPECT_EQ(SECSuccess, SSL_AlertSentCallback(server_->ssl_fd(),
+ FailOnCloseNotify, nullptr));
+ EXPECT_EQ(SECSuccess, SSL_AlertReceivedCallback(client_->ssl_fd(),
+ FailOnCloseNotify, nullptr));
+
+ bool client_sent = false;
+ EXPECT_EQ(SECSuccess, SSL_AlertSentCallback(client_->ssl_fd(),
+ CheckCloseNotify, &client_sent));
+ bool server_received = false;
+ EXPECT_EQ(SECSuccess,
+ SSL_AlertReceivedCallback(server_->ssl_fd(), CheckCloseNotify,
+ &server_received));
+ EXPECT_EQ(PR_SUCCESS, PR_Shutdown(client_->ssl_fd(), PR_SHUTDOWN_SEND));
+
+ // Make sure that the server reads out the close_notify.
+ uint8_t buf[10];
+ EXPECT_EQ(0, PR_Read(server_->ssl_fd(), buf, sizeof(buf)));
+
+ // Reading and writing should still work in the one open direction.
+ EXPECT_TRUE(client_sent);
+ EXPECT_TRUE(server_received);
+ server_->SendData(10, 10);
+ client_->ReadBytes(10);
+
+ // Now close the other side and do the same checks.
+ bool server_sent = false;
+ EXPECT_EQ(SECSuccess, SSL_AlertSentCallback(server_->ssl_fd(),
+ CheckCloseNotify, &server_sent));
+ bool client_received = false;
+ EXPECT_EQ(SECSuccess,
+ SSL_AlertReceivedCallback(client_->ssl_fd(), CheckCloseNotify,
+ &client_received));
+ EXPECT_EQ(PR_SUCCESS, PR_Shutdown(server_->ssl_fd(), PR_SHUTDOWN_SEND));
+
+ EXPECT_EQ(0, PR_Read(client_->ssl_fd(), buf, sizeof(buf)));
+ EXPECT_TRUE(server_sent);
+ EXPECT_TRUE(client_received);
+}
+
+TEST_P(TlsConnectGeneric, ShutdownOneSideThenCloseTcp) {
+ Connect();
+
+ bool client_sent = false;
+ EXPECT_EQ(SECSuccess, SSL_AlertSentCallback(client_->ssl_fd(),
+ CheckCloseNotify, &client_sent));
+ bool server_received = false;
+ EXPECT_EQ(SECSuccess,
+ SSL_AlertReceivedCallback(server_->ssl_fd(), CheckCloseNotify,
+ &server_received));
+ EXPECT_EQ(PR_SUCCESS, PR_Shutdown(client_->ssl_fd(), PR_SHUTDOWN_SEND));
+
+ // Make sure that the server reads out the close_notify.
+ uint8_t buf[10];
+ EXPECT_EQ(0, PR_Read(server_->ssl_fd(), buf, sizeof(buf)));
+
+ // Now simulate the underlying connection closing.
+ client_->adapter()->Reset();
+
+ // Now close the other side and see that things don't explode.
+ EXPECT_EQ(PR_SUCCESS, PR_Shutdown(server_->ssl_fd(), PR_SHUTDOWN_SEND));
+
+ EXPECT_GT(0, PR_Read(client_->ssl_fd(), buf, sizeof(buf)));
+ EXPECT_EQ(PR_NOT_CONNECTED_ERROR, PR_GetError());
+}
+
INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGeneric,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,