878 lines
30 KiB
C++
878 lines
30 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 "secerr.h"
|
|
#include "ssl.h"
|
|
|
|
#include "gtest_utils.h"
|
|
#include "tls_connect.h"
|
|
#include "util.h"
|
|
|
|
namespace nss_test {
|
|
|
|
const uint8_t kTlsGreaseExtensionMessages[] = {kTlsHandshakeEncryptedExtensions,
|
|
kTlsHandshakeCertificate};
|
|
|
|
const uint16_t kTlsGreaseValues[] = {
|
|
0x0a0a, 0x1a1a, 0x2a2a, 0x3a3a, 0x4a4a, 0x5a5a, 0x6a6a, 0x7a7a,
|
|
0x8a8a, 0x9a9a, 0xaaaa, 0xbaba, 0xcaca, 0xdada, 0xeaea, 0xfafa};
|
|
|
|
const uint8_t kTlsGreasePskValues[] = {0x0B, 0x2A, 0x49, 0x68,
|
|
0x87, 0xA6, 0xC5, 0xE4};
|
|
|
|
size_t countGreaseInBuffer(const DataBuffer& list) {
|
|
if (!list.len()) {
|
|
return 0;
|
|
}
|
|
size_t occurrence = 0;
|
|
for (uint16_t greaseVal : kTlsGreaseValues) {
|
|
for (size_t i = 0; i < (list.len() - 1); i += 2) {
|
|
uint16_t sample = list.data()[i + 1] + (list.data()[i] << 8);
|
|
if (greaseVal == sample) {
|
|
occurrence++;
|
|
}
|
|
}
|
|
}
|
|
return occurrence;
|
|
}
|
|
|
|
class GreasePresenceAbsenceTestBase : public TlsConnectTestBase {
|
|
public:
|
|
GreasePresenceAbsenceTestBase(SSLProtocolVariant variant, uint16_t version,
|
|
bool shouldGrease)
|
|
: TlsConnectTestBase(variant, version), set_grease_(shouldGrease){};
|
|
|
|
void SetupGrease() {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_),
|
|
SECSuccess);
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_),
|
|
SECSuccess);
|
|
}
|
|
|
|
bool expectGrease() {
|
|
return set_grease_ && version_ >= SSL_LIBRARY_VERSION_TLS_1_3;
|
|
}
|
|
|
|
void checkGreasePresence(const int ifEnabled, const int ifDisabled,
|
|
const DataBuffer& buffer) {
|
|
size_t expected = expectGrease() ? size_t(ifEnabled) : size_t(ifDisabled);
|
|
EXPECT_EQ(expected, countGreaseInBuffer(buffer));
|
|
}
|
|
|
|
private:
|
|
bool set_grease_;
|
|
};
|
|
|
|
class GreasePresenceAbsenceTestAllVersions
|
|
: public GreasePresenceAbsenceTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t, bool>> {
|
|
public:
|
|
GreasePresenceAbsenceTestAllVersions()
|
|
: GreasePresenceAbsenceTestBase(std::get<0>(GetParam()),
|
|
std::get<1>(GetParam()),
|
|
std::get<2>(GetParam())){};
|
|
};
|
|
|
|
// Varies stream/datagram, TLS Version and whether GREASE is enabled
|
|
INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestAllVersions,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV11Plus,
|
|
::testing::Values(true, false)));
|
|
|
|
// Varies whether GREASE is enabled for TLS13 only
|
|
class GreasePresenceAbsenceTestTlsStream13
|
|
: public GreasePresenceAbsenceTestBase,
|
|
public ::testing::WithParamInterface<bool> {
|
|
public:
|
|
GreasePresenceAbsenceTestTlsStream13()
|
|
: GreasePresenceAbsenceTestBase(
|
|
ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3, GetParam()){};
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestTlsStream13,
|
|
::testing::Values(true, false));
|
|
|
|
// These tests check for the presence / absence of GREASE values in the various
|
|
// positions that we are permitted to add them. For positions which existed in
|
|
// prior versions of TLS, we check that enabling GREASE is only effective when
|
|
// negotiating TLS1.3 or higher and that disabling GREASE results in the absence
|
|
// of any GREASE values.
|
|
// For positions that specific to TLS1.3, we only check that enabling/disabling
|
|
// GREASE results in the correct presence/absence of the GREASE value.
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseCiphersuites) {
|
|
SetupGrease();
|
|
|
|
auto ch1 = MakeTlsFilter<ClientHelloCiphersuiteCapture>(client_);
|
|
Connect();
|
|
EXPECT_TRUE(ch1->captured());
|
|
|
|
checkGreasePresence(1, 0, ch1->contents());
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseNamedGroups) {
|
|
SetupGrease();
|
|
|
|
auto ch1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_supported_groups_xtn);
|
|
Connect();
|
|
EXPECT_TRUE(ch1->captured());
|
|
|
|
checkGreasePresence(1, 0, ch1->extension());
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseKeyShare) {
|
|
SetupGrease();
|
|
|
|
auto ch1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_key_share_xtn);
|
|
Connect();
|
|
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured());
|
|
|
|
checkGreasePresence(1, 0, ch1->extension());
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSigAlg) {
|
|
SetupGrease();
|
|
|
|
auto ch1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
|
Connect();
|
|
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_2) == ch1->captured());
|
|
|
|
checkGreasePresence(1, 0, ch1->extension());
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSupportedVersions) {
|
|
SetupGrease();
|
|
|
|
auto ch1 = MakeTlsFilter<TlsExtensionCapture>(
|
|
client_, ssl_tls13_supported_versions_xtn);
|
|
Connect();
|
|
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured());
|
|
|
|
// Supported Versions have a 1 byte length field.
|
|
TlsParser extParser(ch1->extension());
|
|
DataBuffer versions;
|
|
extParser.ReadVariable(&versions, 1);
|
|
|
|
checkGreasePresence(1, 0, versions);
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestTlsStream13, ClientGreasePskExchange) {
|
|
SetupGrease();
|
|
|
|
auto ch1 = MakeTlsFilter<TlsExtensionCapture>(
|
|
client_, ssl_tls13_psk_key_exchange_modes_xtn);
|
|
Connect();
|
|
EXPECT_TRUE(ch1->captured());
|
|
|
|
// PSK Exchange Modes have a 1 byte length field
|
|
TlsParser extParser(ch1->extension());
|
|
DataBuffer modes;
|
|
extParser.ReadVariable(&modes, 1);
|
|
|
|
// Scan for single byte GREASE PSK Values
|
|
size_t numGrease = 0;
|
|
for (uint8_t greaseVal : kTlsGreasePskValues) {
|
|
for (unsigned long i = 0; i < modes.len(); i++) {
|
|
if (greaseVal == modes.data()[i]) {
|
|
numGrease++;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), numGrease);
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseAlpn) {
|
|
SetupGrease();
|
|
EnableAlpn();
|
|
|
|
auto ch1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_app_layer_protocol_xtn);
|
|
Connect();
|
|
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_1) == ch1->captured());
|
|
|
|
// ALPN Xtns have a redundant two-byte length
|
|
TlsParser alpnParser(ch1->extension());
|
|
alpnParser.Skip(2); // Skip the length
|
|
DataBuffer alpnEntry;
|
|
|
|
// Each ALPN entry has a single byte length prefixed.
|
|
size_t greaseAlpnEntrys = 0;
|
|
while (alpnParser.remaining()) {
|
|
alpnParser.ReadVariable(&alpnEntry, 1);
|
|
if (alpnEntry.len() == 2) {
|
|
greaseAlpnEntrys += countGreaseInBuffer(alpnEntry);
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), greaseAlpnEntrys);
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestAllVersions, GreaseClientHelloExtension) {
|
|
SetupGrease();
|
|
|
|
auto ch1 =
|
|
MakeTlsFilter<TlsHandshakeRecorder>(client_, kTlsHandshakeClientHello);
|
|
Connect();
|
|
EXPECT_TRUE(ch1->buffer().len() > 0);
|
|
|
|
TlsParser extParser(ch1->buffer());
|
|
EXPECT_TRUE(extParser.Skip(2 + 32)); // Version + Random
|
|
EXPECT_TRUE(extParser.SkipVariable(1)); // Session ID
|
|
if (variant_ == ssl_variant_datagram) {
|
|
EXPECT_TRUE(extParser.SkipVariable(1)); // Cookie
|
|
}
|
|
EXPECT_TRUE(extParser.SkipVariable(2)); // Ciphersuites
|
|
EXPECT_TRUE(extParser.SkipVariable(1)); // Compression Methods
|
|
EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths
|
|
|
|
// Scan for a 1-byte and a 0-byte extension.
|
|
uint32_t extType;
|
|
DataBuffer extBuf;
|
|
bool foundSmall = false;
|
|
bool foundLarge = false;
|
|
size_t numFound = 0;
|
|
while (extParser.remaining()) {
|
|
extParser.Read(&extType, 2);
|
|
extParser.ReadVariable(&extBuf, 2);
|
|
for (uint16_t greaseVal : kTlsGreaseValues) {
|
|
if (greaseVal == extType) {
|
|
numFound++;
|
|
foundSmall |= extBuf.len() == 0;
|
|
foundLarge |= extBuf.len() > 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(foundSmall, expectGrease());
|
|
EXPECT_EQ(foundLarge, expectGrease());
|
|
EXPECT_EQ(numFound, expectGrease() ? size_t(2) : size_t(0));
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseCertificateRequestSigAlg) {
|
|
SetupGrease();
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
|
|
auto cr =
|
|
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_signature_algorithms_xtn);
|
|
cr->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
|
|
cr->EnableDecryption();
|
|
Connect();
|
|
EXPECT_TRUE(cr->captured());
|
|
|
|
checkGreasePresence(1, 0, cr->extension());
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestTlsStream13,
|
|
GreaseCertificateRequestExtension) {
|
|
SetupGrease();
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
|
|
auto cr = MakeTlsFilter<TlsHandshakeRecorder>(
|
|
server_, kTlsHandshakeCertificateRequest);
|
|
cr->EnableDecryption();
|
|
Connect();
|
|
EXPECT_TRUE(cr->buffer().len() > 0);
|
|
|
|
TlsParser extParser(cr->buffer());
|
|
EXPECT_TRUE(extParser.SkipVariable(1)); // Context
|
|
EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths
|
|
|
|
uint32_t extType;
|
|
DataBuffer extBuf;
|
|
bool found = false;
|
|
// Scan for a single, empty extension
|
|
while (extParser.remaining()) {
|
|
extParser.Read(&extType, 2);
|
|
extParser.ReadVariable(&extBuf, 2);
|
|
for (uint16_t greaseVal : kTlsGreaseValues) {
|
|
if (greaseVal == extType) {
|
|
EXPECT_TRUE(!found);
|
|
EXPECT_EQ(extBuf.len(), size_t(0));
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(expectGrease(), found);
|
|
}
|
|
|
|
TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseNewSessionTicketExtension) {
|
|
SetupGrease();
|
|
|
|
auto nst = MakeTlsFilter<TlsHandshakeRecorder>(server_,
|
|
kTlsHandshakeNewSessionTicket);
|
|
nst->EnableDecryption();
|
|
Connect();
|
|
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
|
|
EXPECT_TRUE(nst->buffer().len() > 0);
|
|
|
|
TlsParser extParser(nst->buffer());
|
|
EXPECT_TRUE(extParser.Skip(4)); // lifetime
|
|
EXPECT_TRUE(extParser.Skip(4)); // age
|
|
EXPECT_TRUE(extParser.SkipVariable(1)); // Nonce
|
|
EXPECT_TRUE(extParser.SkipVariable(2)); // Ticket
|
|
EXPECT_TRUE(extParser.Skip(2)); // Extension Length
|
|
|
|
uint32_t extType;
|
|
DataBuffer extBuf;
|
|
bool found = false;
|
|
// Scan for a single, empty extension
|
|
while (extParser.remaining()) {
|
|
extParser.Read(&extType, 2);
|
|
extParser.ReadVariable(&extBuf, 2);
|
|
for (uint16_t greaseVal : kTlsGreaseValues) {
|
|
if (greaseVal == extType) {
|
|
EXPECT_TRUE(!found);
|
|
EXPECT_EQ(extBuf.len(), size_t(0));
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(expectGrease(), found);
|
|
}
|
|
|
|
// Generic Client GREASE test
|
|
TEST_P(TlsConnectGeneric, ClientGrease) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
// Generic Server GREASE test
|
|
TEST_P(TlsConnectGeneric, ServerGrease) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
// Generic GREASE test
|
|
TEST_P(TlsConnectGeneric, Grease) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
// Check that GREASE values can be correctly reconstructed after HRR.
|
|
TEST_P(TlsConnectGeneric, GreaseHRR) {
|
|
EnsureTlsSetup();
|
|
const std::vector<SSLNamedGroup> client_groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
// Check that GREASE additions interact correctly with psk-only handshake.
|
|
TEST_F(TlsConnectStreamTls13, GreasePsk) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
|
|
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
|
const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
|
|
0x06, 0x07, 0x08, 0x09, 0x0a,
|
|
0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
|
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);
|
|
|
|
ScopedPK11SymKey scoped_psk_(key);
|
|
const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
|
|
const SSLHashType kPskHash_ = ssl_hash_sha384;
|
|
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
|
|
|
Connect();
|
|
SendReceive();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
|
}
|
|
|
|
// Test that ECH and GREASE work together successfully
|
|
TEST_F(TlsConnectStreamTls13, GreaseAndECH) {
|
|
EnsureTlsSetup();
|
|
SetupEch(client_, server_);
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
// Test that TLS12 Server handles Client GREASE correctly
|
|
TEST_F(TlsConnectTest, GreaseTLS12Server) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
|
SSL_LIBRARY_VERSION_TLS_1_2);
|
|
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
|
SSL_LIBRARY_VERSION_TLS_1_3);
|
|
Connect();
|
|
}
|
|
|
|
// Test that TLS12 Client handles Server GREASE correctly
|
|
TEST_F(TlsConnectTest, GreaseTLS12Client) {
|
|
EnsureTlsSetup();
|
|
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
|
SECSuccess);
|
|
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
|
SSL_LIBRARY_VERSION_TLS_1_3);
|
|
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
|
SSL_LIBRARY_VERSION_TLS_1_2);
|
|
Connect();
|
|
}
|
|
|
|
class GreaseOnlyTestStreamTls13 : public TlsConnectStreamTls13 {
|
|
public:
|
|
GreaseOnlyTestStreamTls13() : TlsConnectStreamTls13() {}
|
|
|
|
void ConnectWithCustomChExpectFail(const std::string& ch,
|
|
uint8_t server_alert, uint32_t server_code,
|
|
uint32_t client_code) {
|
|
std::vector<uint8_t> ch_vec = hex_string_to_bytes(ch);
|
|
DataBuffer ch_buf;
|
|
EnsureTlsSetup();
|
|
|
|
TlsAgentTestBase::MakeRecord(variant_, ssl_ct_handshake,
|
|
SSL_LIBRARY_VERSION_TLS_1_3, ch_vec.data(),
|
|
ch_vec.size(), &ch_buf, 0);
|
|
StartConnect();
|
|
client_->SendDirect(ch_buf);
|
|
ExpectAlert(server_, server_alert);
|
|
server_->Handshake();
|
|
server_->CheckErrorCode(server_code);
|
|
client_->ExpectReceiveAlert(server_alert, kTlsAlertFatal);
|
|
client_->Handshake();
|
|
client_->CheckErrorCode(client_code);
|
|
}
|
|
};
|
|
|
|
// Client: Offer only GREASE CipherSuite value
|
|
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientCipherSuite) {
|
|
// 0xdada
|
|
std::string ch =
|
|
"010000b003038afacda2963358e98f464f3ff0680ed3a9d382a8c3eac5e5604f5721add9"
|
|
"855c000002dada010000850000000b0009000006736572766572ff01000100000a001400"
|
|
"12001d00170018001901000101010201030104003300260024001d0020683668992de470"
|
|
"38660ee37bafc7392b05b8a94402ea1f3463ad3cfd7a694a46002b0003020304000d0018"
|
|
"001604030503060302030804080508060401050106010201002d00020101001c0002400"
|
|
"1";
|
|
|
|
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
|
SSL_ERROR_NO_CYPHER_OVERLAP,
|
|
SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
}
|
|
|
|
// Client: Offer only GREASE SupportedGroups value
|
|
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedGroup) {
|
|
// 0x3a3a
|
|
std::string ch =
|
|
"010000a40303484a4e14f547404da6115d7f73bbb0f1c9d65e66ac073dee6c4a62f72de9"
|
|
"a36f000006130113031302010000750000000b0009000006736572766572ff0100010000"
|
|
"0a000400023a3a003300260024001d0020e75cb8e217c95176954e8b5fb95843882462ce"
|
|
"2cd3fcfe67cf31463a05ea3d57002b0003020304000d0018001604030503060302030804"
|
|
"080508060401050106010201002d00020101001c00024001";
|
|
|
|
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
|
SSL_ERROR_NO_CYPHER_OVERLAP,
|
|
SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
}
|
|
|
|
// Client: Offer only GREASE SigAlgs value
|
|
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSignatureAlgorithm) {
|
|
// 0x8a8a
|
|
std::string ch =
|
|
"010000a00303dfd8e2438a8d1b9f48d921dfc08959108807bd1105238bb3da2a2a8e3db0"
|
|
"6990000006130113031302010000710000000b0009000006736572766572ff0100010000"
|
|
"0a00140012001d00170018001901000101010201030104003300260024001d002074bb2c"
|
|
"94996d3ffc7ae5792f0c3c58676358a85ea304cd029fa3d6551013b333002b0003020304"
|
|
"000d000400028a8a002d00020101001c00024001";
|
|
|
|
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
|
SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM,
|
|
SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
}
|
|
|
|
// Client: Offer only GREASE SupportedVersions value
|
|
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedVersion) {
|
|
// 0xeaea
|
|
std::string ch =
|
|
"010000b203037e3618abae0dd0b3f06a504c47354551d1d5be36e9c3e1eac9c139c246b1"
|
|
"66da000006130113031302010000830000000b0009000006736572766572ff0100010000"
|
|
"0a00140012001d00170018001901000101010201030104003300260024001d00206b1816"
|
|
"577ff2e69d4d2661419150eaefa0328ffd396425cf1733ec06536b4e55002b000100000d"
|
|
"0018001604030503060302030804080508060401050106010201002d00020101001c0002"
|
|
"4001";
|
|
|
|
ConnectWithCustomChExpectFail(ch, kTlsAlertIllegalParameter,
|
|
SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
|
|
SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
class GreaseTestStreamTls12
|
|
: public TlsConnectStreamTls12,
|
|
public ::testing::WithParamInterface<uint16_t /* GREASE */> {
|
|
public:
|
|
GreaseTestStreamTls12() : TlsConnectStreamTls12(), grease_(GetParam()){};
|
|
|
|
void ConnectExpectSigAlgFail() {
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
protected:
|
|
uint16_t grease_;
|
|
};
|
|
|
|
class TlsCertificateRequestSigAlgSetterFilter : public TlsHandshakeFilter {
|
|
public:
|
|
TlsCertificateRequestSigAlgSetterFilter(const std::shared_ptr<TlsAgent>& a,
|
|
uint16_t sigAlg)
|
|
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}),
|
|
sigAlg_(sigAlg) {}
|
|
virtual PacketFilter::Action FilterHandshake(
|
|
const TlsHandshakeFilter::HandshakeHeader& header,
|
|
const DataBuffer& input, DataBuffer* output) {
|
|
TlsParser parser(input);
|
|
DataBuffer cert_types;
|
|
if (!parser.ReadVariable(&cert_types, 1)) {
|
|
ADD_FAILURE();
|
|
return KEEP;
|
|
}
|
|
|
|
if (!parser.SkipVariable(2)) {
|
|
ADD_FAILURE();
|
|
return KEEP;
|
|
}
|
|
|
|
DataBuffer cas;
|
|
if (!parser.ReadVariable(&cas, 2)) {
|
|
ADD_FAILURE();
|
|
return KEEP;
|
|
}
|
|
|
|
size_t idx = 0;
|
|
|
|
// Write certificate types.
|
|
idx = output->Write(idx, cert_types.len(), 1);
|
|
idx = output->Write(idx, cert_types);
|
|
|
|
// Write signature algorithm.
|
|
idx = output->Write(idx, sizeof(sigAlg_), 2);
|
|
idx = output->Write(idx, sigAlg_, 2);
|
|
|
|
// Write certificate authorities.
|
|
idx = output->Write(idx, cas.len(), 2);
|
|
idx = output->Write(idx, cas);
|
|
|
|
return CHANGE;
|
|
}
|
|
|
|
private:
|
|
uint16_t sigAlg_;
|
|
};
|
|
|
|
// Server: Offer only GREASE CertificateRequest SigAlg value
|
|
TEST_P(GreaseTestStreamTls12, GreaseOnlyServerTLS12CertificateRequestSigAlg) {
|
|
EnsureTlsSetup();
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
MakeTlsFilter<TlsCertificateRequestSigAlgSetterFilter>(server_, grease_);
|
|
|
|
client_->ExpectSendAlert(kTlsAlertHandshakeFailure);
|
|
server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
|
|
ConnectExpectFail();
|
|
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
|
|
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
}
|
|
|
|
// Illegally GREASE ServerKeyExchange ECC SignatureAlgorithm
|
|
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEccSigAlg) {
|
|
MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_, grease_);
|
|
EnableSomeEcdhCiphers();
|
|
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
// Illegally GREASE ServerKeyExchange DHE SignatureAlgorithm
|
|
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexDheSigAlg) {
|
|
MakeTlsFilter<DHEServerKEXSigAlgReplacer>(server_, grease_);
|
|
EnableOnlyDheCiphers();
|
|
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
// Illegally GREASE ServerKeyExchange ECDHE NamedCurve
|
|
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEcdheNamedCurve) {
|
|
MakeTlsFilter<ECCServerKEXNamedCurveReplacer>(server_, grease_);
|
|
EnableSomeEcdhCiphers();
|
|
|
|
client_->ExpectSendAlert(kTlsAlertHandshakeFailure);
|
|
server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
|
|
ConnectExpectFail();
|
|
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
|
|
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
|
}
|
|
|
|
// Illegally GREASE TLS12 Client CertificateVerify SignatureAlgorithm
|
|
TEST_P(GreaseTestStreamTls12, GreasedTLS12ClientCertificateVerifySigAlg) {
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_, grease_);
|
|
|
|
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
}
|
|
|
|
class GreaseTestStreamTls13
|
|
: public TlsConnectStreamTls13,
|
|
public ::testing::WithParamInterface<uint16_t /* GREASE */> {
|
|
public:
|
|
GreaseTestStreamTls13() : grease_(GetParam()){};
|
|
|
|
protected:
|
|
uint16_t grease_;
|
|
};
|
|
|
|
// Illegally GREASE TLS13 Client CertificateVerify SignatureAlgorithm
|
|
TEST_P(GreaseTestStreamTls13, GreasedTLS13ClientCertificateVerifySigAlg) {
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
auto filter =
|
|
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_, grease_);
|
|
filter->EnableDecryption();
|
|
|
|
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
|
|
// Manually trigger handshake to avoid race conditions
|
|
StartConnect();
|
|
client_->Handshake();
|
|
server_->Handshake();
|
|
client_->Handshake();
|
|
server_->Handshake();
|
|
client_->Handshake();
|
|
|
|
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
|
|
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
// Illegally GREASE TLS13 Server CertificateVerify SignatureAlgorithm
|
|
TEST_P(GreaseTestStreamTls13, GreasedTLS13ServerCertificateVerifySigAlg) {
|
|
EnsureTlsSetup();
|
|
auto filter =
|
|
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, grease_);
|
|
filter->EnableDecryption();
|
|
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
|
|
}
|
|
|
|
// Illegally GREASE HelloRetryRequest version value
|
|
TEST_P(GreaseTestStreamTls13, GreasedHelloRetryRequestVersion) {
|
|
EnsureTlsSetup();
|
|
// Trigger HelloRetryRequest
|
|
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_tls13_key_share_xtn);
|
|
auto filter = MakeTlsFilter<TlsMessageVersionSetter>(
|
|
server_, kTlsHandshakeHelloRetryRequest, grease_);
|
|
filter->EnableDecryption();
|
|
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
|
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
|
|
class GreaseTestStreamTls123
|
|
: public TlsConnectTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<uint16_t /* version */, uint16_t /* GREASE */>> {
|
|
public:
|
|
GreaseTestStreamTls123()
|
|
: TlsConnectTestBase(ssl_variant_stream, std::get<0>(GetParam())),
|
|
grease_(std::get<1>(GetParam())){};
|
|
|
|
void ConnectExpectIllegalGreaseFail() {
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
// Server expects handshake but receives encrypted alert.
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
} else {
|
|
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
|
}
|
|
ConnectExpectFail();
|
|
}
|
|
|
|
protected:
|
|
uint16_t grease_;
|
|
};
|
|
|
|
// Illegally GREASE TLS12 and TLS13 ServerHello version value
|
|
TEST_P(GreaseTestStreamTls123, GreasedServerHelloVersion) {
|
|
EnsureTlsSetup();
|
|
auto filter = MakeTlsFilter<TlsMessageVersionSetter>(
|
|
server_, kTlsHandshakeServerHello, grease_);
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
filter->EnableDecryption();
|
|
}
|
|
ConnectExpectIllegalGreaseFail();
|
|
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
|
}
|
|
|
|
// Illegally GREASE TLS12 and TLS13 selected CipherSuite value
|
|
TEST_P(GreaseTestStreamTls123, GreasedServerHelloCipherSuite) {
|
|
EnsureTlsSetup();
|
|
auto filter = MakeTlsFilter<SelectedCipherSuiteReplacer>(server_, grease_);
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
filter->EnableDecryption();
|
|
}
|
|
ConnectExpectIllegalGreaseFail();
|
|
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
}
|
|
|
|
class GreaseExtensionTestStreamTls13
|
|
: public TlsConnectStreamTls13,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<uint8_t /* message */, uint16_t /* GREASE */>> {
|
|
public:
|
|
GreaseExtensionTestStreamTls13()
|
|
: TlsConnectStreamTls13(),
|
|
message_(std::get<0>(GetParam())),
|
|
grease_(std::get<1>(GetParam())){};
|
|
|
|
protected:
|
|
uint8_t message_;
|
|
uint16_t grease_;
|
|
};
|
|
|
|
// Illegally GREASE TLS13 Server EncryptedExtensions and Certificate Extensions
|
|
// NSS currently allows offering unkown extensions in HelloRetryRequests!
|
|
TEST_P(GreaseExtensionTestStreamTls13, GreasedServerExtensions) {
|
|
EnsureTlsSetup();
|
|
DataBuffer empty = DataBuffer(1);
|
|
auto filter =
|
|
MakeTlsFilter<TlsExtensionAppender>(server_, message_, grease_, empty);
|
|
filter->EnableDecryption();
|
|
|
|
server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension);
|
|
client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
|
|
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT);
|
|
}
|
|
|
|
// Illegally GREASE TLS12 and TLS13 ServerHello Extensions
|
|
TEST_P(GreaseTestStreamTls123, GreasedServerHelloExtensions) {
|
|
EnsureTlsSetup();
|
|
DataBuffer empty = DataBuffer(1);
|
|
auto filter = MakeTlsFilter<TlsExtensionAppender>(
|
|
server_, kTlsHandshakeServerHello, grease_, empty);
|
|
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
filter->EnableDecryption();
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
} else {
|
|
server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension);
|
|
}
|
|
client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
|
|
}
|
|
|
|
// Illegally GREASE TLS13 Client Certificate Extensions
|
|
// Server ignores injected client extensions and fails on CertificateVerify
|
|
TEST_P(GreaseTestStreamTls13, GreasedClientCertificateExtensions) {
|
|
client_->SetupClientAuth();
|
|
server_->RequestClientAuth(true);
|
|
DataBuffer empty = DataBuffer(1);
|
|
auto filter = MakeTlsFilter<TlsExtensionAppender>(
|
|
client_, kTlsHandshakeCertificate, grease_, empty);
|
|
filter->EnableDecryption();
|
|
|
|
server_->ExpectSendAlert(kTlsAlertDecryptError);
|
|
client_->ExpectReceiveAlert(kTlsAlertDecryptError);
|
|
|
|
// Manually trigger handshake to avoid race conditions
|
|
StartConnect();
|
|
client_->Handshake();
|
|
server_->Handshake();
|
|
client_->Handshake();
|
|
server_->Handshake();
|
|
client_->Handshake();
|
|
|
|
server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
|
|
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
|
|
}
|
|
|
|
TEST_F(TlsConnectStreamTls13, GreaseClientHelloExtensionPermutation) {
|
|
EnsureTlsSetup();
|
|
ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(),
|
|
SSL_ENABLE_CH_EXTENSION_PERMUTATION,
|
|
PR_TRUE) == SECSuccess);
|
|
ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE) ==
|
|
SECSuccess);
|
|
Connect();
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(GreaseTestTls12, GreaseTestStreamTls12,
|
|
::testing::ValuesIn(kTlsGreaseValues));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(GreaseTestTls13, GreaseTestStreamTls13,
|
|
::testing::ValuesIn(kTlsGreaseValues));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
GreaseTestTls123, GreaseTestStreamTls123,
|
|
::testing::Combine(TlsConnectTestBase::kTlsV12Plus,
|
|
::testing::ValuesIn(kTlsGreaseValues)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
GreaseExtensionTest, GreaseExtensionTestStreamTls13,
|
|
testing::Combine(testing::ValuesIn(kTlsGreaseExtensionMessages),
|
|
testing::ValuesIn(kTlsGreaseValues)));
|
|
|
|
} // namespace nss_test
|