515 lines
19 KiB
C++
515 lines
19 KiB
C++
/* -*- 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
|