Bug 1144055 - Upgrade Firefox 39 to use NSS 3.18.1, land NSS_3_18_1_BETA1, r=nss-confcall

This commit is contained in:
Kai Engert 2015-03-26 20:39:25 +01:00
parent 41e0657ba2
commit e2f12bfec6
22 changed files with 1042 additions and 341 deletions

View File

@ -1 +1 @@
NSS_3_18_RTM
NSS_3_18_1_BETA1

View File

@ -87,8 +87,8 @@ EXTRA_LIBS += \
$(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \
$(PKIXLIB) \
$(DBMLIB) \
$(DIST)/lib/$(LIB_PREFIX)$(SQLITE_LIB_NAME).$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
$(SQLITE_LIB_DIR)/$(LIB_PREFIX)$(SQLITE_LIB_NAME).$(LIB_SUFFIX) \
$(NSSUTIL_LIB_DIR)/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.$(LIB_SUFFIX) \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.$(LIB_SUFFIX) \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \
@ -135,7 +135,7 @@ endif
# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(SQLITE_LIB_DIR) \
-l$(SQLITE_LIB_NAME) \
-L$(NSSUTIL_LIB_DIR) \
-lnssutil3 \
@ -153,7 +153,7 @@ ifeq ($(OS_ARCH), WINNT)
# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS)
EXTRA_LIBS += \
$(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \
$(DIST)/lib/$(IMPORT_LIB_PREFIX)nssutil3$(IMPORT_LIB_SUFFIX) \
$(NSSUTIL_LIB_DIR)/$(IMPORT_LIB_PREFIX)nssutil3$(IMPORT_LIB_SUFFIX) \
$(DIST)/lib/$(IMPORT_LIB_PREFIX)smime3$(IMPORT_LIB_SUFFIX) \
$(DIST)/lib/$(IMPORT_LIB_PREFIX)ssl3$(IMPORT_LIB_SUFFIX) \
$(DIST)/lib/$(IMPORT_LIB_PREFIX)nss3$(IMPORT_LIB_SUFFIX) \

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -67,6 +67,10 @@ ifndef SOFTOKEN_LIB_DIR
SOFTOKEN_LIB_DIR = $(DIST)/lib
endif
ifndef SQLITE_LIB_DIR
SQLITE_LIB_DIR = $(DIST)/lib
endif
ifndef SQLITE_LIB_NAME
SQLITE_LIB_NAME = sqlite3
endif

View File

@ -8,6 +8,7 @@ MODULE = nss
CPPSRCS = \
ssl_loopback_unittest.cc \
ssl_extension_unittest.cc \
ssl_gtest.cc \
test_io.cc \
tls_agent.cc \

View File

@ -0,0 +1,578 @@
/* -*- 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 "sslproto.h"
#include <memory>
#include "tls_parser.h"
#include "tls_filter.h"
#include "tls_connect.h"
namespace nss_test {
class TlsExtensionFilter : public TlsHandshakeFilter {
protected:
virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
const DataBuffer& input, DataBuffer* output) {
if (handshake_type == kTlsHandshakeClientHello) {
TlsParser parser(input);
if (!FindClientHelloExtensions(parser, version)) {
return false;
}
return FilterExtensions(parser, input, output);
}
if (handshake_type == kTlsHandshakeServerHello) {
TlsParser parser(input);
if (!FindServerHelloExtensions(parser, version)) {
return false;
}
return FilterExtensions(parser, input, output);
}
return false;
}
virtual bool FilterExtension(uint16_t extension_type,
const DataBuffer& input, DataBuffer* output) = 0;
public:
static bool FindClientHelloExtensions(TlsParser& parser, uint16_t version) {
if (!parser.Skip(2 + 32)) { // version + random
return false;
}
if (!parser.SkipVariable(1)) { // session ID
return false;
}
if (IsDtls(version) && !parser.SkipVariable(1)) { // DTLS cookie
return false;
}
if (!parser.SkipVariable(2)) { // cipher suites
return false;
}
if (!parser.SkipVariable(1)) { // compression methods
return false;
}
return true;
}
static bool FindServerHelloExtensions(TlsParser& parser, uint16_t version) {
if (!parser.Skip(2 + 32)) { // version + random
return false;
}
if (!parser.SkipVariable(1)) { // session ID
return false;
}
if (!parser.Skip(2)) { // cipher suite
return false;
}
if (NormalizeTlsVersion(version) <= SSL_LIBRARY_VERSION_TLS_1_2) {
if (!parser.Skip(1)) { // compression method
return false;
}
}
return true;
}
private:
bool FilterExtensions(TlsParser& parser,
const DataBuffer& input, DataBuffer* output) {
size_t length_offset = parser.consumed();
uint32_t all_extensions;
if (!parser.Read(&all_extensions, 2)) {
return false; // no extensions, odd but OK
}
if (all_extensions != parser.remaining()) {
return false; // malformed
}
bool changed = false;
// Write out the start of the message.
output->Allocate(input.len());
output->Write(0, input.data(), parser.consumed());
size_t output_offset = parser.consumed();
while (parser.remaining()) {
uint32_t extension_type;
if (!parser.Read(&extension_type, 2)) {
return false; // malformed
}
// Copy extension type.
output->Write(output_offset, extension_type, 2);
DataBuffer extension;
if (!parser.ReadVariable(&extension, 2)) {
return false; // malformed
}
output_offset = ApplyFilter(static_cast<uint16_t>(extension_type), extension,
output, output_offset + 2, &changed);
}
output->Truncate(output_offset);
if (changed) {
size_t newlen = output->len() - length_offset - 2;
if (newlen >= 0x10000) {
return false; // bad: size increased too much
}
output->Write(length_offset, newlen, 2);
}
return changed;
}
size_t ApplyFilter(uint16_t extension_type, const DataBuffer& extension,
DataBuffer* output, size_t offset, bool* changed) {
const DataBuffer* source = &extension;
DataBuffer filtered;
if (FilterExtension(extension_type, extension, &filtered) &&
filtered.len() < 0x10000) {
*changed = true;
std::cerr << "extension old: " << extension << std::endl;
std::cerr << "extension new: " << filtered << std::endl;
source = &filtered;
}
output->Write(offset, source->len(), 2);
output->Write(offset + 2, *source);
return offset + 2 + source->len();
}
};
class TlsExtensionTruncator : public TlsExtensionFilter {
public:
TlsExtensionTruncator(uint16_t extension, size_t length)
: extension_(extension), length_(length) {}
virtual bool FilterExtension(uint16_t extension_type,
const DataBuffer& input, DataBuffer* output) {
if (extension_type != extension_) {
return false;
}
if (input.len() <= length_) {
return false;
}
output->Assign(input.data(), length_);
return true;
}
private:
uint16_t extension_;
size_t length_;
};
class TlsExtensionDamager : public TlsExtensionFilter {
public:
TlsExtensionDamager(uint16_t extension, size_t index)
: extension_(extension), index_(index) {}
virtual bool FilterExtension(uint16_t extension_type,
const DataBuffer& input, DataBuffer* output) {
if (extension_type != extension_) {
return false;
}
*output = input;
output->data()[index_] += 73; // Increment selected for maximum damage
return true;
}
private:
uint16_t extension_;
size_t index_;
};
class TlsExtensionReplacer : public TlsExtensionFilter {
public:
TlsExtensionReplacer(uint16_t extension, const DataBuffer& data)
: extension_(extension), data_(data) {}
virtual bool FilterExtension(uint16_t extension_type,
const DataBuffer& input, DataBuffer* output) {
if (extension_type != extension_) {
return false;
}
*output = data_;
return true;
}
private:
uint16_t extension_;
DataBuffer data_;
};
class TlsExtensionInjector : public TlsHandshakeFilter {
public:
TlsExtensionInjector(uint16_t ext, DataBuffer& data)
: extension_(ext), data_(data) {}
virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
const DataBuffer& input, DataBuffer* output) {
size_t offset;
if (handshake_type == kTlsHandshakeClientHello) {
TlsParser parser(input);
if (!TlsExtensionFilter::FindClientHelloExtensions(parser, version)) {
return false;
}
offset = parser.consumed();
} else if (handshake_type == kTlsHandshakeServerHello) {
TlsParser parser(input);
if (!TlsExtensionFilter::FindServerHelloExtensions(parser, version)) {
return false;
}
offset = parser.consumed();
} else {
return false;
}
*output = input;
std::cerr << "Pre:" << input << std::endl;
std::cerr << "Lof:" << offset << std::endl;
// Increase the size of the extensions.
uint16_t* len_addr = reinterpret_cast<uint16_t*>(output->data() + offset);
std::cerr << "L-p:" << ntohs(*len_addr) << std::endl;
*len_addr = htons(ntohs(*len_addr) + data_.len() + 4);
std::cerr << "L-i:" << ntohs(*len_addr) << std::endl;
// Insert the extension type and length.
DataBuffer type_length;
type_length.Allocate(4);
type_length.Write(0, extension_, 2);
type_length.Write(2, data_.len(), 2);
output->Splice(type_length, offset + 2);
// Insert the payload.
output->Splice(data_, offset + 6);
std::cerr << "Aft:" << *output << std::endl;
return true;
}
private:
uint16_t extension_;
DataBuffer data_;
};
class TlsExtensionTestBase : public TlsConnectTestBase {
protected:
TlsExtensionTestBase(Mode mode, uint16_t version)
: TlsConnectTestBase(mode, version) {}
void ClientHelloErrorTest(PacketFilter* filter,
uint8_t alert = kTlsAlertDecodeError) {
auto alert_recorder = new TlsAlertRecorder();
server_->SetPacketFilter(alert_recorder);
if (filter) {
client_->SetPacketFilter(filter);
}
ConnectExpectFail();
ASSERT_EQ(kTlsAlertFatal, alert_recorder->level());
ASSERT_EQ(alert, alert_recorder->description());
}
void ServerHelloErrorTest(PacketFilter* filter,
uint8_t alert = kTlsAlertDecodeError) {
auto alert_recorder = new TlsAlertRecorder();
client_->SetPacketFilter(alert_recorder);
if (filter) {
server_->SetPacketFilter(filter);
}
ConnectExpectFail();
ASSERT_EQ(kTlsAlertFatal, alert_recorder->level());
ASSERT_EQ(alert, alert_recorder->description());
}
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);
}
};
class TlsExtensionTestDtls
: public TlsExtensionTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
TlsExtensionTestDtls() : TlsExtensionTestBase(DGRAM, GetParam()) {}
};
class TlsExtensionTest12Plus
: public TlsExtensionTestBase,
public ::testing::WithParamInterface<std::string> {
public:
TlsExtensionTest12Plus()
: TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
SSL_LIBRARY_VERSION_TLS_1_2) {}
};
class TlsExtensionTestGeneric
: public TlsExtensionTestBase,
public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
public:
TlsExtensionTestGeneric()
: TlsExtensionTestBase(TlsConnectTestBase::ToMode((std::get<0>(GetParam()))),
std::get<1>(GetParam())) {}
};
TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 1));
}
TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 4));
}
TEST_P(TlsExtensionTestGeneric, TruncateSni) {
ClientHelloErrorTest(new TlsExtensionTruncator(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(new TlsExtensionInjector(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(new TlsExtensionReplacer(ssl_server_name_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
EnableAlpn();
DataBuffer extension;
ClientHelloErrorTest(new TlsExtensionReplacer(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(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
kTlsAlertNoApplicationProtocol);
}
TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
EnableAlpn();
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 1));
}
TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
EnableAlpn();
// This will leave the length of the second entry, but no value.
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 5));
}
TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
EnableAlpn();
const uint8_t val[] = { 0x01, 0x61, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(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);
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyList) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyName) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x01, 0x00 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedListTrailingData) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x02, 0x01, 0x61, 0x00 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedExtraEntry) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x04, 0x01, 0x61, 0x01, 0x62 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadListLength) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x99, 0x01, 0x61, 0x00 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadNameLength) {
EnableAlpn();
const uint8_t val[] = { 0x00, 0x02, 0x99, 0x61 };
DataBuffer extension(val, sizeof(val));
ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestDtls, SrtpShort) {
EnableSrtp();
ClientHelloErrorTest(new TlsExtensionTruncator(ssl_use_srtp_xtn, 3));
}
TEST_P(TlsExtensionTestDtls, SrtpOdd) {
EnableSrtp();
const uint8_t val[] = { 0x00, 0x01, 0xff, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_use_srtp_xtn, extension));
}
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
const uint8_t val[] = { 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(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(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
extension));
}
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
const uint8_t val[] = { 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
extension));
}
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
const uint8_t val[] = { 0x00, 0x01, 0x04 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
extension));
}
// The extension handling ignores unsupported hashes, so breaking that has no
// effect on success rates. However, ssl3_SendServerKeyExchange catches an
// unsupported signature algorithm.
// This actually fails with a decryption error (fatal alert 51). That's a bad
// to fail, since any tampering with the handshake will trigger that alert when
// verifying the Finished message. Thus, this test is disabled until this error
// is turned into an alert.
TEST_P(TlsExtensionTest12Plus, DISABLED_SignatureAlgorithmsSigUnsupported) {
const uint8_t val[] = { 0x00, 0x02, 0x04, 0x99 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x00, 0x01, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x09, 0x99, 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x00, 0x02, 0x00, 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedPointsEmpty) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedPointsBadLength) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x99, 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedPointsTrailingData) {
EnableSomeECDHECiphers();
const uint8_t val[] = { 0x01, 0x00, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoBadLength) {
const uint8_t val[] = { 0x99 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
extension));
}
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoMismatch) {
const uint8_t val[] = { 0x01, 0x00 };
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
extension));
}
// The extension has to contain a length.
TEST_P(TlsExtensionTestGeneric, RenegotiationInfoExtensionEmpty) {
DataBuffer extension;
ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
extension));
}
INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
TlsConnectTestBase::kTlsV10));
INSTANTIATE_TEST_CASE_P(ExtensionVariants, TlsExtensionTestGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesAll,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
TlsConnectTestBase::kTlsModesAll);
INSTANTIATE_TEST_CASE_P(ExtensionDgram, TlsExtensionTestDtls,
TlsConnectTestBase::kTlsV11V12);
} // namespace nspr_test

View File

@ -44,13 +44,7 @@ TEST_P(TlsConnectGeneric, SetupOnly) {}
TEST_P(TlsConnectGeneric, Connect) {
Connect();
// Check that we negotiated the expected version.
if (mode_ == STREAM) {
client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_0);
} else {
client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_1);
}
client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
}
TEST_P(TlsConnectGeneric, ConnectResumed) {
@ -152,29 +146,6 @@ TEST_P(TlsConnectGeneric, ConnectClientNoneServerBoth) {
CheckResumption(RESUME_NONE);
}
TEST_P(TlsConnectGeneric, ConnectTLS_1_1_Only) {
EnsureTlsSetup();
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_1);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_1);
Connect();
client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_1);
}
TEST_P(TlsConnectGeneric, ConnectTLS_1_2_Only) {
EnsureTlsSetup();
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
Connect();
client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
}
TEST_P(TlsConnectGeneric, ConnectAlpn) {
EnableAlpn();
Connect();
@ -182,19 +153,19 @@ TEST_P(TlsConnectGeneric, ConnectAlpn) {
server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
}
TEST_F(DtlsConnectTest, ConnectSrtp) {
TEST_P(TlsConnectDatagram, ConnectSrtp) {
EnableSrtp();
Connect();
CheckSrtp();
}
TEST_F(TlsConnectTest, ConnectECDHE) {
TEST_P(TlsConnectStream, ConnectECDHE) {
EnableSomeECDHECiphers();
Connect();
client_->CheckKEAType(ssl_kea_ecdh);
}
TEST_F(TlsConnectTest, ConnectECDHETwiceReuseKey) {
TEST_P(TlsConnectStream, ConnectECDHETwiceReuseKey) {
EnableSomeECDHECiphers();
TlsInspectorRecordHandshakeMessage* i1 =
new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
@ -223,7 +194,7 @@ TEST_F(TlsConnectTest, ConnectECDHETwiceReuseKey) {
dhe1.public_key_.len()));
}
TEST_F(TlsConnectTest, ConnectECDHETwiceNewKey) {
TEST_P(TlsConnectStream, ConnectECDHETwiceNewKey) {
EnableSomeECDHECiphers();
SECStatus rv =
SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
@ -257,7 +228,17 @@ TEST_F(TlsConnectTest, ConnectECDHETwiceNewKey) {
dhe1.public_key_.len())));
}
INSTANTIATE_TEST_CASE_P(Variants, TlsConnectGeneric,
::testing::Values("TLS", "DTLS"));
INSTANTIATE_TEST_CASE_P(VariantsStream10, TlsConnectGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
TlsConnectTestBase::kTlsV10));
INSTANTIATE_TEST_CASE_P(VariantsAll, TlsConnectGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesAll,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(VersionsDatagram, TlsConnectDatagram,
TlsConnectTestBase::kTlsV11V12);
INSTANTIATE_TEST_CASE_P(VersionsDatagram, TlsConnectStream,
TlsConnectTestBase::kTlsV11V12);
} // namespace nspr_test

View File

@ -328,7 +328,7 @@ int32_t DummyPrSocket::Recv(void *buf, int32_t buflen) {
}
Packet *front = input_.front();
if (buflen < front->len()) {
if (static_cast<size_t>(buflen) < front->len()) {
PR_ASSERT(false);
PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
return -1;
@ -344,33 +344,23 @@ int32_t DummyPrSocket::Recv(void *buf, int32_t buflen) {
}
int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
DataBuffer packet(static_cast<const uint8_t*>(buf),
static_cast<size_t>(length));
if (filter_) {
DataBuffer filtered;
if (filter_->Filter(packet, &filtered)) {
if (WriteDirect(filtered) != filtered.len()) {
PR_SetError(PR_IO_ERROR, 0);
return -1;
}
LOG("Wrote: " << packet);
// libssl can't handle if this reports something other than the length of
// what was passed in (or less, but we're not doing partial writes).
return packet.len();
}
}
return WriteDirect(packet);
}
int32_t DummyPrSocket::WriteDirect(const DataBuffer& packet) {
if (!peer_) {
PR_SetError(PR_IO_ERROR, 0);
return -1;
}
peer_->PacketReceived(packet);
return static_cast<int32_t>(packet.len()); // ignore truncation
DataBuffer packet(static_cast<const uint8_t*>(buf),
static_cast<size_t>(length));
DataBuffer filtered;
if (filter_ && filter_->Filter(packet, &filtered)) {
LOG("Filtered packet: " << filtered);
peer_->PacketReceived(filtered);
} else {
peer_->PacketReceived(packet);
}
// libssl can't handle it if this reports something other than the length
// of what was passed in (or less, but we're not doing partial writes).
return static_cast<int32_t>(packet.len());
}
Poller *Poller::instance;

View File

@ -12,6 +12,7 @@
#include <memory>
#include <queue>
#include <string>
#include <ostream>
#include "prio.h"
@ -36,6 +37,10 @@ class PacketFilter {
enum Mode { STREAM, DGRAM };
inline std::ostream& operator<<(std::ostream& os, Mode m) {
return os << ((m == STREAM) ? "TLS" : "DTLS");
}
class DummyPrSocket {
public:
~DummyPrSocket();
@ -52,7 +57,6 @@ class DummyPrSocket {
int32_t Read(void* data, int32_t len);
int32_t Recv(void* buf, int32_t buflen);
int32_t Write(const void* buf, int32_t length);
int32_t WriteDirect(const DataBuffer& data);
Mode mode() const { return mode_; }
bool readable() const { return !input_.empty(); }

View File

@ -58,8 +58,12 @@ bool TlsAgent::EnsureTlsSetup() {
if (rv != SECSuccess) return false;
}
SECStatus rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook,
reinterpret_cast<void*>(this));
SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook,
reinterpret_cast<void*>(this));
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
@ -104,8 +108,13 @@ void TlsAgent::SetSessionCacheEnabled(bool en) {
}
void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
SSLVersionRange range = {minver, maxver};
ASSERT_EQ(SECSuccess, SSL_VersionRangeSet(ssl_fd_, &range));
vrange_.min = minver;
vrange_.max = maxver;
if (ssl_fd_) {
SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
ASSERT_EQ(SECSuccess, rv);
}
}
void TlsAgent::CheckKEAType(SSLKEAType type) const {

View File

@ -14,6 +14,9 @@
#include "test_io.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
namespace nss_test {
#define LOG(msg) std::cerr << name_ << ": " << msg << std::endl
@ -40,6 +43,10 @@ class TlsAgent : public PollTarget {
state_(INIT) {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
SECStatus rv = SSL_VersionRangeGetDefault(mode_ == STREAM ?
ssl_variant_stream : ssl_variant_datagram,
&vrange_);
EXPECT_EQ(SECSuccess, rv);
}
~TlsAgent() {
@ -95,6 +102,9 @@ class TlsAgent : public PollTarget {
PRFileDesc* ssl_fd() { return ssl_fd_; }
uint16_t min_version() const { return vrange_.min; }
uint16_t max_version() const { return vrange_.max; }
bool version(uint16_t* version) const {
if (state_ != CONNECTED) return false;
@ -103,6 +113,12 @@ class TlsAgent : public PollTarget {
return true;
}
uint16_t version() const {
EXPECT_EQ(CONNECTED, state_);
return info_.protocolVersion;
}
bool cipher_suite(int16_t* cipher_suite) const {
if (state_ != CONNECTED) return false;
@ -163,6 +179,7 @@ class TlsAgent : public PollTarget {
State state_;
SSLChannelInfo info_;
SSLCipherSuiteInfo csinfo_;
SSLVersionRange vrange_;
};
} // namespace nss_test

View File

@ -8,16 +8,56 @@
#include <iostream>
#include "sslproto.h"
#include "gtest_utils.h"
extern std::string g_working_dir_path;
namespace nss_test {
TlsConnectTestBase::TlsConnectTestBase(Mode mode)
static const std::string kTlsModesStreamArr[] = {"TLS"};
::testing::internal::ParamGenerator<std::string>
TlsConnectTestBase::kTlsModesStream = ::testing::ValuesIn(kTlsModesStreamArr);
static const std::string kTlsModesAllArr[] = {"TLS", "DTLS"};
::testing::internal::ParamGenerator<std::string>
TlsConnectTestBase::kTlsModesAll = ::testing::ValuesIn(kTlsModesAllArr);
static const uint16_t kTlsV10Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0};
::testing::internal::ParamGenerator<uint16_t>
TlsConnectTestBase::kTlsV10 = ::testing::ValuesIn(kTlsV10Arr);
static const uint16_t kTlsV11V12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_2};
::testing::internal::ParamGenerator<uint16_t>
TlsConnectTestBase::kTlsV11V12 = ::testing::ValuesIn(kTlsV11V12Arr);
// TODO: add TLS 1.3
static const uint16_t kTlsV12PlusArr[] = {SSL_LIBRARY_VERSION_TLS_1_2};
::testing::internal::ParamGenerator<uint16_t>
TlsConnectTestBase::kTlsV12Plus = ::testing::ValuesIn(kTlsV12PlusArr);
static std::string VersionString(uint16_t version) {
switch(version) {
case 0:
return "(no version)";
case SSL_LIBRARY_VERSION_TLS_1_0:
return "1.0";
case SSL_LIBRARY_VERSION_TLS_1_1:
return "1.1";
case SSL_LIBRARY_VERSION_TLS_1_2:
return "1.2";
default:
std::cerr << "Invalid version: " << version << std::endl;
EXPECT_TRUE(false);
return "";
}
}
TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
: mode_(mode),
client_(new TlsAgent("client", TlsAgent::CLIENT, mode_)),
server_(new TlsAgent("server", TlsAgent::SERVER, mode_)) {}
server_(new TlsAgent("server", TlsAgent::SERVER, mode_)),
version_(version),
session_ids_() {
std::cerr << "Version: " << mode_ << " " << VersionString(version_) << std::endl;
}
TlsConnectTestBase::~TlsConnectTestBase() {
delete client_;
@ -49,6 +89,11 @@ void TlsConnectTestBase::Init() {
client_->SetPeer(server_);
server_->SetPeer(client_);
if (version_) {
client_->SetVersionRange(version_, version_);
server_->SetVersionRange(version_, version_);
}
}
void TlsConnectTestBase::Reset() {
@ -72,14 +117,21 @@ void TlsConnectTestBase::Handshake() {
client_->Handshake();
server_->Handshake();
ASSERT_TRUE_WAIT(client_->state() != TlsAgent::CONNECTING &&
server_->state() != TlsAgent::CONNECTING,
ASSERT_TRUE_WAIT((client_->state() != TlsAgent::CONNECTING) &&
(server_->state() != TlsAgent::CONNECTING),
5000);
}
void TlsConnectTestBase::Connect() {
Handshake();
// Check the version is as expected
ASSERT_EQ(client_->version(), server_->version());
ASSERT_EQ(std::min(client_->max_version(),
server_->max_version()),
client_->version());
ASSERT_EQ(TlsAgent::CONNECTED, client_->state());
ASSERT_EQ(TlsAgent::CONNECTED, server_->state());
@ -90,14 +142,15 @@ void TlsConnectTestBase::Connect() {
ASSERT_TRUE(ret);
ASSERT_EQ(cipher_suite1, cipher_suite2);
std::cerr << "Connected with cipher suite " << client_->cipher_suite_name()
std::cerr << "Connected with version " << client_->version()
<< " cipher suite " << client_->cipher_suite_name()
<< std::endl;
// Check and store session ids.
std::vector<uint8_t> sid_c1 = client_->session_id();
ASSERT_EQ(32, sid_c1.size());
ASSERT_EQ(32U, sid_c1.size());
std::vector<uint8_t> sid_s1 = server_->session_id();
ASSERT_EQ(32, sid_s1.size());
ASSERT_EQ(32U, sid_s1.size());
ASSERT_EQ(sid_c1, sid_s1);
session_ids_.push_back(sid_c1);
}
@ -136,7 +189,7 @@ void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
if (resume_ct) {
// Check that the last two session ids match.
ASSERT_GE(2, session_ids_.size());
ASSERT_GE(2U, session_ids_.size());
ASSERT_EQ(session_ids_[session_ids_.size()-1],
session_ids_[session_ids_.size()-2]);
}
@ -163,8 +216,7 @@ void TlsConnectTestBase::CheckSrtp() {
}
TlsConnectGeneric::TlsConnectGeneric()
: TlsConnectTestBase((GetParam() == "TLS") ? STREAM : DGRAM) {
std::cerr << "Variant: " << GetParam() << std::endl;
}
: TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
std::get<1>(GetParam())) {}
} // namespace nss_test

View File

@ -7,6 +7,8 @@
#ifndef tls_connect_h_
#define tls_connect_h_
#include <tuple>
#include "sslt.h"
#include "tls_agent.h"
@ -19,7 +21,17 @@ namespace nss_test {
// A generic TLS connection test base.
class TlsConnectTestBase : public ::testing::Test {
public:
TlsConnectTestBase(Mode mode);
static ::testing::internal::ParamGenerator<std::string> kTlsModesStream;
static ::testing::internal::ParamGenerator<std::string> kTlsModesAll;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV10;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV11V12;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV12Plus;
static inline Mode ToMode(const std::string& str) {
return str == "TLS" ? STREAM : DGRAM;
}
TlsConnectTestBase(Mode mode, uint16_t version);
virtual ~TlsConnectTestBase();
void SetUp();
@ -46,30 +58,35 @@ class TlsConnectTestBase : public ::testing::Test {
void EnableAlpn();
void EnableSrtp();
void CheckSrtp();
protected:
Mode mode_;
TlsAgent* client_;
TlsAgent* server_;
uint16_t version_;
std::vector<std::vector<uint8_t>> session_ids_;
};
// A TLS-only test base.
class TlsConnectTest : public TlsConnectTestBase {
class TlsConnectStream : public TlsConnectTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
TlsConnectTest() : TlsConnectTestBase(STREAM) {}
TlsConnectStream() : TlsConnectTestBase(STREAM, GetParam()) {}
};
// A DTLS-only test base.
class DtlsConnectTest : public TlsConnectTestBase {
class TlsConnectDatagram : public TlsConnectTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
DtlsConnectTest() : TlsConnectTestBase(DGRAM) {}
TlsConnectDatagram() : TlsConnectTestBase(DGRAM, GetParam()) {}
};
// A generic test class that can be either STREAM or DGRAM. This is configured
// in ssl_loopback_unittest.cc. All uses of this should use TEST_P().
class TlsConnectGeneric : public TlsConnectTestBase,
public ::testing::WithParamInterface<std::string> {
// A generic test class that can be either STREAM or DGRAM and a single version
// of TLS. This is configured in ssl_loopback_unittest.cc. All uses of this
// should use TEST_P().
class TlsConnectGeneric
: public TlsConnectTestBase,
public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
public:
TlsConnectGeneric();
};

View File

@ -192,6 +192,8 @@ bool TlsAlertRecorder::FilterRecord(uint8_t content_type, uint16_t version,
return false;
}
std::cerr << "Alert: " << input << std::endl;
TlsParser parser(input);
uint8_t lvl;
if (!parser.Read(&lvl)) {

View File

@ -33,12 +33,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.18" _NSS_ECC_STRING _NSS_CUSTOMIZED
#define NSS_VERSION "3.18.1" _NSS_ECC_STRING _NSS_CUSTOMIZED " Beta"
#define NSS_VMAJOR 3
#define NSS_VMINOR 18
#define NSS_VPATCH 0
#define NSS_VBUILD 2
#define NSS_BETA PR_FALSE
#define NSS_VPATCH 1
#define NSS_VBUILD 0
#define NSS_BETA PR_TRUE
#ifndef RC_INVOKED

View File

@ -22,7 +22,7 @@ RESNAME = $(LIBRARY_NAME).rc
ifdef NS_USE_GCC
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(SQLITE_LIB_DIR) \
-l$(SQLITE_LIB_NAME) \
-L$(NSSUTIL_LIB_DIR) \
-lnssutil3 \
@ -34,7 +34,7 @@ EXTRA_SHARED_LIBS += \
else # ! NS_USE_GCC
EXTRA_SHARED_LIBS += \
$(DIST)/lib/$(SQLITE_LIB_NAME).lib \
$(SQLITE_LIB_DIR)/$(SQLITE_LIB_NAME).lib \
$(NSSUTIL_LIB_DIR)/nssutil3.lib \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
@ -47,7 +47,7 @@ else
# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
-L$(SQLITE_LIB_DIR) \
-l$(SQLITE_LIB_NAME) \
-L$(NSSUTIL_LIB_DIR) \
-lnssutil3 \

View File

@ -25,11 +25,11 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.18" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.18.1" SOFTOKEN_ECC_STRING " Beta"
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 18
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 2
#define SOFTOKEN_BETA PR_FALSE
#define SOFTOKEN_VPATCH 1
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_TRUE
#endif /* _SOFTKVER_H_ */

View File

@ -2788,6 +2788,12 @@ ssl3_SendRecord( sslSocket * ss,
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
return SECFailure;
}
capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
if (capRecordVersion) {
@ -3233,6 +3239,9 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
}
if (level == alert_fatal) {
ss->ssl3.fatalAlertSent = PR_TRUE;
}
ssl_ReleaseXmitBufLock(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */

View File

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* SSL3 Protocol
*
@ -1184,8 +1185,7 @@ ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type,
if (data->len < 2 || data->len > 255 || !data->data ||
data->len != (unsigned int)data->data[0] + 1) {
/* malformed */
goto loser;
return ssl3_DecodeError(ss);
}
for (i = data->len; --i > 0; ) {
if (data->data[i] == 0) {
@ -1196,10 +1196,10 @@ ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type,
return rv;
}
}
loser:
/* evil client doesn't support uncompressed */
ssl3_DisableECCSuites(ss, ecSuites);
return SECFailure;
return SECSuccess;
}
@ -1220,7 +1220,7 @@ ECName ssl3_GetSvrCertCurveName(sslSocket *ss)
return ec_curve;
}
/* Ensure that the curve in our server cert is one of the ones suppored
/* Ensure that the curve in our server cert is one of the ones supported
* by the remote client, and disable all ECC cipher suites if not.
*/
SECStatus
@ -1231,26 +1231,34 @@ ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
PRUint32 mutualCurves = 0;
PRUint16 svrCertCurveName;
if (!data->data || data->len < 4 || data->len > 65535)
goto loser;
if (!data->data || data->len < 4) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* get the length of elliptic_curve_list */
list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
/* malformed */
goto loser;
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* build bit vector of peer's supported curve names */
while (data->len) {
PRInt32 curve_name =
ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
PRInt32 curve_name =
ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
if (curve_name < 0) {
return SECFailure; /* fatal alert already sent */
}
if (curve_name > ec_noName && curve_name < ec_pastLastName) {
peerCurves |= (1U << curve_name);
}
}
/* What curves do we support in common? */
mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
if (!mutualCurves) { /* no mutually supported EC Curves */
goto loser;
if (!mutualCurves) {
/* no mutually supported EC Curves, disable ECC */
ssl3_DisableECCSuites(ss, ecSuites);
return SECSuccess;
}
/* if our ECC cert doesn't use one of these supported curves,
@ -1266,12 +1274,7 @@ ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
*/
ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
return SECFailure;
loser:
/* no common curve supported */
ssl3_DisableECCSuites(ss, ecSuites);
return SECFailure;
return SECSuccess;
}
#endif /* NSS_DISABLE_ECC */

View File

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* SSL3 Protocol
*
@ -64,10 +65,14 @@ static PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static PRInt32 ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static PRInt32 ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static SECStatus ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
SECItem *data);
static PRInt32 ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static PRInt32 ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static SECStatus ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
SECItem *data);
static SECStatus ssl3_ServerHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
SECItem *data);
static PRInt32 ssl3_ServerSendStatusRequestXtn(sslSocket * ss,
PRBool append, PRUint32 maxBytes);
static SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss,
@ -247,7 +252,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
{ ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
{ ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn },
@ -263,7 +268,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
{ ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
{ -1, NULL }
};
@ -290,7 +295,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
{ ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
{ ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
@ -398,13 +403,7 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
PRInt32 listLenBytes = 0;
if (!ss->sec.isServer) {
/* Verify extension_data is empty. */
if (data->data || data->len ||
!ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
/* malformed or was not initiated by the client.*/
return SECFailure;
}
return SECSuccess;
return SECSuccess; /* ignore extension */
}
/* Server side - consume client data and register server sender. */
@ -414,33 +413,38 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
}
/* length of server_name_list */
listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
if (listLenBytes == 0 || listLenBytes != data->len) {
if (listLenBytes < 0 || listLenBytes != data->len) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
if (listLenBytes == 0) {
return SECSuccess; /* ignore an empty extension */
}
ldata = *data;
/* Calculate the size of the array.*/
while (listLenBytes > 0) {
SECItem litem;
SECStatus rv;
PRInt32 type;
/* Name Type (sni_host_name) */
PRInt32 type;
/* Skip Name Type (sni_host_name); checks are on the second pass */
type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len);
if (!ldata.len) {
if (type < 0) { /* i.e., SECFailure cast to PRint32 */
return SECFailure;
}
rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len);
if (rv != SECSuccess) {
return SECFailure;
return rv;
}
/* Adjust total length for cunsumed item, item len and type.*/
/* Adjust total length for consumed item, item len and type.*/
listLenBytes -= litem.len + 3;
if (listLenBytes > 0 && !ldata.len) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
listCount += 1;
}
if (!listCount) {
return SECFailure;
return SECFailure; /* nothing we can act on */
}
names = PORT_ZNewArray(SECItem, listCount);
if (!names) {
@ -455,6 +459,7 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
/* Check if we have such type in the list */
for (j = 0;j < listCount && names[j].data;j++) {
/* TODO bug 998524: .type is not assigned a value */
if (names[j].type == type) {
nametypePresent = PR_TRUE;
break;
@ -464,7 +469,10 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2,
&data->data, &data->len);
if (rv != SECSuccess) {
goto loser;
PORT_Assert(0);
PORT_Free(names);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return rv;
}
if (nametypePresent == PR_FALSE) {
namesPos += 1;
@ -479,10 +487,6 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
return SECSuccess;
loser:
PORT_Free(names);
return SECFailure;
}
/* Called by both clients and servers.
@ -603,17 +607,11 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned int length)
* store protocol identifiers in null-terminated strings.
*/
if (newOffset > length || data[offset] == 0) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
return SECFailure;
}
offset = newOffset;
}
if (offset > length) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
return SECFailure;
}
return SECSuccess;
}
@ -626,34 +624,41 @@ ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data)
SECItem result = { siBuffer, resultBuffer, 0 };
rv = ssl3_ValidateNextProtoNego(data->data, data->len);
if (rv != SECSuccess)
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
return rv;
}
PORT_Assert(ss->nextProtoCallback);
rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
result.data, &result.len, sizeof resultBuffer);
if (rv != SECSuccess)
return rv;
/* If the callback wrote more than allowed to |result| it has corrupted our
* stack. */
if (result.len > sizeof resultBuffer) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
result.data, &result.len, sizeof(resultBuffer));
if (rv != SECSuccess) {
/* Expect callback to call PORT_SetError() */
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
return SECFailure;
}
/* If the callback wrote more than allowed to |result| it has corrupted our
* stack. */
if (result.len > sizeof(resultBuffer)) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
/* TODO: crash */
return SECFailure;
}
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
if (ex_type == ssl_app_layer_protocol_xtn &&
ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
/* The callback might say OK, but then it's picked a default.
* That's OK for NPN, but not ALPN. */
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
/* The callback might say OK, but then it picks a default value - one
* that was not listed. That's OK for NPN, but not ALPN. */
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
(void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol);
return SECFailure;
}
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
}
@ -669,17 +674,16 @@ ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
if (ss->firstHsDone || data->len == 0) {
/* Clients MUST send a non-empty ALPN extension. */
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
/* unlike NPN, ALPN has extra redundant length information so that
* the extension is the same in both ClientHello and ServerHello */
/* Unlike NPN, ALPN has extra redundant length information so that
* the extension is the same in both ClientHello and ServerHello. */
count = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
if (count < 0) {
return SECFailure; /* fatal alert was sent */
}
if (count != data->len) {
return ssl3_DecodeError(ss);
(void)ssl3_DecodeError(ss);
return SECFailure;
}
if (!ss->nextProtoCallback) {
@ -694,8 +698,13 @@ ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
/* prepare to send back a response, if we negotiated */
if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
return ssl3_RegisterServerHelloExtensionSender(
rv = ssl3_RegisterServerHelloExtensionSender(
ss, ex_type, ssl3_ServerSendAppProtoXtn);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
return rv;
}
}
return SECSuccess;
}
@ -713,7 +722,8 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
* we've negotiated NPN then we're required to send the NPN handshake
* message. Thus, these two extensions cannot both be negotiated on the
* same connection. */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
PORT_SetError(SSL_ERROR_BAD_SERVER);
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
@ -722,7 +732,9 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
* that an application erroneously cleared the callback between the time
* we sent the ClientHello and now. */
if (!ss->nextProtoCallback) {
PORT_Assert(0);
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
return SECFailure;
}
@ -732,8 +744,8 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
static SECStatus
ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
{
const unsigned char* d = data->data;
PRUint16 name_list_len;
SECStatus rv;
PRInt32 list_len;
SECItem protocol_name;
if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
@ -743,22 +755,30 @@ ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
/* The extension data from the server has the following format:
* uint16 name_list_len;
* uint8 len;
* uint8 len; // where len >= 1
* uint8 protocol_name[len]; */
if (data->len < 4 || data->len > 2 + 1 + 255) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
return SECFailure;
}
name_list_len = ((PRUint16) d[0]) << 8 |
((PRUint16) d[1]);
if (name_list_len != data->len - 2 || d[2] != data->len - 3) {
list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
/* The list has to be the entire extension. */
if (list_len != data->len) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
return SECFailure;
}
protocol_name.data = data->data + 3;
protocol_name.len = data->len - 3;
rv = ssl3_ConsumeHandshakeVariable(ss, &protocol_name, 1,
&data->data, &data->len);
/* The list must have exactly one value. */
if (rv != SECSuccess || data->len != 0) {
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
return SECFailure;
}
SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
ss->ssl3.nextProtoState = SSL_NEXT_PROTO_SELECTED;
@ -1386,8 +1406,9 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
SSL3Statistics *ssl3stats;
/* Ignore the SessionTicket extension if processing is disabled. */
if (!ss->opt.enableSessionTickets)
if (!ss->opt.enableSessionTickets) {
return SECSuccess;
}
/* Keep track of negotiated extensions. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
@ -1445,8 +1466,9 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
extension_data.len = data->len;
if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket)
!= SECSuccess)
return SECFailure;
!= SECSuccess) {
return SECSuccess; /* Pretend it isn't there */
}
/* Get session ticket keys. */
#ifndef NO_PKCS11_BYPASS
@ -1874,18 +1896,22 @@ ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length)
/* get the data for this extension, so we can pass it or skip it. */
rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length);
if (rv != SECSuccess)
return rv;
return rv; /* alert already sent */
/* Check whether the server sent an extension which was not advertised
* in the ClientHello.
*/
if (!ss->sec.isServer &&
!ssl3_ClientExtensionAdvertised(ss, extension_type))
return SECFailure; /* TODO: send unsupported_extension alert */
!ssl3_ClientExtensionAdvertised(ss, extension_type)) {
(void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
return SECFailure;
}
/* Check whether an extension has been sent multiple times. */
if (ssl3_ExtensionNegotiated(ss, extension_type))
if (ssl3_ExtensionNegotiated(ss, extension_type)) {
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
/* find extension_type in table of Hello Extension Handlers */
for (handler = handlers; handler->ex_type >= 0; handler++) {
@ -1893,9 +1919,13 @@ ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length)
if (handler->ex_type == extension_type) {
rv = (*handler->ex_handler)(ss, (PRUint16)extension_type,
&extension_data);
/* Ignore this result */
/* Treat all bad extensions as unrecognized types. */
break;
if (rv != SECSuccess) {
if (!ss->ssl3.fatalAlertSent) {
/* send a generic alert if the handler didn't already */
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
}
return SECFailure;
}
}
}
}
@ -2027,13 +2057,14 @@ ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
: ss->ssl3.hs.finishedBytes * 2;
}
if (data->len != 1 + len ||
data->data[0] != len || (len &&
NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
data->data + 1, len))) {
/* Can we do this here? Or, must we arrange for the caller to do it? */
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
if (data->len != 1 + len || data->data[0] != len ) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
if (len && NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
data->data + 1, len)) {
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
return SECFailure;
}
/* remember that we got this extension and it was correct. */
@ -2042,13 +2073,13 @@ ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
if (ss->sec.isServer) {
/* prepare to send back the appropriate response */
rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
ssl3_SendRenegotiationInfoXtn);
ssl3_SendRenegotiationInfoXtn);
}
return rv;
}
static PRInt32
ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
{
PRUint32 ext_data_len;
PRInt16 i;
@ -2057,65 +2088,139 @@ ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
if (!ss)
return 0;
if (!ss->sec.isServer) {
/* Client side */
if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
return 0; /* Not relevant */
if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
return 0; /* Not relevant */
ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
if (append && maxBytes >= 4 + ext_data_len) {
/* Extension type */
rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
if (rv != SECSuccess) return -1;
/* Length of extension data */
rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
if (rv != SECSuccess) return -1;
/* Length of the SRTP cipher list */
rv = ssl3_AppendHandshakeNumber(ss,
2 * ss->ssl3.dtlsSRTPCipherCount,
2);
if (rv != SECSuccess) return -1;
/* The SRTP ciphers */
for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
rv = ssl3_AppendHandshakeNumber(ss,
ss->ssl3.dtlsSRTPCiphers[i],
2);
}
/* Empty MKI value */
ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
ssl_use_srtp_xtn;
}
return 4 + ext_data_len;
}
/* Server side */
if (append && maxBytes >= 9) {
if (append && maxBytes >= 4 + ext_data_len) {
/* Extension type */
rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
if (rv != SECSuccess) return -1;
/* Length of extension data */
rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
if (rv != SECSuccess) return -1;
/* Length of the SRTP cipher list */
rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
if (rv != SECSuccess) return -1;
/* The selected cipher */
rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
rv = ssl3_AppendHandshakeNumber(ss,
2 * ss->ssl3.dtlsSRTPCipherCount,
2);
if (rv != SECSuccess) return -1;
/* The SRTP ciphers */
for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
rv = ssl3_AppendHandshakeNumber(ss,
ss->ssl3.dtlsSRTPCiphers[i],
2);
}
/* Empty MKI value */
ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
ssl_use_srtp_xtn;
}
return 4 + ext_data_len;
}
static PRInt32
ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
{
SECStatus rv;
/* Server side */
if (!append || maxBytes < 9) {
return 9;
}
/* Extension type */
rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
if (rv != SECSuccess) return -1;
/* Length of extension data */
rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
if (rv != SECSuccess) return -1;
/* Length of the SRTP cipher list */
rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
if (rv != SECSuccess) return -1;
/* The selected cipher */
rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
if (rv != SECSuccess) return -1;
/* Empty MKI value */
ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
return 9;
}
static SECStatus
ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
{
SECStatus rv;
SECItem ciphers = {siBuffer, NULL, 0};
PRUint16 i;
PRUint16 cipher = 0;
PRBool found = PR_FALSE;
SECItem litem;
if (!data->data || !data->len) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* Get the cipher list */
rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
&data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure; /* fatal alert already sent */
}
/* Now check that the server has picked just 1 (i.e., len = 2) */
if (ciphers.len != 2) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* Get the selected cipher */
cipher = (ciphers.data[0] << 8) | ciphers.data[1];
/* Now check that this is one of the ciphers we offered */
for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
found = PR_TRUE;
break;
}
}
if (!found) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
/* Get the srtp_mki value */
rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
&data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure; /* alert already sent */
}
/* We didn't offer an MKI, so this must be 0 length */
if (litem.len != 0) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
/* extra trailing bytes */
if (data->len != 0) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* OK, this looks fine. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
ss->ssl3.dtlsSRTPCipherSuite = cipher;
return SECSuccess;
}
static SECStatus
ssl3_ServerHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
{
SECStatus rv;
SECItem ciphers = {siBuffer, NULL, 0};
@ -2125,74 +2230,6 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
PRBool found = PR_FALSE;
SECItem litem;
if (!ss->sec.isServer) {
/* Client side */
if (!data->data || !data->len) {
/* malformed */
return SECFailure;
}
/* Get the cipher list */
rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
&data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure;
}
/* Now check that the number of ciphers listed is 1 (len = 2) */
if (ciphers.len != 2) {
return SECFailure;
}
/* Get the selected cipher */
cipher = (ciphers.data[0] << 8) | ciphers.data[1];
/* Now check that this is one of the ciphers we offered */
for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
found = PR_TRUE;
break;
}
}
if (!found) {
return SECFailure;
}
/* Get the srtp_mki value */
rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
&data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure;
}
/* We didn't offer an MKI, so this must be 0 length */
/* XXX RFC 5764 Section 4.1.3 says:
* If the client detects a nonzero-length MKI in the server's
* response that is different than the one the client offered,
* then the client MUST abort the handshake and SHOULD send an
* invalid_parameter alert.
*
* Due to a limitation of the ssl3_HandleHelloExtensions function,
* returning SECFailure here won't abort the handshake. It will
* merely cause the use_srtp extension to be not negotiated. We
* should fix this. See NSS bug 753136.
*/
if (litem.len != 0) {
return SECFailure;
}
if (data->len != 0) {
/* malformed */
return SECFailure;
}
/* OK, this looks fine. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
ss->ssl3.dtlsSRTPCipherSuite = cipher;
return SECSuccess;
}
/* Server side */
if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) {
/* Ignore the extension if we aren't doing DTLS or no DTLS-SRTP
* preferences have been set. */
@ -2200,7 +2237,7 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
}
if (!data->data || data->len < 5) {
/* malformed */
(void)ssl3_DecodeError(ss);
return SECFailure;
}
@ -2208,10 +2245,11 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
&data->data, &data->len);
if (rv != SECSuccess) {
return SECFailure;
return SECFailure; /* alert already sent */
}
/* Check that the list is even length */
if (ciphers.len % 2) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
@ -2234,12 +2272,13 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
}
if (data->len != 0) {
return SECFailure; /* Malformed */
(void)ssl3_DecodeError(ss); /* trailing bytes */
return SECFailure;
}
/* Now figure out what to do */
if (!found) {
/* No matching ciphers */
/* No matching ciphers, pretend we don't support use_srtp */
return SECSuccess;
}
@ -2248,7 +2287,7 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn,
ssl3_SendUseSRTPXtn);
ssl3_ServerSendUseSRTPXtn);
}
/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension
@ -2267,9 +2306,6 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
return SECSuccess;
}
/* Keep track of negotiated extensions. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data,
&data->len);
if (rv != SECSuccess) {
@ -2278,6 +2314,7 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
/* Trailing data, empty value, or odd-length value is invalid. */
if (data->len != 0 || algorithms.len == 0 || (algorithms.len & 1) != 0) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
return SECFailure;
}
@ -2291,6 +2328,8 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
ss->ssl3.hs.clientSigAndHash =
PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms);
if (!ss->ssl3.hs.clientSigAndHash) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
return SECFailure;
}
ss->ssl3.hs.numClientSigAndHash = 0;
@ -2320,6 +2359,8 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
ss->ssl3.hs.clientSigAndHash = NULL;
}
/* Keep track of negotiated extensions. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
return SECSuccess;
}
@ -2483,41 +2524,32 @@ ssl3_ServerHandleDraftVersionXtn(sslSocket * ss, PRUint16 ex_type,
return SECSuccess;
}
if (data->len != 2)
goto loser;
if (data->len != 2) {
(void)ssl3_DecodeError(ss);
return SECFailure;
}
/* Get the draft version out of the handshake */
draft_version = ssl3_ConsumeHandshakeNumber(ss, 2,
&data->data, &data->len);
if (draft_version < 0) {
goto loser;
return SECFailure;
}
/* Keep track of negotiated extensions. */
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
/* Compare the version */
if (draft_version != TLS_1_3_DRAFT_VERSION) {
/*
* Incompatible/broken TLS 1.3 implementation. Fall back to TLS 1.2.
* TODO(ekr@rtfm.com): It's not entirely clear it's safe to roll back
* here. Need to double-check.
*/
SSL_TRC(30, ("%d: SSL3[%d]: Incompatible version of TLS 1.3 (%d), "
"expected %d",
SSL_GETPID(), ss->fd, draft_version, TLS_1_3_DRAFT_VERSION));
goto loser;
ss->version = SSL_LIBRARY_VERSION_TLS_1_2;
}
return SECSuccess;
loser:
/*
* Incompatible/broken TLS 1.3 implementation. Fall back to TLS 1.2.
* TODO(ekr@rtfm.com): It's not entirely clear it's safe to roll back
* here. Need to double-check.
* TODO(ekr@rtfm.com): Currently we fall back even on broken extensions.
* because SECFailure does not cause handshake failures. See bug
* 753136.
*/
SSL_TRC(30, ("%d: SSL3[%d]: Rolling back to TLS 1.2", SSL_GETPID(), ss->fd));
ss->version = SSL_LIBRARY_VERSION_TLS_1_2;
return SECSuccess;
}

View File

@ -981,6 +981,7 @@ struct ssl3StateStr {
PRUint16 dtlsSRTPCiphers[MAX_DTLS_SRTP_CIPHER_SUITES];
PRUint16 dtlsSRTPCipherCount;
PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
PRBool fatalAlertSent;
};
#define DTLS_MAX_MTU 1500 /* Ethernet MTU but without subtracting the

View File

@ -19,12 +19,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.18"
#define NSSUTIL_VERSION "3.18.1 Beta"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 18
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 2
#define NSSUTIL_BETA PR_FALSE
#define NSSUTIL_VPATCH 1
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_TRUE
SEC_BEGIN_PROTOS