зеркало из https://github.com/mozilla/gecko-dev.git
1274 строки
44 KiB
C++
1274 строки
44 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 "ssl.h"
|
|
#include "ssl3prot.h"
|
|
#include "sslerr.h"
|
|
#include "sslproto.h"
|
|
|
|
// This is only to get DTLS_1_3_DRAFT_VERSION
|
|
#include "ssl3prot.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "tls_connect.h"
|
|
#include "tls_filter.h"
|
|
#include "tls_parser.h"
|
|
|
|
namespace nss_test {
|
|
|
|
class TlsExtensionTruncator : public TlsExtensionFilter {
|
|
public:
|
|
TlsExtensionTruncator(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
|
|
size_t length)
|
|
: TlsExtensionFilter(a), extension_(extension), length_(length) {}
|
|
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
|
|
const DataBuffer& input,
|
|
DataBuffer* output) {
|
|
if (extension_type != extension_) {
|
|
return KEEP;
|
|
}
|
|
if (input.len() <= length_) {
|
|
return KEEP;
|
|
}
|
|
|
|
output->Assign(input.data(), length_);
|
|
return CHANGE;
|
|
}
|
|
|
|
private:
|
|
uint16_t extension_;
|
|
size_t length_;
|
|
};
|
|
|
|
class TlsExtensionAppender : public TlsHandshakeFilter {
|
|
public:
|
|
TlsExtensionAppender(const std::shared_ptr<TlsAgent>& a,
|
|
uint8_t handshake_type, uint16_t ext, DataBuffer& data)
|
|
: TlsHandshakeFilter(a, {handshake_type}), extension_(ext), data_(data) {}
|
|
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
|
const DataBuffer& input,
|
|
DataBuffer* output) {
|
|
TlsParser parser(input);
|
|
if (!TlsExtensionFilter::FindExtensions(&parser, header)) {
|
|
return KEEP;
|
|
}
|
|
*output = input;
|
|
|
|
// Increase the length of the extensions block.
|
|
if (!UpdateLength(output, parser.consumed(), 2)) {
|
|
return KEEP;
|
|
}
|
|
|
|
// Extensions in Certificate are nested twice. Increase the size of the
|
|
// certificate list.
|
|
if (header.handshake_type() == kTlsHandshakeCertificate) {
|
|
TlsParser p2(input);
|
|
if (!p2.SkipVariable(1)) {
|
|
ADD_FAILURE();
|
|
return KEEP;
|
|
}
|
|
if (!UpdateLength(output, p2.consumed(), 3)) {
|
|
return KEEP;
|
|
}
|
|
}
|
|
|
|
size_t offset = output->len();
|
|
offset = output->Write(offset, extension_, 2);
|
|
WriteVariable(output, offset, data_, 2);
|
|
|
|
return CHANGE;
|
|
}
|
|
|
|
private:
|
|
bool UpdateLength(DataBuffer* output, size_t offset, size_t size) {
|
|
uint32_t len;
|
|
if (!output->Read(offset, size, &len)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
|
|
len += 4 + data_.len();
|
|
output->Write(offset, len, size);
|
|
return true;
|
|
}
|
|
|
|
const uint16_t extension_;
|
|
const DataBuffer data_;
|
|
};
|
|
|
|
class TlsExtensionTestBase : public TlsConnectTestBase {
|
|
protected:
|
|
TlsExtensionTestBase(SSLProtocolVariant variant, uint16_t version)
|
|
: TlsConnectTestBase(variant, version) {}
|
|
|
|
void ClientHelloErrorTest(std::shared_ptr<PacketFilter> filter,
|
|
uint8_t desc = kTlsAlertDecodeError) {
|
|
client_->SetFilter(filter);
|
|
ConnectExpectAlert(server_, desc);
|
|
}
|
|
|
|
void ServerHelloErrorTest(std::shared_ptr<PacketFilter> filter,
|
|
uint8_t desc = kTlsAlertDecodeError) {
|
|
server_->SetFilter(filter);
|
|
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
|
|
extension->Write(3, namelen, 2);
|
|
extension->Write(5, reinterpret_cast<const uint8_t*>(name), namelen);
|
|
}
|
|
|
|
void HrrThenRemoveExtensionsTest(SSLExtensionType type, PRInt32 client_error,
|
|
PRInt32 server_error) {
|
|
static const std::vector<SSLNamedGroup> client_groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
|
static const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ec_secp384r1};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
EnsureTlsSetup();
|
|
StartConnect();
|
|
client_->Handshake(); // Send ClientHello
|
|
server_->Handshake(); // Send HRR.
|
|
MakeTlsFilter<TlsExtensionDropper>(client_, type);
|
|
Handshake();
|
|
client_->CheckErrorCode(client_error);
|
|
server_->CheckErrorCode(server_error);
|
|
}
|
|
};
|
|
|
|
class TlsExtensionTestDtls : public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<uint16_t> {
|
|
public:
|
|
TlsExtensionTestDtls()
|
|
: TlsExtensionTestBase(ssl_variant_datagram, GetParam()) {}
|
|
};
|
|
|
|
class TlsExtensionTest12Plus : public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t>> {
|
|
public:
|
|
TlsExtensionTest12Plus()
|
|
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
|
|
}
|
|
};
|
|
|
|
class TlsExtensionTest12 : public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t>> {
|
|
public:
|
|
TlsExtensionTest12()
|
|
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
|
|
}
|
|
};
|
|
|
|
class TlsExtensionTest13
|
|
: public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<SSLProtocolVariant> {
|
|
public:
|
|
TlsExtensionTest13()
|
|
: TlsExtensionTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
|
|
|
|
void ConnectWithBogusVersionList(const uint8_t* buf, size_t len) {
|
|
DataBuffer versions_buf(buf, len);
|
|
MakeTlsFilter<TlsExtensionReplacer>(
|
|
client_, ssl_tls13_supported_versions_xtn, versions_buf);
|
|
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);
|
|
versions_buf.Write(index, version, 2);
|
|
MakeTlsFilter<TlsExtensionReplacer>(
|
|
client_, ssl_tls13_supported_versions_xtn, versions_buf);
|
|
ConnectExpectFail();
|
|
}
|
|
};
|
|
|
|
class TlsExtensionTest13Stream : public TlsExtensionTestBase {
|
|
public:
|
|
TlsExtensionTest13Stream()
|
|
: TlsExtensionTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
|
|
};
|
|
|
|
class TlsExtensionTestGeneric : public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t>> {
|
|
public:
|
|
TlsExtensionTestGeneric()
|
|
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
|
|
}
|
|
};
|
|
|
|
class TlsExtensionTestPre13 : public TlsExtensionTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t>> {
|
|
public:
|
|
TlsExtensionTestPre13()
|
|
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
|
|
}
|
|
};
|
|
|
|
TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
|
|
ClientHelloErrorTest(
|
|
std::make_shared<TlsExtensionDamager>(client_, ssl_server_name_xtn, 1));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
|
|
ClientHelloErrorTest(
|
|
std::make_shared<TlsExtensionDamager>(client_, ssl_server_name_xtn, 4));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, TruncateSni) {
|
|
ClientHelloErrorTest(
|
|
std::make_shared<TlsExtensionTruncator>(client_, ssl_server_name_xtn, 7));
|
|
}
|
|
|
|
// A valid extension that appears twice will be reported as unsupported.
|
|
TEST_P(TlsExtensionTestGeneric, RepeatSni) {
|
|
DataBuffer extension;
|
|
InitSimpleSni(&extension);
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionInjector>(
|
|
client_, ssl_server_name_xtn, extension),
|
|
kTlsAlertIllegalParameter);
|
|
}
|
|
|
|
// An SNI entry with zero length is considered invalid (strangely, not if it is
|
|
// the last entry, which is probably a bug).
|
|
TEST_P(TlsExtensionTestGeneric, BadSni) {
|
|
DataBuffer simple;
|
|
InitSimpleSni(&simple);
|
|
DataBuffer extension;
|
|
extension.Allocate(simple.len() + 3);
|
|
extension.Write(0, static_cast<uint32_t>(0), 3);
|
|
extension.Write(3, simple);
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_server_name_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, EmptySni) {
|
|
DataBuffer extension;
|
|
extension.Allocate(2);
|
|
extension.Write(0, static_cast<uint32_t>(0), 2);
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_server_name_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
|
|
EnableAlpn();
|
|
DataBuffer extension;
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_app_layer_protocol_xtn, extension),
|
|
kTlsAlertIllegalParameter);
|
|
}
|
|
|
|
// An empty ALPN isn't considered bad, though it does lead to there being no
|
|
// protocol for the server to select.
|
|
TEST_P(TlsExtensionTestGeneric, EmptyAlpnList) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_app_layer_protocol_xtn, extension),
|
|
kTlsAlertNoApplicationProtocol);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
|
|
EnableAlpn();
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
|
|
client_, ssl_app_layer_protocol_xtn, 1));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
|
|
EnableAlpn();
|
|
// This will leave the length of the second entry, but no value.
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
|
|
client_, ssl_app_layer_protocol_xtn, 5));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, AlpnLengthOverflow) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x01};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
|
|
const uint8_t client_alpn[] = {0x01, 0x61};
|
|
client_->EnableAlpn(client_alpn, sizeof(client_alpn));
|
|
const uint8_t server_alpn[] = {0x02, 0x61, 0x62};
|
|
server_->EnableAlpn(server_alpn, sizeof(server_alpn));
|
|
|
|
ClientHelloErrorTest(nullptr, kTlsAlertNoApplicationProtocol);
|
|
}
|
|
|
|
// Many of these tests fail in TLS 1.3 because the extension is encrypted, which
|
|
// prevents modification of the value from the ServerHello.
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyList) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyName) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x01, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedListTrailingData) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x02, 0x01, 0x61, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedExtraEntry) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x04, 0x01, 0x61, 0x01, 0x62};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedBadListLength) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x99, 0x01, 0x61, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedBadNameLength) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x02, 0x99, 0x61};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, AlpnReturnedUnknownName) {
|
|
EnableAlpn();
|
|
const uint8_t val[] = {0x00, 0x02, 0x01, 0x67};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
server_, ssl_app_layer_protocol_xtn, extension),
|
|
kTlsAlertIllegalParameter);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestDtls, SrtpShort) {
|
|
EnableSrtp();
|
|
ClientHelloErrorTest(
|
|
std::make_shared<TlsExtensionTruncator>(client_, ssl_use_srtp_xtn, 3));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestDtls, SrtpOdd) {
|
|
EnableSrtp();
|
|
const uint8_t val[] = {0x00, 0x01, 0xff, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_use_srtp_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
|
|
const uint8_t val[] = {0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_signature_algorithms_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
|
|
const uint8_t val[] = {0x00, 0x02, 0x04, 0x01, 0x00}; // sha-256, rsa
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_signature_algorithms_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
|
|
const uint8_t val[] = {0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_signature_algorithms_xtn, extension),
|
|
kTlsAlertHandshakeFailure);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsNoOverlap) {
|
|
const uint8_t val[] = {0x00, 0x02, 0xff, 0xff};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_signature_algorithms_xtn, extension),
|
|
kTlsAlertHandshakeFailure);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
|
|
const uint8_t val[] = {0x00, 0x01, 0x04};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_signature_algorithms_xtn, extension));
|
|
}
|
|
|
|
TEST_F(TlsExtensionTest13Stream, SignatureAlgorithmsPrecedingGarbage) {
|
|
// 31 unknown signature algorithms followed by sha-256, rsa
|
|
const uint8_t val[] = {
|
|
0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x01};
|
|
DataBuffer extension(val, sizeof(val));
|
|
MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_signature_algorithms_xtn,
|
|
extension);
|
|
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
|
server_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
|
ConnectExpectFail();
|
|
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
|
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, NoSupportedGroups) {
|
|
ClientHelloErrorTest(
|
|
std::make_shared<TlsExtensionDropper>(client_, ssl_supported_groups_xtn),
|
|
version_ < SSL_LIBRARY_VERSION_TLS_1_3 ? kTlsAlertDecryptError
|
|
: kTlsAlertMissingExtension);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
|
|
const uint8_t val[] = {0x00, 0x01, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_elliptic_curves_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
|
|
const uint8_t val[] = {0x09, 0x99, 0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_elliptic_curves_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
|
|
const uint8_t val[] = {0x00, 0x02, 0x00, 0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_elliptic_curves_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest12, SupportedCurvesDisableX25519) {
|
|
// Disable session resumption.
|
|
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
|
|
|
// Ensure that we can enable its use in the key exchange.
|
|
SECStatus rv =
|
|
NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, NSS_USE_ALG_IN_SSL_KX, 0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
auto capture1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
|
|
Connect();
|
|
|
|
EXPECT_TRUE(capture1->captured());
|
|
const DataBuffer& ext1 = capture1->extension();
|
|
|
|
uint32_t count;
|
|
ASSERT_TRUE(ext1.Read(0, 2, &count));
|
|
|
|
// Whether or not we've seen x25519 offered in this handshake.
|
|
bool seen1_x25519 = false;
|
|
for (size_t offset = 2; offset <= count; offset++) {
|
|
uint32_t val;
|
|
ASSERT_TRUE(ext1.Read(offset, 2, &val));
|
|
if (val == ssl_grp_ec_curve25519) {
|
|
seen1_x25519 = true;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT_TRUE(seen1_x25519);
|
|
|
|
// Ensure that we can disable its use in the key exchange.
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, 0, NSS_USE_ALG_IN_SSL_KX);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
// Clean up after the last run.
|
|
Reset();
|
|
auto capture2 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
|
|
Connect();
|
|
|
|
EXPECT_TRUE(capture2->captured());
|
|
const DataBuffer& ext2 = capture2->extension();
|
|
|
|
ASSERT_TRUE(ext2.Read(0, 2, &count));
|
|
|
|
// Whether or not we've seen x25519 offered in this handshake.
|
|
bool seen2_x25519 = false;
|
|
for (size_t offset = 2; offset <= count; offset++) {
|
|
uint32_t val;
|
|
ASSERT_TRUE(ext2.Read(offset, 2, &val));
|
|
|
|
if (val == ssl_grp_ec_curve25519) {
|
|
seen2_x25519 = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT_FALSE(seen2_x25519);
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, SupportedPointsEmpty) {
|
|
const uint8_t val[] = {0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_ec_point_formats_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, SupportedPointsBadLength) {
|
|
const uint8_t val[] = {0x99, 0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_ec_point_formats_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, SupportedPointsTrailingData) {
|
|
const uint8_t val[] = {0x01, 0x00, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_ec_point_formats_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, RenegotiationInfoBadLength) {
|
|
const uint8_t val[] = {0x99};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_renegotiation_info_xtn, extension));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTestPre13, RenegotiationInfoMismatch) {
|
|
const uint8_t val[] = {0x01, 0x00};
|
|
DataBuffer extension(val, sizeof(val));
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_renegotiation_info_xtn, extension));
|
|
}
|
|
|
|
// The extension has to contain a length.
|
|
TEST_P(TlsExtensionTestPre13, RenegotiationInfoExtensionEmpty) {
|
|
DataBuffer extension;
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
|
client_, ssl_renegotiation_info_xtn, extension));
|
|
}
|
|
|
|
// This only works on TLS 1.2, since it relies on static RSA; otherwise libssl
|
|
// picks the wrong cipher suite.
|
|
TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
|
|
const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_rsae_sha512,
|
|
ssl_sig_rsa_pss_rsae_sha384};
|
|
|
|
auto capture =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
|
client_->SetSignatureSchemes(schemes, PR_ARRAY_SIZE(schemes));
|
|
EnableOnlyStaticRsaCiphers();
|
|
Connect();
|
|
|
|
const DataBuffer& ext = capture->extension();
|
|
EXPECT_EQ(2 + PR_ARRAY_SIZE(schemes) * 2, ext.len());
|
|
for (size_t i = 0, cursor = 2;
|
|
i < PR_ARRAY_SIZE(schemes) && cursor < ext.len(); ++i) {
|
|
uint32_t v = 0;
|
|
EXPECT_TRUE(ext.Read(cursor, 2, &v));
|
|
cursor += 2;
|
|
EXPECT_EQ(schemes[i], static_cast<SSLSignatureScheme>(v));
|
|
}
|
|
}
|
|
|
|
// This only works on TLS 1.2, since it relies on DSA.
|
|
TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
|
|
const std::vector<SSLSignatureScheme> schemes = {
|
|
ssl_sig_dsa_sha1, ssl_sig_dsa_sha256, ssl_sig_dsa_sha384,
|
|
ssl_sig_dsa_sha512, ssl_sig_rsa_pss_rsae_sha256};
|
|
|
|
// Connect with DSA enabled by policy.
|
|
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
|
|
NSS_USE_ALG_IN_SSL_KX, 0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
Reset(TlsAgent::kServerDsa);
|
|
auto capture1 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
|
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
Connect();
|
|
|
|
// Check if all the signature algorithms are advertised.
|
|
EXPECT_TRUE(capture1->captured());
|
|
const DataBuffer& ext1 = capture1->extension();
|
|
EXPECT_EQ(2U + 2U * schemes.size(), ext1.len());
|
|
|
|
// Connect with DSA disabled by policy.
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, 0,
|
|
NSS_USE_ALG_IN_SSL_KX);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
Reset(TlsAgent::kServerDsa);
|
|
auto capture2 =
|
|
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
|
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
|
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
|
|
// Check if no DSA algorithms are advertised.
|
|
EXPECT_TRUE(capture2->captured());
|
|
const DataBuffer& ext2 = capture2->extension();
|
|
EXPECT_EQ(2U + 2U, ext2.len());
|
|
uint32_t v = 0;
|
|
EXPECT_TRUE(ext2.Read(2, 2, &v));
|
|
EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, v);
|
|
}
|
|
|
|
// Temporary test to verify that we choke on an empty ClientKeyShare.
|
|
// This test will fail when we implement HelloRetryRequest.
|
|
TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
|
|
ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
|
|
client_, ssl_tls13_key_share_xtn, 2),
|
|
kTlsAlertHandshakeFailure);
|
|
}
|
|
|
|
// 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();
|
|
MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_key_share_xtn);
|
|
client_->ExpectSendAlert(kTlsAlertMissingExtension);
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
ConnectExpectFail();
|
|
EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
|
|
EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
|
|
}
|
|
|
|
TEST_F(TlsExtensionTest13Stream, WrongServerKeyShare) {
|
|
const uint16_t wrong_group = ssl_grp_ec_secp384r1;
|
|
|
|
static const uint8_t key_share[] = {
|
|
wrong_group >> 8,
|
|
wrong_group & 0xff, // Group we didn't offer.
|
|
0x00,
|
|
0x02, // length = 2
|
|
0x01,
|
|
0x02};
|
|
DataBuffer buf(key_share, sizeof(key_share));
|
|
EnsureTlsSetup();
|
|
MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_key_share_xtn, buf);
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
ConnectExpectFail();
|
|
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
|
|
EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
|
|
}
|
|
|
|
TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
|
|
const uint16_t wrong_group = 0xffff;
|
|
|
|
static const uint8_t key_share[] = {
|
|
wrong_group >> 8,
|
|
wrong_group & 0xff, // Group we didn't offer.
|
|
0x00,
|
|
0x02, // length = 2
|
|
0x01,
|
|
0x02};
|
|
DataBuffer buf(key_share, sizeof(key_share));
|
|
EnsureTlsSetup();
|
|
MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_key_share_xtn, buf);
|
|
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
ConnectExpectFail();
|
|
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
|
|
EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
|
|
}
|
|
|
|
TEST_F(TlsExtensionTest13Stream, AddServerSignatureAlgorithmsOnResumption) {
|
|
SetupForResume();
|
|
DataBuffer empty;
|
|
MakeTlsFilter<TlsExtensionInjector>(server_, ssl_signature_algorithms_xtn,
|
|
empty);
|
|
client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
ConnectExpectFail();
|
|
EXPECT_EQ(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, client_->error_code());
|
|
EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
|
|
}
|
|
|
|
struct PskIdentity {
|
|
DataBuffer identity;
|
|
uint32_t obfuscated_ticket_age;
|
|
};
|
|
|
|
class TlsPreSharedKeyReplacer;
|
|
|
|
typedef std::function<void(TlsPreSharedKeyReplacer*)>
|
|
TlsPreSharedKeyReplacerFunc;
|
|
|
|
class TlsPreSharedKeyReplacer : public TlsExtensionFilter {
|
|
public:
|
|
TlsPreSharedKeyReplacer(const std::shared_ptr<TlsAgent>& a,
|
|
TlsPreSharedKeyReplacerFunc function)
|
|
: TlsExtensionFilter(a), identities_(), binders_(), function_(function) {}
|
|
|
|
static size_t CopyAndMaybeReplace(TlsParser* parser, size_t size,
|
|
const std::unique_ptr<DataBuffer>& replace,
|
|
size_t index, DataBuffer* output) {
|
|
DataBuffer tmp;
|
|
bool ret = parser->ReadVariable(&tmp, size);
|
|
EXPECT_EQ(true, ret);
|
|
if (!ret) return 0;
|
|
if (replace) {
|
|
tmp = *replace;
|
|
}
|
|
|
|
return WriteVariable(output, index, tmp, size);
|
|
}
|
|
|
|
PacketFilter::Action FilterExtension(uint16_t extension_type,
|
|
const DataBuffer& input,
|
|
DataBuffer* output) {
|
|
if (extension_type != ssl_tls13_pre_shared_key_xtn) {
|
|
return KEEP;
|
|
}
|
|
|
|
if (!Decode(input)) {
|
|
return KEEP;
|
|
}
|
|
|
|
// Call the function.
|
|
function_(this);
|
|
|
|
Encode(output);
|
|
|
|
return CHANGE;
|
|
}
|
|
|
|
std::vector<PskIdentity> identities_;
|
|
std::vector<DataBuffer> binders_;
|
|
|
|
private:
|
|
bool Decode(const DataBuffer& input) {
|
|
std::unique_ptr<TlsParser> parser(new TlsParser(input));
|
|
DataBuffer identities;
|
|
|
|
if (!parser->ReadVariable(&identities, 2)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
|
|
DataBuffer binders;
|
|
if (!parser->ReadVariable(&binders, 2)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
EXPECT_EQ(0UL, parser->remaining());
|
|
|
|
// Now parse the inner sections.
|
|
parser.reset(new TlsParser(identities));
|
|
while (parser->remaining()) {
|
|
PskIdentity identity;
|
|
|
|
if (!parser->ReadVariable(&identity.identity, 2)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
|
|
if (!parser->Read(&identity.obfuscated_ticket_age, 4)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
|
|
identities_.push_back(identity);
|
|
}
|
|
|
|
parser.reset(new TlsParser(binders));
|
|
while (parser->remaining()) {
|
|
DataBuffer binder;
|
|
|
|
if (!parser->ReadVariable(&binder, 1)) {
|
|
ADD_FAILURE();
|
|
return false;
|
|
}
|
|
|
|
binders_.push_back(binder);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Encode(DataBuffer* output) {
|
|
DataBuffer identities;
|
|
size_t index = 0;
|
|
for (auto id : identities_) {
|
|
index = WriteVariable(&identities, index, id.identity, 2);
|
|
index = identities.Write(index, id.obfuscated_ticket_age, 4);
|
|
}
|
|
|
|
DataBuffer binders;
|
|
index = 0;
|
|
for (auto binder : binders_) {
|
|
index = WriteVariable(&binders, index, binder, 1);
|
|
}
|
|
|
|
output->Truncate(0);
|
|
index = 0;
|
|
index = WriteVariable(output, index, identities, 2);
|
|
index = WriteVariable(output, index, binders, 2);
|
|
}
|
|
|
|
TlsPreSharedKeyReplacerFunc function_;
|
|
};
|
|
|
|
TEST_F(TlsExtensionTest13Stream, ResumeEmptyPskLabel) {
|
|
SetupForResume();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->identities_[0].identity.Truncate(0);
|
|
});
|
|
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();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
|
|
});
|
|
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();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->binders_[0].Write(r->binders_[0].len(), 0xff, 1);
|
|
});
|
|
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();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) { r->binders_[0].Truncate(31); });
|
|
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();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->identities_.push_back(r->identities_[0]);
|
|
r->binders_.push_back(r->binders_[0]);
|
|
});
|
|
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();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->identities_.push_back(r->identities_[0]);
|
|
});
|
|
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
|
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
|
}
|
|
|
|
TEST_F(TlsExtensionTest13Stream, ResumeOneIdentityTwoBinders) {
|
|
SetupForResume();
|
|
|
|
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
|
client_, [](TlsPreSharedKeyReplacer* r) {
|
|
r->binders_.push_back(r->binders_[0]);
|
|
});
|
|
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);
|
|
// Inject an unused extension after the PSK extension.
|
|
MakeTlsFilter<TlsExtensionAppender>(client_, kTlsHandshakeClientHello, 0xffff,
|
|
empty);
|
|
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;
|
|
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);
|
|
}
|
|
|
|
// 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));
|
|
MakeTlsFilter<TlsExtensionReplacer>(
|
|
client_, 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 = MakeTlsFilter<TlsExtensionCapture>(
|
|
client_, ssl_tls13_psk_key_exchange_modes_xtn);
|
|
Connect();
|
|
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_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
|
|
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);
|
|
// The downgrade check is disabled in DTLS 1.3, so all that happens when we
|
|
// tamper with the supported versions is that the Finished check fails.
|
|
#ifdef DTLS_1_3_DRAFT_VERSION
|
|
if (variant_ == ssl_variant_datagram) {
|
|
ExpectAlert(server_, kTlsAlertDecryptError);
|
|
} else
|
|
#endif
|
|
{
|
|
ExpectAlert(client_, kTlsAlertIllegalParameter);
|
|
}
|
|
ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
|
|
#ifdef DTLS_1_3_DRAFT_VERSION
|
|
if (variant_ == ssl_variant_datagram) {
|
|
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
|
|
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
|
} else
|
|
#endif
|
|
{
|
|
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
|
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
TEST_P(TlsExtensionTest13, OddVersionList) {
|
|
static const uint8_t ext[] = {0x00, 0x01, 0x00};
|
|
ConnectWithBogusVersionList(ext, sizeof(ext));
|
|
}
|
|
|
|
// TODO: this only tests extensions in server messages. The client can extend
|
|
// Certificate messages, which is not checked here.
|
|
class TlsBogusExtensionTest : public TlsConnectTestBase,
|
|
public ::testing::WithParamInterface<
|
|
std::tuple<SSLProtocolVariant, uint16_t>> {
|
|
public:
|
|
TlsBogusExtensionTest()
|
|
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
|
|
|
|
protected:
|
|
virtual void ConnectAndFail(uint8_t message) = 0;
|
|
|
|
void AddFilter(uint8_t message, uint16_t extension) {
|
|
static uint8_t empty_buf[1] = {0};
|
|
DataBuffer empty(empty_buf, 0);
|
|
auto filter =
|
|
MakeTlsFilter<TlsExtensionAppender>(server_, message, extension, empty);
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
filter->EnableDecryption();
|
|
}
|
|
}
|
|
|
|
void Run(uint8_t message, uint16_t extension = 0xff) {
|
|
EnsureTlsSetup();
|
|
AddFilter(message, extension);
|
|
ConnectAndFail(message);
|
|
}
|
|
};
|
|
|
|
class TlsBogusExtensionTestPre13 : public TlsBogusExtensionTest {
|
|
protected:
|
|
void ConnectAndFail(uint8_t) override {
|
|
ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
|
|
}
|
|
};
|
|
|
|
class TlsBogusExtensionTest13 : public TlsBogusExtensionTest {
|
|
protected:
|
|
void ConnectAndFail(uint8_t message) override {
|
|
if (message != kTlsHandshakeServerHello) {
|
|
ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
|
|
return;
|
|
}
|
|
|
|
FailWithAlert(kTlsAlertUnsupportedExtension);
|
|
}
|
|
|
|
void FailWithAlert(uint8_t alert) {
|
|
StartConnect();
|
|
client_->Handshake(); // ClientHello
|
|
server_->Handshake(); // ServerHello
|
|
|
|
client_->ExpectSendAlert(alert);
|
|
client_->Handshake();
|
|
if (variant_ == ssl_variant_stream) {
|
|
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
|
}
|
|
server_->Handshake();
|
|
}
|
|
};
|
|
|
|
TEST_P(TlsBogusExtensionTestPre13, AddBogusExtensionServerHello) {
|
|
Run(kTlsHandshakeServerHello);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionServerHello) {
|
|
Run(kTlsHandshakeServerHello);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionEncryptedExtensions) {
|
|
Run(kTlsHandshakeEncryptedExtensions);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificate) {
|
|
Run(kTlsHandshakeCertificate);
|
|
}
|
|
|
|
// It's perfectly valid to set unknown extensions in CertificateRequest.
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificateRequest) {
|
|
server_->RequestClientAuth(false);
|
|
AddFilter(kTlsHandshakeCertificateRequest, 0xff);
|
|
ConnectExpectAlert(client_, kTlsAlertDecryptError);
|
|
client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
|
|
static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
|
|
server_->ConfigNamedGroups(groups);
|
|
|
|
Run(kTlsHandshakeHelloRetryRequest);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddVersionExtensionEncryptedExtensions) {
|
|
Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_supported_versions_xtn);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificate) {
|
|
Run(kTlsHandshakeCertificate, ssl_tls13_supported_versions_xtn);
|
|
}
|
|
|
|
TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificateRequest) {
|
|
server_->RequestClientAuth(false);
|
|
Run(kTlsHandshakeCertificateRequest, ssl_tls13_supported_versions_xtn);
|
|
}
|
|
|
|
// NewSessionTicket allows unknown extensions AND it isn't protected by the
|
|
// Finished. So adding an unknown extension doesn't cause an error.
|
|
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionNewSessionTicket) {
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
|
|
AddFilter(kTlsHandshakeNewSessionTicket, 0xff);
|
|
Connect();
|
|
SendReceive();
|
|
CheckKeys();
|
|
|
|
Reset();
|
|
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
|
ExpectResumption(RESUME_TICKET);
|
|
Connect();
|
|
SendReceive();
|
|
}
|
|
|
|
TEST_P(TlsConnectStream, IncludePadding) {
|
|
EnsureTlsSetup();
|
|
|
|
// This needs to be long enough to push a TLS 1.0 ClientHello over 255, but
|
|
// short enough not to push a TLS 1.3 ClientHello over 511.
|
|
static const char* long_name =
|
|
"chickenchickenchickenchickenchickenchickenchickenchicken."
|
|
"chickenchickenchickenchickenchickenchickenchickenchicken."
|
|
"chickenchickenchickenchickenchicken.";
|
|
SECStatus rv = SSL_SetURL(client_->ssl_fd(), long_name);
|
|
EXPECT_EQ(SECSuccess, rv);
|
|
|
|
auto capture = MakeTlsFilter<TlsExtensionCapture>(client_, ssl_padding_xtn);
|
|
client_->StartConnect();
|
|
client_->Handshake();
|
|
EXPECT_TRUE(capture->captured());
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ExtensionStream, TlsExtensionTestGeneric,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
|
TlsConnectTestBase::kTlsVAll));
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ExtensionDatagram, TlsExtensionTestGeneric,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
|
TlsConnectTestBase::kTlsV11Plus));
|
|
INSTANTIATE_TEST_CASE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
|
|
TlsConnectTestBase::kTlsV11Plus);
|
|
|
|
INSTANTIATE_TEST_CASE_P(ExtensionTls12, TlsExtensionTest12,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV12));
|
|
|
|
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV12Plus));
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ExtensionPre13Stream, TlsExtensionTestPre13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
|
TlsConnectTestBase::kTlsV10ToV12));
|
|
INSTANTIATE_TEST_CASE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV11V12));
|
|
|
|
INSTANTIATE_TEST_CASE_P(ExtensionTls13, TlsExtensionTest13,
|
|
TlsConnectTestBase::kTlsVariantsAll);
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
BogusExtensionStream, TlsBogusExtensionTestPre13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
|
TlsConnectTestBase::kTlsV10ToV12));
|
|
INSTANTIATE_TEST_CASE_P(
|
|
BogusExtensionDatagram, TlsBogusExtensionTestPre13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
|
TlsConnectTestBase::kTlsV11V12));
|
|
|
|
INSTANTIATE_TEST_CASE_P(BogusExtension13, TlsBogusExtensionTest13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV13));
|
|
|
|
} // namespace nss_test
|