|
Packit |
40b132 |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
Packit |
40b132 |
/* vim: set ts=2 et sw=2 tw=80: */
|
|
Packit |
40b132 |
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
40b132 |
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
Packit |
40b132 |
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
#include "ssl.h"
|
|
Packit |
40b132 |
#include "sslproto.h"
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
#include <memory>
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
#include "tls_parser.h"
|
|
Packit |
40b132 |
#include "tls_filter.h"
|
|
Packit |
40b132 |
#include "tls_connect.h"
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
namespace nss_test {
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionFilter : public TlsHandshakeFilter {
|
|
Packit |
40b132 |
protected:
|
|
Packit |
40b132 |
virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
if (handshake_type == kTlsHandshakeClientHello) {
|
|
Packit |
40b132 |
TlsParser parser(input);
|
|
Packit |
40b132 |
if (!FindClientHelloExtensions(parser, version)) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return FilterExtensions(parser, input, output);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (handshake_type == kTlsHandshakeServerHello) {
|
|
Packit |
40b132 |
TlsParser parser(input);
|
|
Packit |
40b132 |
if (!FindServerHelloExtensions(parser, version)) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return FilterExtensions(parser, input, output);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
virtual bool FilterExtension(uint16_t extension_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) = 0;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
static bool FindClientHelloExtensions(TlsParser& parser, uint16_t version) {
|
|
Packit |
40b132 |
if (!parser.Skip(2 + 32)) { // version + random
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (!parser.SkipVariable(1)) { // session ID
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (IsDtls(version) && !parser.SkipVariable(1)) { // DTLS cookie
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (!parser.SkipVariable(2)) { // cipher suites
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (!parser.SkipVariable(1)) { // compression methods
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
static bool FindServerHelloExtensions(TlsParser& parser, uint16_t version) {
|
|
Packit |
40b132 |
if (!parser.Skip(2 + 32)) { // version + random
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (!parser.SkipVariable(1)) { // session ID
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (!parser.Skip(2)) { // cipher suite
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (NormalizeTlsVersion(version) <= SSL_LIBRARY_VERSION_TLS_1_2) {
|
|
Packit |
40b132 |
if (!parser.Skip(1)) { // compression method
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
private:
|
|
Packit |
40b132 |
bool FilterExtensions(TlsParser& parser,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
size_t length_offset = parser.consumed();
|
|
Packit |
40b132 |
uint32_t all_extensions;
|
|
Packit |
40b132 |
if (!parser.Read(&all_extensions, 2)) {
|
|
Packit |
40b132 |
return false; // no extensions, odd but OK
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (all_extensions != parser.remaining()) {
|
|
Packit |
40b132 |
return false; // malformed
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
bool changed = false;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// Write out the start of the message.
|
|
Packit |
40b132 |
output->Allocate(input.len());
|
|
Packit |
40b132 |
output->Write(0, input.data(), parser.consumed());
|
|
Packit |
40b132 |
size_t output_offset = parser.consumed();
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
while (parser.remaining()) {
|
|
Packit |
40b132 |
uint32_t extension_type;
|
|
Packit |
40b132 |
if (!parser.Read(&extension_type, 2)) {
|
|
Packit |
40b132 |
return false; // malformed
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// Copy extension type.
|
|
Packit |
40b132 |
output->Write(output_offset, extension_type, 2);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
DataBuffer extension;
|
|
Packit |
40b132 |
if (!parser.ReadVariable(&extension, 2)) {
|
|
Packit |
40b132 |
return false; // malformed
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
output_offset = ApplyFilter(static_cast<uint16_t>(extension_type), extension,
|
|
Packit |
40b132 |
output, output_offset + 2, &changed);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
output->Truncate(output_offset);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (changed) {
|
|
Packit |
40b132 |
size_t newlen = output->len() - length_offset - 2;
|
|
Packit |
40b132 |
if (newlen >= 0x10000) {
|
|
Packit |
40b132 |
return false; // bad: size increased too much
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
output->Write(length_offset, newlen, 2);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
return changed;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
size_t ApplyFilter(uint16_t extension_type, const DataBuffer& extension,
|
|
Packit |
40b132 |
DataBuffer* output, size_t offset, bool* changed) {
|
|
Packit |
40b132 |
const DataBuffer* source = &extension;
|
|
Packit |
40b132 |
DataBuffer filtered;
|
|
Packit |
40b132 |
if (FilterExtension(extension_type, extension, &filtered) &&
|
|
Packit |
40b132 |
filtered.len() < 0x10000) {
|
|
Packit |
40b132 |
*changed = true;
|
|
Packit |
40b132 |
std::cerr << "extension old: " << extension << std::endl;
|
|
Packit |
40b132 |
std::cerr << "extension new: " << filtered << std::endl;
|
|
Packit |
40b132 |
source = &filtered;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
output->Write(offset, source->len(), 2);
|
|
Packit |
40b132 |
output->Write(offset + 2, *source);
|
|
Packit |
40b132 |
return offset + 2 + source->len();
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionTruncator : public TlsExtensionFilter {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionTruncator(uint16_t extension, size_t length)
|
|
Packit |
40b132 |
: extension_(extension), length_(length) {}
|
|
Packit |
40b132 |
virtual bool FilterExtension(uint16_t extension_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
if (extension_type != extension_) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (input.len() <= length_) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
output->Assign(input.data(), length_);
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
private:
|
|
Packit |
40b132 |
uint16_t extension_;
|
|
Packit |
40b132 |
size_t length_;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionDamager : public TlsExtensionFilter {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionDamager(uint16_t extension, size_t index)
|
|
Packit |
40b132 |
: extension_(extension), index_(index) {}
|
|
Packit |
40b132 |
virtual bool FilterExtension(uint16_t extension_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
if (extension_type != extension_) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
*output = input;
|
|
Packit |
40b132 |
output->data()[index_] += 73; // Increment selected for maximum damage
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
private:
|
|
Packit |
40b132 |
uint16_t extension_;
|
|
Packit |
40b132 |
size_t index_;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionReplacer : public TlsExtensionFilter {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionReplacer(uint16_t extension, const DataBuffer& data)
|
|
Packit |
40b132 |
: extension_(extension), data_(data) {}
|
|
Packit |
40b132 |
virtual bool FilterExtension(uint16_t extension_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
if (extension_type != extension_) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
*output = data_;
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
private:
|
|
Packit |
40b132 |
uint16_t extension_;
|
|
Packit |
40b132 |
DataBuffer data_;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionInjector : public TlsHandshakeFilter {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionInjector(uint16_t ext, DataBuffer& data)
|
|
Packit |
40b132 |
: extension_(ext), data_(data) {}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
|
|
Packit |
40b132 |
const DataBuffer& input, DataBuffer* output) {
|
|
Packit |
40b132 |
size_t offset;
|
|
Packit |
40b132 |
if (handshake_type == kTlsHandshakeClientHello) {
|
|
Packit |
40b132 |
TlsParser parser(input);
|
|
Packit |
40b132 |
if (!TlsExtensionFilter::FindClientHelloExtensions(parser, version)) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
offset = parser.consumed();
|
|
Packit |
40b132 |
} else if (handshake_type == kTlsHandshakeServerHello) {
|
|
Packit |
40b132 |
TlsParser parser(input);
|
|
Packit |
40b132 |
if (!TlsExtensionFilter::FindServerHelloExtensions(parser, version)) {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
offset = parser.consumed();
|
|
Packit |
40b132 |
} else {
|
|
Packit |
40b132 |
return false;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
*output = input;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
std::cerr << "Pre:" << input << std::endl;
|
|
Packit |
40b132 |
std::cerr << "Lof:" << offset << std::endl;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// Increase the size of the extensions.
|
|
Packit |
40b132 |
uint16_t* len_addr = reinterpret_cast<uint16_t*>(output->data() + offset);
|
|
Packit |
40b132 |
std::cerr << "L-p:" << ntohs(*len_addr) << std::endl;
|
|
Packit |
40b132 |
*len_addr = htons(ntohs(*len_addr) + data_.len() + 4);
|
|
Packit |
40b132 |
std::cerr << "L-i:" << ntohs(*len_addr) << std::endl;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// Insert the extension type and length.
|
|
Packit |
40b132 |
DataBuffer type_length;
|
|
Packit |
40b132 |
type_length.Allocate(4);
|
|
Packit |
40b132 |
type_length.Write(0, extension_, 2);
|
|
Packit |
40b132 |
type_length.Write(2, data_.len(), 2);
|
|
Packit |
40b132 |
output->Splice(type_length, offset + 2);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// Insert the payload.
|
|
Packit |
40b132 |
output->Splice(data_, offset + 6);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
std::cerr << "Aft:" << *output << std::endl;
|
|
Packit |
40b132 |
return true;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
private:
|
|
Packit |
40b132 |
uint16_t extension_;
|
|
Packit |
40b132 |
DataBuffer data_;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionTestBase : public TlsConnectTestBase {
|
|
Packit |
40b132 |
protected:
|
|
Packit |
40b132 |
TlsExtensionTestBase(Mode mode, uint16_t version)
|
|
Packit |
40b132 |
: TlsConnectTestBase(mode, version) {}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
void ClientHelloErrorTest(PacketFilter* filter,
|
|
Packit |
40b132 |
uint8_t alert = kTlsAlertDecodeError) {
|
|
Packit |
40b132 |
auto alert_recorder = new TlsAlertRecorder();
|
|
Packit |
40b132 |
server_->SetPacketFilter(alert_recorder);
|
|
Packit |
40b132 |
if (filter) {
|
|
Packit |
40b132 |
client_->SetPacketFilter(filter);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
ConnectExpectFail();
|
|
Packit |
40b132 |
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
|
|
Packit |
40b132 |
EXPECT_EQ(alert, alert_recorder->description());
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
void ServerHelloErrorTest(PacketFilter* filter,
|
|
Packit |
40b132 |
uint8_t alert = kTlsAlertDecodeError) {
|
|
Packit |
40b132 |
auto alert_recorder = new TlsAlertRecorder();
|
|
Packit |
40b132 |
client_->SetPacketFilter(alert_recorder);
|
|
Packit |
40b132 |
if (filter) {
|
|
Packit |
40b132 |
server_->SetPacketFilter(filter);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
ConnectExpectFail();
|
|
Packit |
40b132 |
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
|
|
Packit |
40b132 |
EXPECT_EQ(alert, alert_recorder->description());
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
static void InitSimpleSni(DataBuffer* extension) {
|
|
Packit |
40b132 |
const char* name = "host.name";
|
|
Packit |
40b132 |
const size_t namelen = PL_strlen(name);
|
|
Packit |
40b132 |
extension->Allocate(namelen + 5);
|
|
Packit |
40b132 |
extension->Write(0, namelen + 3, 2);
|
|
Packit |
40b132 |
extension->Write(2, static_cast<uint32_t>(0), 1); // 0 == hostname
|
|
Packit |
40b132 |
extension->Write(3, namelen, 2);
|
|
Packit |
40b132 |
extension->Write(5, reinterpret_cast<const uint8_t*>(name), namelen);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionTestDtls
|
|
Packit |
40b132 |
: public TlsExtensionTestBase,
|
|
Packit |
40b132 |
public ::testing::WithParamInterface<uint16_t> {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionTestDtls() : TlsExtensionTestBase(DGRAM, GetParam()) {}
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionTest12Plus
|
|
Packit |
40b132 |
: public TlsExtensionTestBase,
|
|
Packit |
40b132 |
public ::testing::WithParamInterface<std::string> {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionTest12Plus()
|
|
Packit |
40b132 |
: TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
|
|
Packit |
40b132 |
SSL_LIBRARY_VERSION_TLS_1_2) {}
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
class TlsExtensionTestGeneric
|
|
Packit |
40b132 |
: public TlsExtensionTestBase,
|
|
Packit |
40b132 |
public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
|
|
Packit |
40b132 |
public:
|
|
Packit |
40b132 |
TlsExtensionTestGeneric()
|
|
Packit |
40b132 |
: TlsExtensionTestBase(TlsConnectTestBase::ToMode((std::get<0>(GetParam()))),
|
|
Packit |
40b132 |
std::get<1>(GetParam())) {}
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 1));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 4));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, TruncateSni) {
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_server_name_xtn, 7));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// A valid extension that appears twice will be reported as unsupported.
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, RepeatSni) {
|
|
Packit |
40b132 |
DataBuffer extension;
|
|
Packit |
40b132 |
InitSimpleSni(&extension);
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionInjector(ssl_server_name_xtn, extension),
|
|
Packit |
40b132 |
kTlsAlertIllegalParameter);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// An SNI entry with zero length is considered invalid (strangely, not if it is
|
|
Packit |
40b132 |
// the last entry, which is probably a bug).
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, BadSni) {
|
|
Packit |
40b132 |
DataBuffer simple;
|
|
Packit |
40b132 |
InitSimpleSni(&simple;;
|
|
Packit |
40b132 |
DataBuffer extension;
|
|
Packit |
40b132 |
extension.Allocate(simple.len() + 3);
|
|
Packit |
40b132 |
extension.Write(0, static_cast<uint32_t>(0), 3);
|
|
Packit |
40b132 |
extension.Write(3, simple);
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_server_name_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
DataBuffer extension;
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
|
|
Packit |
40b132 |
kTlsAlertIllegalParameter);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// An empty ALPN isn't considered bad, though it does lead to there being no
|
|
Packit |
40b132 |
// protocol for the server to select.
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, EmptyAlpnList) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
|
|
Packit |
40b132 |
kTlsAlertNoApplicationProtocol);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 1));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
// This will leave the length of the second entry, but no value.
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 5));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x01, 0x61, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
|
|
Packit |
40b132 |
const uint8_t client_alpn[] = { 0x01, 0x61 };
|
|
Packit |
40b132 |
client_->EnableAlpn(client_alpn, sizeof(client_alpn));
|
|
Packit |
40b132 |
const uint8_t server_alpn[] = { 0x02, 0x61, 0x62 };
|
|
Packit |
40b132 |
server_->EnableAlpn(server_alpn, sizeof(server_alpn));
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
ClientHelloErrorTest(nullptr, kTlsAlertNoApplicationProtocol);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyList) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyName) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x01, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedListTrailingData) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x02, 0x01, 0x61, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedExtraEntry) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x04, 0x01, 0x61, 0x01, 0x62 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadListLength) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x99, 0x01, 0x61, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadNameLength) {
|
|
Packit |
40b132 |
EnableAlpn();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x02, 0x99, 0x61 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestDtls, SrtpShort) {
|
|
Packit |
40b132 |
EnableSrtp();
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_use_srtp_xtn, 3));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestDtls, SrtpOdd) {
|
|
Packit |
40b132 |
EnableSrtp();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x01, 0xff, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_use_srtp_xtn, extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x02, 0x04, 0x01, 0x00 }; // sha-256, rsa
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x01, 0x04 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// The extension handling ignores unsupported hashes, so breaking that has no
|
|
Packit |
40b132 |
// effect on success rates. However, ssl3_SendServerKeyExchange catches an
|
|
Packit |
40b132 |
// unsupported signature algorithm.
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// This actually fails with a decryption error (fatal alert 51). That's a bad
|
|
Packit |
40b132 |
// to fail, since any tampering with the handshake will trigger that alert when
|
|
Packit |
40b132 |
// verifying the Finished message. Thus, this test is disabled until this error
|
|
Packit |
40b132 |
// is turned into an alert.
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTest12Plus, DISABLED_SignatureAlgorithmsSigUnsupported) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x02, 0x04, 0x99 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x01, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x09, 0x99, 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00, 0x02, 0x00, 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedPointsEmpty) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedPointsBadLength) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x99, 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, SupportedPointsTrailingData) {
|
|
Packit |
40b132 |
EnableSomeEcdheCiphers();
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x01, 0x00, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoBadLength) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x99 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoMismatch) {
|
|
Packit |
40b132 |
const uint8_t val[] = { 0x01, 0x00 };
|
|
Packit |
40b132 |
DataBuffer extension(val, sizeof(val));
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
// The extension has to contain a length.
|
|
Packit |
40b132 |
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoExtensionEmpty) {
|
|
Packit |
40b132 |
DataBuffer extension;
|
|
Packit |
40b132 |
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
|
|
Packit |
40b132 |
extension));
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
|
|
Packit |
40b132 |
::testing::Combine(
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsModesStream,
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsV10));
|
|
Packit |
40b132 |
INSTANTIATE_TEST_CASE_P(ExtensionVariants, TlsExtensionTestGeneric,
|
|
Packit |
40b132 |
::testing::Combine(
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsModesAll,
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsV11V12));
|
|
Packit |
40b132 |
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsModesAll);
|
|
Packit |
40b132 |
INSTANTIATE_TEST_CASE_P(ExtensionDgram, TlsExtensionTestDtls,
|
|
Packit |
40b132 |
TlsConnectTestBase::kTlsV11V12);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
} // namespace nspr_test
|