summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/gtests/ssl_gtest/tls_psk_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/tls_psk_unittest.cc515
1 files changed, 515 insertions, 0 deletions
diff --git a/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc b/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
new file mode 100644
index 0000000000..678a9ff585
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <functional>
+#include <memory>
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+class Tls13PskTest : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ Tls13PskTest()
+ : TlsConnectTestBase(std::get<0>(GetParam()),
+ SSL_LIBRARY_VERSION_TLS_1_3),
+ suite_(std::get<1>(GetParam())) {}
+
+ void SetUp() override {
+ TlsConnectTestBase::SetUp();
+ scoped_psk_.reset(GetPsk());
+ ASSERT_TRUE(!!scoped_psk_);
+ }
+
+ private:
+ PK11SymKey* GetPsk() {
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ ADD_FAILURE();
+ return nullptr;
+ }
+
+ SECItem psk_item;
+ psk_item.type = siBuffer;
+ psk_item.len = sizeof(kPskDummyVal_);
+ psk_item.data = const_cast<uint8_t*>(kPskDummyVal_);
+
+ PK11SymKey* key =
+ PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
+ CKA_DERIVE, &psk_item, NULL);
+ if (!key) {
+ ADD_FAILURE();
+ }
+ return key;
+ }
+
+ protected:
+ ScopedPK11SymKey scoped_psk_;
+ const uint16_t suite_;
+ const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
+ const SSLHashType kPskHash_ = ssl_hash_sha384;
+};
+
+// TLS 1.3 PSK connection test.
+TEST_P(Tls13PskTest, NormalExternal) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+ client_->RemovePsk(kPskDummyLabel_);
+ server_->RemovePsk(kPskDummyLabel_);
+
+ // Removing it again should fail.
+ EXPECT_EQ(SECFailure, SSL_RemoveExternalPsk(client_->ssl_fd(),
+ reinterpret_cast<const uint8_t*>(
+ kPskDummyLabel_.data()),
+ kPskDummyLabel_.length()));
+ EXPECT_EQ(SECFailure, SSL_RemoveExternalPsk(server_->ssl_fd(),
+ reinterpret_cast<const uint8_t*>(
+ kPskDummyLabel_.data()),
+ kPskDummyLabel_.length()));
+}
+
+TEST_P(Tls13PskTest, KeyTooLarge) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ ASSERT_TRUE(!!slot);
+ ScopedPK11SymKey scoped_psk(PK11_KeyGen(
+ slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 128, nullptr));
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+// Attempt to use a PSK with the wrong PRF hash.
+// "Clients MUST verify that...the server selected a cipher suite
+// indicating a Hash associated with the PSK"
+TEST_P(Tls13PskTest, ClientVerifyHashType) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ MakeTlsFilter<SelectedCipherSuiteReplacer>(server_,
+ TLS_CHACHA20_POLY1305_SHA256);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
+ } else {
+ ConnectExpectFailOneSide(TlsAgent::CLIENT);
+ }
+ EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
+}
+
+// Different EPSKs (by label) on each endpoint. Expect cert auth.
+TEST_P(Tls13PskTest, LabelMismatch) {
+ client_->AddPsk(scoped_psk_, std::string("foo"), kPskHash_);
+ server_->AddPsk(scoped_psk_, std::string("bar"), kPskHash_);
+ Connect();
+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+}
+
+SSLHelloRetryRequestAction RetryFirstHello(
+ PRBool firstHello, const PRUint8* clientToken, unsigned int clientTokenLen,
+ PRUint8* appToken, unsigned int* appTokenLen, unsigned int appTokenMax,
+ void* arg) {
+ auto* called = reinterpret_cast<size_t*>(arg);
+ ++*called;
+ EXPECT_EQ(0U, clientTokenLen);
+ EXPECT_EQ(*called, firstHello ? 1U : 2U);
+ return firstHello ? ssl_hello_retry_request : ssl_hello_retry_accept;
+}
+
+// Test resumption PSK with HRR.
+TEST_P(Tls13PskTest, ResPskRetryStateless) {
+ ConfigureSelfEncrypt();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive(); // Need to read so that we absorb the session ticket.
+ CheckKeys();
+
+ Reset();
+ StartConnect();
+ size_t cb_called = 0;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
+ server_->ssl_fd(), RetryFirstHello, &cb_called));
+ ExpectResumption(RESUME_TICKET);
+ Handshake();
+ CheckConnected();
+ EXPECT_EQ(2U, cb_called);
+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+ SendReceive();
+}
+
+// Test external PSK with HRR.
+TEST_P(Tls13PskTest, ExtPskRetryStateless) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ size_t cb_called = 0;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
+ server_->ssl_fd(), RetryFirstHello, &cb_called));
+ StartConnect();
+ client_->Handshake();
+ server_->Handshake();
+ EXPECT_EQ(1U, cb_called);
+ auto replacement = std::make_shared<TlsAgent>(
+ server_->name(), TlsAgent::SERVER, server_->variant());
+ server_ = replacement;
+ server_->SetVersionRange(version_, version_);
+ client_->SetPeer(server_);
+ server_->SetPeer(client_);
+ server_->AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ server_->ExpectPsk();
+ server_->StartConnect();
+ Handshake();
+ CheckConnected();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+// Server not configured with PSK and sends a certificate instead of
+// a selected_identity. Client should attempt certificate authentication.
+TEST_P(Tls13PskTest, ClientOnly) {
+ client_->AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ Connect();
+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+}
+
+// Set a PSK, remove psk_key_exchange_modes.
+TEST_P(Tls13PskTest, DropKexModes) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ StartConnect();
+ MakeTlsFilter<TlsExtensionDropper>(client_,
+ ssl_tls13_psk_key_exchange_modes_xtn);
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
+ client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
+ server_->CheckErrorCode(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES);
+}
+
+// "Clients MUST verify that...a server "key_share" extension is present
+// if required by the ClientHello "psk_key_exchange_modes" extension."
+// As we don't support PSK without DH, it is always required.
+TEST_P(Tls13PskTest, DropRequiredKeyShare) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ StartConnect();
+ MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_key_share_xtn);
+ client_->ExpectSendAlert(kTlsAlertMissingExtension);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ } else {
+ ConnectExpectFailOneSide(TlsAgent::CLIENT);
+ }
+ client_->CheckErrorCode(SSL_ERROR_MISSING_KEY_SHARE);
+}
+
+// "Clients MUST verify that...the server's selected_identity is
+// within the range supplied by the client". We send one OfferedPsk.
+TEST_P(Tls13PskTest, InvalidSelectedIdentity) {
+ static const uint8_t selected_identity[] = {0x00, 0x01};
+ DataBuffer buf(selected_identity, sizeof(selected_identity));
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ StartConnect();
+ MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_pre_shared_key_xtn,
+ buf);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ } else {
+ ConnectExpectFailOneSide(TlsAgent::CLIENT);
+ }
+ client_->CheckErrorCode(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
+}
+
+// Resume-eligible reconnect with an EPSK configured.
+// Expect the EPSK to be used.
+TEST_P(Tls13PskTest, PreferEpsk) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive(); // Need to read so that we absorb the session ticket.
+ CheckKeys();
+
+ Reset();
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ ExpectResumption(RESUME_NONE);
+ StartConnect();
+ Handshake();
+ CheckConnected();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+// Enable resumption, but connect (initially) with an EPSK.
+// Expect no session ticket.
+TEST_P(Tls13PskTest, SuppressNewSessionTicket) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ auto nst_capture =
+ MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_new_session_ticket);
+ nst_capture->EnableDecryption();
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+ EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
+ EXPECT_EQ(0U, nst_capture->buffer().len());
+ if (variant_ == ssl_variant_stream) {
+ EXPECT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
+ } else {
+ EXPECT_EQ(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, PORT_GetError());
+ }
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ ExpectResumption(RESUME_NONE);
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+TEST_P(Tls13PskTest, BadConfigValues) {
+ EXPECT_TRUE(client_->EnsureTlsSetup());
+ std::vector<uint8_t> label{'L', 'A', 'B', 'E', 'L'};
+ EXPECT_EQ(SECFailure,
+ SSL_AddExternalPsk(client_->ssl_fd(), nullptr, label.data(),
+ label.size(), kPskHash_));
+ EXPECT_EQ(SECFailure, SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
+ nullptr, label.size(), kPskHash_));
+
+ EXPECT_EQ(SECFailure, SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
+ label.data(), 0, kPskHash_));
+ EXPECT_EQ(SECSuccess,
+ SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
+ label.data(), label.size(), ssl_hash_sha256));
+
+ EXPECT_EQ(SECFailure,
+ SSL_RemoveExternalPsk(client_->ssl_fd(), nullptr, label.size()));
+
+ EXPECT_EQ(SECFailure,
+ SSL_RemoveExternalPsk(client_->ssl_fd(), label.data(), 0));
+
+ EXPECT_EQ(SECSuccess, SSL_RemoveExternalPsk(client_->ssl_fd(), label.data(),
+ label.size()));
+}
+
+// If the server has an EPSK configured with a ciphersuite not supported
+// by the client, it should use certificate authentication.
+TEST_P(Tls13PskTest, FallbackUnsupportedCiphersuite) {
+ client_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
+ TLS_AES_128_GCM_SHA256);
+ server_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
+ TLS_CHACHA20_POLY1305_SHA256);
+
+ client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+}
+
+// That fallback should not occur if there is no cipher overlap.
+TEST_P(Tls13PskTest, ExplicitSuiteNoOverlap) {
+ client_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
+ TLS_AES_128_GCM_SHA256);
+ server_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
+ TLS_CHACHA20_POLY1305_SHA256);
+
+ client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+ server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+ server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+TEST_P(Tls13PskTest, SuppressHandshakeCertReq) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ server_->SetOption(SSL_REQUEST_CERTIFICATE, PR_TRUE);
+ server_->SetOption(SSL_REQUIRE_CERTIFICATE, PR_TRUE);
+ const std::set<uint8_t> hs_types = {ssl_hs_certificate,
+ ssl_hs_certificate_request};
+ auto cr_cert_capture = MakeTlsFilter<TlsHandshakeRecorder>(server_, hs_types);
+ cr_cert_capture->EnableDecryption();
+
+ Connect();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+ EXPECT_EQ(0U, cr_cert_capture->buffer().len());
+}
+
+TEST_P(Tls13PskTest, DisallowClientConfigWithoutServerCert) {
+ AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
+ server_->SetOption(SSL_REQUEST_CERTIFICATE, PR_TRUE);
+ server_->SetOption(SSL_REQUIRE_CERTIFICATE, PR_TRUE);
+ const std::set<uint8_t> hs_types = {ssl_hs_certificate,
+ ssl_hs_certificate_request};
+ auto cr_cert_capture = MakeTlsFilter<TlsHandshakeRecorder>(server_, hs_types);
+ cr_cert_capture->EnableDecryption();
+
+ EXPECT_EQ(SECSuccess, SSLInt_RemoveServerCertificates(server_->ssl_fd()));
+
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+ server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ EXPECT_EQ(0U, cr_cert_capture->buffer().len());
+}
+
+TEST_F(TlsConnectStreamTls13, ClientRejectHandshakeCertReq) {
+ // Stream only, as the filter doesn't support DTLS 1.3 yet.
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ ASSERT_TRUE(!!slot);
+ ScopedPK11SymKey scoped_psk(PK11_KeyGen(
+ slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 32, nullptr));
+ AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256);
+ // Inject a CR after EE. This would be legal if not for ssl_auth_psk.
+ auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
+ server_, kTlsHandshakeFinished, kTlsHandshakeCertificateRequest);
+ filter->EnableDecryption();
+
+ ExpectAlert(client_, kTlsAlertUnexpectedMessage);
+ ConnectExpectFail();
+ client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
+ server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
+}
+
+TEST_F(TlsConnectStreamTls13, RejectPha) {
+ // Stream only, as the filter doesn't support DTLS 1.3 yet.
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ ASSERT_TRUE(!!slot);
+ ScopedPK11SymKey scoped_psk(PK11_KeyGen(
+ slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 32, nullptr));
+ AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256);
+ server_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
+ auto kuToCr = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
+ server_, kTlsHandshakeKeyUpdate, kTlsHandshakeCertificateRequest);
+ kuToCr->EnableDecryption();
+ Connect();
+
+ // Make sure the direct path is blocked.
+ EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
+ EXPECT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
+
+ // Inject a PHA CR. Since this is not allowed, send KeyUpdate
+ // and change the message type.
+ EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
+ ExpectAlert(client_, kTlsAlertUnexpectedMessage);
+ client_->Handshake(); // Eat the CR.
+ server_->Handshake();
+ client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
+ server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
+}
+
+class Tls13PskTestWithCiphers : public Tls13PskTest {};
+
+TEST_P(Tls13PskTestWithCiphers, 0RttCiphers) {
+ RolloverAntiReplay();
+ AddPsk(scoped_psk_, kPskDummyLabel_, tls13_GetHashForCipherSuite(suite_),
+ suite_);
+ StartConnect();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ZeroRttSendReceive(true, true);
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+ SendReceive();
+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
+}
+
+TEST_P(Tls13PskTestWithCiphers, 0RttMaxEarlyData) {
+ EnsureTlsSetup();
+ RolloverAntiReplay();
+ const char* big_message = "0123456789abcdef";
+ const size_t short_size = strlen(big_message) - 1;
+ const PRInt32 short_length = static_cast<PRInt32>(short_size);
+
+ // Set up the PSK
+ EXPECT_EQ(SECSuccess,
+ SSL_AddExternalPsk0Rtt(
+ client_->ssl_fd(), scoped_psk_.get(),
+ reinterpret_cast<const uint8_t*>(kPskDummyLabel_.data()),
+ kPskDummyLabel_.length(), tls13_GetHashForCipherSuite(suite_),
+ suite_, short_length));
+ EXPECT_EQ(SECSuccess,
+ SSL_AddExternalPsk0Rtt(
+ server_->ssl_fd(), scoped_psk_.get(),
+ reinterpret_cast<const uint8_t*>(kPskDummyLabel_.data()),
+ kPskDummyLabel_.length(), tls13_GetHashForCipherSuite(suite_),
+ suite_, short_length));
+ client_->ExpectPsk();
+ server_->ExpectPsk();
+ client_->expected_cipher_suite(suite_);
+ server_->expected_cipher_suite(suite_);
+ StartConnect();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ client_->Handshake();
+ CheckEarlyDataLimit(client_, short_size);
+
+ PRInt32 sent;
+ // Writing more than the limit will succeed in TLS, but fail in DTLS.
+ if (variant_ == ssl_variant_stream) {
+ sent = PR_Write(client_->ssl_fd(), big_message,
+ static_cast<PRInt32>(strlen(big_message)));
+ } else {
+ sent = PR_Write(client_->ssl_fd(), big_message,
+ static_cast<PRInt32>(strlen(big_message)));
+ EXPECT_GE(0, sent);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ // Try an exact-sized write now.
+ sent = PR_Write(client_->ssl_fd(), big_message, short_length);
+ }
+ EXPECT_EQ(short_length, sent);
+
+ // Even a single octet write should now fail.
+ sent = PR_Write(client_->ssl_fd(), big_message, 1);
+ EXPECT_GE(0, sent);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ // Process the ClientHello and read 0-RTT.
+ server_->Handshake();
+ CheckEarlyDataLimit(server_, short_size);
+
+ std::vector<uint8_t> buf(short_size + 1);
+ PRInt32 read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
+ EXPECT_EQ(short_length, read);
+ EXPECT_EQ(0, memcmp(big_message, buf.data(), short_size));
+
+ // Second read fails.
+ read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
+ EXPECT_EQ(SECFailure, read);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+ SendReceive();
+}
+
+static const uint16_t k0RttCipherDefs[] = {TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384};
+
+static const uint16_t kDefaultSuite[] = {TLS_CHACHA20_POLY1305_SHA256};
+
+INSTANTIATE_TEST_SUITE_P(
+ Tls13PskTest, Tls13PskTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ ::testing::ValuesIn(kDefaultSuite)));
+
+INSTANTIATE_TEST_SUITE_P(
+ Tls13PskTestWithCiphers, Tls13PskTestWithCiphers,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ ::testing::ValuesIn(k0RttCipherDefs)));
+
+} // namespace nss_test