summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-02-06 11:46:26 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-02-06 11:46:26 +0100
commitf017b749ea9f1586d2308504553d40bf4cc5439d (patch)
treec6033924a0de9be1ab140596e305898c651bf57e /security/nss/gtests/ssl_gtest
parent7c728b3c7680662fc4e92b5d03697b8339560b08 (diff)
downloadUXP-f017b749ea9f1586d2308504553d40bf4cc5439d.tar
UXP-f017b749ea9f1586d2308504553d40bf4cc5439d.tar.gz
UXP-f017b749ea9f1586d2308504553d40bf4cc5439d.tar.lz
UXP-f017b749ea9f1586d2308504553d40bf4cc5439d.tar.xz
UXP-f017b749ea9f1586d2308504553d40bf4cc5439d.zip
Update NSS to 3.32.1-RTM
Diffstat (limited to 'security/nss/gtests/ssl_gtest')
-rw-r--r--security/nss/gtests/ssl_gtest/Makefile5
-rw-r--r--security/nss/gtests/ssl_gtest/databuffer.h191
-rw-r--r--security/nss/gtests/ssl_gtest/gtest_utils.h2
-rw-r--r--security/nss/gtests/ssl_gtest/libssl_internals.c107
-rw-r--r--security/nss/gtests/ssl_gtest/libssl_internals.h16
-rw-r--r--security/nss/gtests/ssl_gtest/manifest.mn17
-rw-r--r--security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc281
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc199
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc28
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc173
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc83
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc45
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc64
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc100
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc16
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc30
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc6
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc34
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc568
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc157
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc187
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc143
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gtest.cc14
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gtest.gyp46
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc117
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc177
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc187
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc143
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc50
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc58
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_version_unittest.cc59
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc394
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.cc386
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.h97
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.cc375
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.h137
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.cc181
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.h86
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.cc326
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.h231
-rw-r--r--security/nss/gtests/ssl_gtest/tls_parser.cc73
-rw-r--r--security/nss/gtests/ssl_gtest/tls_parser.h131
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.cc145
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.h76
44 files changed, 4076 insertions, 1865 deletions
diff --git a/security/nss/gtests/ssl_gtest/Makefile b/security/nss/gtests/ssl_gtest/Makefile
index dfb8df943..a9a9290e0 100644
--- a/security/nss/gtests/ssl_gtest/Makefile
+++ b/security/nss/gtests/ssl_gtest/Makefile
@@ -33,11 +33,8 @@ ifdef NSS_SSL_ENABLE_ZLIB
include $(CORE_DEPTH)/coreconf/zlib.mk
endif
-ifndef NSS_ENABLE_TLS_1_3
-NSS_DISABLE_TLS_1_3=1
-endif
-
ifdef NSS_DISABLE_TLS_1_3
+NSS_DISABLE_TLS_1_3=1
# Run parameterized tests only, for which we can easily exclude TLS 1.3
CPPSRCS := $(filter-out $(shell grep -l '^TEST_F' $(CPPSRCS)), $(CPPSRCS))
CFLAGS += -DNSS_DISABLE_TLS_1_3
diff --git a/security/nss/gtests/ssl_gtest/databuffer.h b/security/nss/gtests/ssl_gtest/databuffer.h
deleted file mode 100644
index e7236d4e9..000000000
--- a/security/nss/gtests/ssl_gtest/databuffer.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/* -*- 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/. */
-
-#ifndef databuffer_h__
-#define databuffer_h__
-
-#include <algorithm>
-#include <cassert>
-#include <cstring>
-#include <iomanip>
-#include <iostream>
-#if defined(WIN32) || defined(WIN64)
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
-
-extern bool g_ssl_gtest_verbose;
-
-namespace nss_test {
-
-class DataBuffer {
- public:
- DataBuffer() : data_(nullptr), len_(0) {}
- DataBuffer(const uint8_t* data, size_t len) : data_(nullptr), len_(0) {
- Assign(data, len);
- }
- DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
- Assign(other);
- }
- ~DataBuffer() { delete[] data_; }
-
- DataBuffer& operator=(const DataBuffer& other) {
- if (&other != this) {
- Assign(other);
- }
- return *this;
- }
-
- void Allocate(size_t len) {
- delete[] data_;
- data_ = new uint8_t[len ? len : 1]; // Don't depend on new [0].
- len_ = len;
- }
-
- void Truncate(size_t len) { len_ = std::min(len_, len); }
-
- void Assign(const DataBuffer& other) { Assign(other.data(), other.len()); }
-
- void Assign(const uint8_t* data, size_t len) {
- if (data) {
- Allocate(len);
- memcpy(static_cast<void*>(data_), static_cast<const void*>(data), len);
- } else {
- assert(len == 0);
- data_ = nullptr;
- len_ = 0;
- }
- }
-
- // Write will do a new allocation and expand the size of the buffer if needed.
- // Returns the offset of the end of the write.
- size_t Write(size_t index, const uint8_t* val, size_t count) {
- assert(val);
- if (index + count > len_) {
- size_t newlen = index + count;
- uint8_t* tmp = new uint8_t[newlen]; // Always > 0.
- if (data_) {
- memcpy(static_cast<void*>(tmp), static_cast<const void*>(data_), len_);
- }
- if (index > len_) {
- memset(static_cast<void*>(tmp + len_), 0, index - len_);
- }
- delete[] data_;
- data_ = tmp;
- len_ = newlen;
- }
- if (data_) {
- memcpy(static_cast<void*>(data_ + index), static_cast<const void*>(val),
- count);
- }
- return index + count;
- }
-
- size_t Write(size_t index, const DataBuffer& buf) {
- return Write(index, buf.data(), buf.len());
- }
-
- // Write an integer, also performing host-to-network order conversion.
- // Returns the offset of the end of the write.
- size_t Write(size_t index, uint32_t val, size_t count) {
- assert(count <= sizeof(uint32_t));
- uint32_t nvalue = htonl(val);
- auto* addr = reinterpret_cast<const uint8_t*>(&nvalue);
- return Write(index, addr + sizeof(uint32_t) - count, count);
- }
-
- // This can't use the same trick as Write(), since we might be reading from a
- // smaller data source.
- bool Read(size_t index, size_t count, uint32_t* val) const {
- assert(count < sizeof(uint32_t));
- assert(val);
- if ((index > len()) || (count > (len() - index))) {
- return false;
- }
- *val = 0;
- for (size_t i = 0; i < count; ++i) {
- *val = (*val << 8) | data()[index + i];
- }
- return true;
- }
-
- // Starting at |index|, remove |remove| bytes and replace them with the
- // contents of |buf|.
- void Splice(const DataBuffer& buf, size_t index, size_t remove = 0) {
- Splice(buf.data(), buf.len(), index, remove);
- }
-
- void Splice(const uint8_t* ins, size_t ins_len, size_t index,
- size_t remove = 0) {
- assert(ins);
- uint8_t* old_value = data_;
- size_t old_len = len_;
-
- // The amount of stuff remaining from the tail of the old.
- size_t tail_len = old_len - std::min(old_len, index + remove);
- // The new length: the head of the old, the new, and the tail of the old.
- len_ = index + ins_len + tail_len;
- data_ = new uint8_t[len_ ? len_ : 1];
-
- // The head of the old.
- if (old_value) {
- Write(0, old_value, std::min(old_len, index));
- }
- // Maybe a gap.
- if (old_value && index > old_len) {
- memset(old_value + index, 0, index - old_len);
- }
- // The new.
- Write(index, ins, ins_len);
- // The tail of the old.
- if (tail_len > 0) {
- Write(index + ins_len, old_value + index + remove, tail_len);
- }
-
- delete[] old_value;
- }
-
- void Append(const DataBuffer& buf) { Splice(buf, len_); }
-
- const uint8_t* data() const { return data_; }
- uint8_t* data() { return data_; }
- size_t len() const { return len_; }
- bool empty() const { return len_ == 0; }
-
- private:
- uint8_t* data_;
- size_t len_;
-};
-
-static const size_t kMaxBufferPrint = 32;
-
-inline std::ostream& operator<<(std::ostream& stream, const DataBuffer& buf) {
- stream << "[" << buf.len() << "] ";
- for (size_t i = 0; i < buf.len(); ++i) {
- if (!g_ssl_gtest_verbose && i >= kMaxBufferPrint) {
- stream << "...";
- break;
- }
- stream << std::hex << std::setfill('0') << std::setw(2)
- << static_cast<unsigned>(buf.data()[i]);
- }
- stream << std::dec;
- return stream;
-}
-
-inline bool operator==(const DataBuffer& a, const DataBuffer& b) {
- return (a.empty() && b.empty()) ||
- (a.len() == b.len() && 0 == memcmp(a.data(), b.data(), a.len()));
-}
-
-inline bool operator!=(const DataBuffer& a, const DataBuffer& b) {
- return !(a == b);
-}
-
-} // namespace nss_test
-
-#endif
diff --git a/security/nss/gtests/ssl_gtest/gtest_utils.h b/security/nss/gtests/ssl_gtest/gtest_utils.h
index 3ecd96cbe..2344c3cea 100644
--- a/security/nss/gtests/ssl_gtest/gtest_utils.h
+++ b/security/nss/gtests/ssl_gtest/gtest_utils.h
@@ -34,7 +34,7 @@ class Timeout : public PollTarget {
bool timed_out() const { return !handle_; }
private:
- Poller::Timer* handle_;
+ std::shared_ptr<Poller::Timer> handle_;
};
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.c b/security/nss/gtests/ssl_gtest/libssl_internals.c
index 5136ee8ec..97b8354ae 100644
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -10,8 +10,7 @@
#include "nss.h"
#include "pk11pub.h"
#include "seccomon.h"
-#include "ssl.h"
-#include "sslimpl.h"
+#include "selfencrypt.h"
SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd) {
sslSocket *ss = ssl_FindSocket(fd);
@@ -35,15 +34,8 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
return SECFailure;
}
- SECStatus rv = ssl3_InitState(ss);
- if (rv != SECSuccess) {
- return rv;
- }
-
- rv = ssl3_RestartHandshakeHashes(ss);
- if (rv != SECSuccess) {
- return rv;
- }
+ ssl3_InitState(ss);
+ ssl3_RestartHandshakeHashes(ss);
// Ensure we don't overrun hs.client_random.
rnd_len = PR_MIN(SSL3_RANDOM_LENGTH, rnd_len);
@@ -64,18 +56,24 @@ PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
}
-void SSLInt_ClearSessionTicketKey() {
- ssl3_SessionTicketShutdown(NULL, NULL);
- NSS_UnregisterShutdown(ssl3_SessionTicketShutdown, NULL);
+void SSLInt_ClearSelfEncryptKey() { ssl_ResetSelfEncryptKeys(); }
+
+sslSelfEncryptKeys *ssl_GetSelfEncryptKeysInt();
+
+void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key) {
+ sslSelfEncryptKeys *keys = ssl_GetSelfEncryptKeysInt();
+
+ PK11_FreeSymKey(keys->macKey);
+ keys->macKey = key;
}
SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu) {
sslSocket *ss = ssl_FindSocket(fd);
- if (ss) {
- ss->ssl3.mtu = mtu;
- return SECSuccess;
+ if (!ss) {
+ return SECFailure;
}
- return SECFailure;
+ ss->ssl3.mtu = mtu;
+ return SECSuccess;
}
PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd) {
@@ -199,7 +197,9 @@ SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len) {
if (ss->xtnData.nextProto.data) {
SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
}
- if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) return SECFailure;
+ if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) {
+ return SECFailure;
+ }
PORT_Memcpy(ss->xtnData.nextProto.data, data, len);
return SECSuccess;
@@ -211,7 +211,7 @@ PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType) {
return PR_FALSE;
}
- return (PRBool)(!!ssl_FindServerCertByAuthType(ss, authType));
+ return (PRBool)(!!ssl_FindServerCert(ss, authType, NULL));
}
PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type) {
@@ -256,6 +256,7 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
return SECFailure;
}
if (to >= (1ULL << 48)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
@@ -267,6 +268,7 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
* scrub the entire structure on the assumption that the new sequence number
* is far enough past the last received sequence number. */
if (to <= spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
dtls_RecordSetRecvd(&spec->recvdRecords, to);
@@ -284,6 +286,7 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
return SECFailure;
}
if (to >= (1ULL << 48)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
@@ -314,6 +317,40 @@ SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
return groupDef->keaType;
}
+SECStatus SSLInt_SetCipherSpecChangeFunc(PRFileDesc *fd,
+ sslCipherSpecChangedFunc func,
+ void *arg) {
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ ss->ssl3.changedCipherSpecFunc = func;
+ ss->ssl3.changedCipherSpecArg = arg;
+
+ return SECSuccess;
+}
+
+static ssl3KeyMaterial *GetKeyingMaterial(PRBool isServer,
+ ssl3CipherSpec *spec) {
+ return isServer ? &spec->server : &spec->client;
+}
+
+PK11SymKey *SSLInt_CipherSpecToKey(PRBool isServer, ssl3CipherSpec *spec) {
+ return GetKeyingMaterial(isServer, spec)->write_key;
+}
+
+SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(PRBool isServer,
+ ssl3CipherSpec *spec) {
+ return spec->cipher_def->calg;
+}
+
+unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec) {
+ return GetKeyingMaterial(isServer, spec)->write_iv;
+}
+
SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd) {
sslSocket *ss;
@@ -335,6 +372,36 @@ SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result) {
}
*result = ss->ssl3.hs.shortHeaders;
+ return SECSuccess;
+}
+
+void SSLInt_SetTicketLifetime(uint32_t lifetime) {
+ ssl_ticket_lifetime = lifetime;
+}
+
+void SSLInt_SetMaxEarlyDataSize(uint32_t size) {
+ ssl_max_early_data_size = size;
+}
+
+SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ /* This only works when resuming. */
+ if (!ss->statelessResume) {
+ PORT_SetError(SEC_INTERNAL_ONLY);
+ return SECFailure;
+ }
+
+ /* Modifying both specs allows this to be used on either peer. */
+ ssl_GetSpecWriteLock(ss);
+ ss->ssl3.crSpec->earlyDataRemaining = size;
+ ss->ssl3.cwSpec->earlyDataRemaining = size;
+ ssl_ReleaseSpecWriteLock(ss);
return SECSuccess;
}
diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.h b/security/nss/gtests/ssl_gtest/libssl_internals.h
index 6ea66db81..33709c4b4 100644
--- a/security/nss/gtests/ssl_gtest/libssl_internals.h
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.h
@@ -11,6 +11,8 @@
#include "prio.h"
#include "seccomon.h"
+#include "ssl.h"
+#include "sslimpl.h"
#include "sslt.h"
SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd);
@@ -20,7 +22,8 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
size_t msg_len);
PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext);
-void SSLInt_ClearSessionTicketKey();
+void SSLInt_ClearSelfEncryptKey();
+void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key);
PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd);
void SSLInt_PrintTls13CipherSpecs(PRFileDesc *fd);
void SSLInt_ForceTimerExpiry(PRFileDesc *fd);
@@ -37,7 +40,18 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to);
SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
+
+SECStatus SSLInt_SetCipherSpecChangeFunc(PRFileDesc *fd,
+ sslCipherSpecChangedFunc func,
+ void *arg);
+PK11SymKey *SSLInt_CipherSpecToKey(PRBool isServer, ssl3CipherSpec *spec);
+SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(PRBool isServer,
+ ssl3CipherSpec *spec);
+unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec);
SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd);
SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result);
+void SSLInt_SetTicketLifetime(uint32_t lifetime);
+void SSLInt_SetMaxEarlyDataSize(uint32_t size);
+SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
#endif // ndef libssl_internals_h_
diff --git a/security/nss/gtests/ssl_gtest/manifest.mn b/security/nss/gtests/ssl_gtest/manifest.mn
index 391db813b..cc729c0f1 100644
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -24,7 +24,9 @@ CPPSRCS = \
ssl_ems_unittest.cc \
ssl_exporter_unittest.cc \
ssl_extension_unittest.cc \
+ ssl_fragment_unittest.cc \
ssl_fuzz_unittest.cc \
+ ssl_gather_unittest.cc \
ssl_gtest.cc \
ssl_hrr_unittest.cc \
ssl_loopback_unittest.cc \
@@ -34,21 +36,26 @@ CPPSRCS = \
ssl_staticrsa_unittest.cc \
ssl_v2_client_hello_unittest.cc \
ssl_version_unittest.cc \
+ ssl_versionpolicy_unittest.cc \
+ selfencrypt_unittest.cc \
test_io.cc \
tls_agent.cc \
tls_connect.cc \
tls_hkdf_unittest.cc \
tls_filter.cc \
- tls_parser.cc \
+ tls_protect.cc \
$(NULL)
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
- -I$(CORE_DEPTH)/gtests/common
+ -I$(CORE_DEPTH)/gtests/common \
+ -I$(CORE_DEPTH)/cpputil
-REQUIRES = nspr nss libdbm gtest
+REQUIRES = nspr nss libdbm gtest cpputil
PROGRAM = ssl_gtest
-EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
- $(DIST)/lib/$(LIB_PREFIX)softokn.$(LIB_SUFFIX)
+EXTRA_LIBS += \
+ $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)cpputil.$(LIB_SUFFIX) \
+ $(NULL)
USE_STATIC_LIBS = 1
diff --git a/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc b/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
new file mode 100644
index 000000000..4bae9dec9
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <functional>
+#include <memory>
+#include "nss.h"
+#include "pk11pub.h"
+#include "prerror.h"
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+extern "C" {
+#include "sslimpl.h"
+#include "selfencrypt.h"
+}
+
+#include "databuffer.h"
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+
+namespace nss_test {
+
+static const uint8_t kAesKey1Buf[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f};
+static const DataBuffer kAesKey1(kAesKey1Buf, sizeof(kAesKey1Buf));
+
+static const uint8_t kAesKey2Buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x1c, 0x1d, 0x1e, 0x1f};
+static const DataBuffer kAesKey2(kAesKey2Buf, sizeof(kAesKey2Buf));
+
+static const uint8_t kHmacKey1Buf[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
+static const DataBuffer kHmacKey1(kHmacKey1Buf, sizeof(kHmacKey1Buf));
+
+static const uint8_t kHmacKey2Buf[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
+ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f};
+static const DataBuffer kHmacKey2(kHmacKey2Buf, sizeof(kHmacKey2Buf));
+
+static const uint8_t* kKeyName1 =
+ reinterpret_cast<const unsigned char*>("KEY1KEY1KEY1KEY1");
+static const uint8_t* kKeyName2 =
+ reinterpret_cast<const uint8_t*>("KEY2KEY2KEY2KEY2");
+
+static void ImportKey(const DataBuffer& key, PK11SlotInfo* slot,
+ CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE cka,
+ ScopedPK11SymKey* to) {
+ SECItem key_item = {siBuffer, const_cast<uint8_t*>(key.data()),
+ static_cast<unsigned int>(key.len())};
+
+ PK11SymKey* inner =
+ PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, cka, &key_item, nullptr);
+ ASSERT_NE(nullptr, inner);
+ to->reset(inner);
+}
+
+extern "C" {
+extern char ssl_trace;
+extern FILE* ssl_trace_iob;
+}
+
+class SelfEncryptTestBase : public ::testing::Test {
+ public:
+ SelfEncryptTestBase(size_t message_size)
+ : aes1_(),
+ aes2_(),
+ hmac1_(),
+ hmac2_(),
+ message_(),
+ slot_(PK11_GetInternalSlot()) {
+ EXPECT_NE(nullptr, slot_);
+ char* ev = getenv("SSLTRACE");
+ if (ev && ev[0]) {
+ ssl_trace = atoi(ev);
+ ssl_trace_iob = stderr;
+ }
+ message_.Allocate(message_size);
+ for (size_t i = 0; i < message_.len(); ++i) {
+ message_.data()[i] = i;
+ }
+ }
+
+ void SetUp() {
+ message_.Allocate(100);
+ for (size_t i = 0; i < 100; ++i) {
+ message_.data()[i] = i;
+ }
+ ImportKey(kAesKey1, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes1_);
+ ImportKey(kAesKey2, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes2_);
+ ImportKey(kHmacKey1, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac1_);
+ ImportKey(kHmacKey2, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac2_);
+ }
+
+ void SelfTest(
+ const uint8_t* writeKeyName, const ScopedPK11SymKey& writeAes,
+ const ScopedPK11SymKey& writeHmac, const uint8_t* readKeyName,
+ const ScopedPK11SymKey& readAes, const ScopedPK11SymKey& readHmac,
+ PRErrorCode protect_error_code = 0, PRErrorCode unprotect_error_code = 0,
+ std::function<void(uint8_t* ciphertext, unsigned int* ciphertext_len)>
+ mutate = nullptr) {
+ uint8_t ciphertext[1000];
+ unsigned int ciphertext_len;
+ uint8_t plaintext[1000];
+ unsigned int plaintext_len;
+
+ SECStatus rv = ssl_SelfEncryptProtectInt(
+ writeAes.get(), writeHmac.get(), writeKeyName, message_.data(),
+ message_.len(), ciphertext, &ciphertext_len, sizeof(ciphertext));
+ if (rv != SECSuccess) {
+ std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl;
+ }
+ if (protect_error_code) {
+ ASSERT_EQ(protect_error_code, PORT_GetError());
+ return;
+ }
+ ASSERT_EQ(SECSuccess, rv);
+
+ if (mutate) {
+ mutate(ciphertext, &ciphertext_len);
+ }
+ rv = ssl_SelfEncryptUnprotectInt(readAes.get(), readHmac.get(), readKeyName,
+ ciphertext, ciphertext_len, plaintext,
+ &plaintext_len, sizeof(plaintext));
+ if (rv != SECSuccess) {
+ std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl;
+ }
+ if (!unprotect_error_code) {
+ ASSERT_EQ(SECSuccess, rv);
+ EXPECT_EQ(message_.len(), plaintext_len);
+ EXPECT_EQ(0, memcmp(message_.data(), plaintext, message_.len()));
+ } else {
+ ASSERT_EQ(SECFailure, rv);
+ EXPECT_EQ(unprotect_error_code, PORT_GetError());
+ }
+ }
+
+ protected:
+ ScopedPK11SymKey aes1_;
+ ScopedPK11SymKey aes2_;
+ ScopedPK11SymKey hmac1_;
+ ScopedPK11SymKey hmac2_;
+ DataBuffer message_;
+
+ private:
+ ScopedPK11SlotInfo slot_;
+};
+
+class SelfEncryptTestVariable : public SelfEncryptTestBase,
+ public ::testing::WithParamInterface<size_t> {
+ public:
+ SelfEncryptTestVariable() : SelfEncryptTestBase(GetParam()) {}
+};
+
+class SelfEncryptTest128 : public SelfEncryptTestBase {
+ public:
+ SelfEncryptTest128() : SelfEncryptTestBase(128) {}
+};
+
+TEST_P(SelfEncryptTestVariable, SuccessCase) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_);
+}
+
+TEST_P(SelfEncryptTestVariable, WrongMacKey) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac2_, 0,
+ SEC_ERROR_BAD_DATA);
+}
+
+TEST_P(SelfEncryptTestVariable, WrongKeyName) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName2, aes1_, hmac1_, 0,
+ SEC_ERROR_NOT_A_RECIPIENT);
+}
+
+TEST_P(SelfEncryptTestVariable, AddAByte) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ (*ciphertext_len)++;
+ });
+}
+
+TEST_P(SelfEncryptTestVariable, SubtractAByte) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ (*ciphertext_len)--;
+ });
+}
+
+TEST_P(SelfEncryptTestVariable, BogusIv) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ ciphertext[16]++;
+ });
+}
+
+TEST_P(SelfEncryptTestVariable, BogusCiphertext) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ ciphertext[32]++;
+ });
+}
+
+TEST_P(SelfEncryptTestVariable, BadMac) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ ciphertext[*ciphertext_len - 1]++;
+ });
+}
+
+TEST_F(SelfEncryptTest128, DISABLED_BadPadding) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes2_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA);
+}
+
+TEST_F(SelfEncryptTest128, ShortKeyName) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ *ciphertext_len = 15;
+ });
+}
+
+TEST_F(SelfEncryptTest128, ShortIv) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ *ciphertext_len = 31;
+ });
+}
+
+TEST_F(SelfEncryptTest128, ShortCiphertextLen) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ *ciphertext_len = 32;
+ });
+}
+
+TEST_F(SelfEncryptTest128, ShortCiphertext) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0,
+ SEC_ERROR_BAD_DATA,
+ [](uint8_t* ciphertext, unsigned int* ciphertext_len) {
+ *ciphertext_len -= 17;
+ });
+}
+
+TEST_F(SelfEncryptTest128, MacWithAESKeyEncrypt) {
+ SelfTest(kKeyName1, aes1_, aes1_, kKeyName1, aes1_, hmac1_,
+ SEC_ERROR_LIBRARY_FAILURE);
+}
+
+TEST_F(SelfEncryptTest128, AESWithMacKeyEncrypt) {
+ SelfTest(kKeyName1, hmac1_, hmac1_, kKeyName1, aes1_, hmac1_,
+ SEC_ERROR_INVALID_KEY);
+}
+
+TEST_F(SelfEncryptTest128, MacWithAESKeyDecrypt) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, aes1_, 0,
+ SEC_ERROR_LIBRARY_FAILURE);
+}
+
+TEST_F(SelfEncryptTest128, AESWithMacKeyDecrypt) {
+ SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, hmac1_, hmac1_, 0,
+ SEC_ERROR_INVALID_KEY);
+}
+
+INSTANTIATE_TEST_CASE_P(VariousSizes, SelfEncryptTestVariable,
+ ::testing::Values(0, 15, 16, 31, 255, 256, 257));
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
index cf5a27fed..85b7011a1 100644
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -155,6 +155,7 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttNoAlpnServer) {
client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a");
EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b, sizeof(b)));
client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b");
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
return true;
});
Handshake();
@@ -174,6 +175,7 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttNoAlpnClient) {
PRUint8 b[] = {'b'};
EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b, 1));
client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b");
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
return true;
});
Handshake();
@@ -200,4 +202,201 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpnChangeBoth) {
CheckAlpn("b");
}
+// The client should abort the connection when sending a 0-rtt handshake but
+// the servers responds with a TLS 1.2 ServerHello. (no app data sent)
+TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngrade) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ server_->Set0RttEnabled(true); // set ticket_allow_early_data
+ Connect();
+
+ SendReceive(); // Need to read so that we absorb the session tickets.
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+ client_->StartConnect();
+ server_->StartConnect();
+
+ // We will send the early data xtn without sending actual early data. Thus
+ // a 1.2 server shouldn't fail until the client sends an alert because the
+ // client sends end_of_early_data only after reading the server's flight.
+ client_->Set0RttEnabled(true);
+
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ }
+ client_->Handshake();
+ server_->Handshake();
+ ASSERT_TRUE_WAIT(
+ (client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000);
+
+ // DTLS will timeout as we bump the epoch when installing the early app data
+ // cipher suite. Thus the encrypted alert will be ignored.
+ if (variant_ == ssl_variant_stream) {
+ // The client sends an encrypted alert message.
+ ASSERT_TRUE_WAIT(
+ (server_->error_code() == SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA),
+ 2000);
+ }
+}
+
+// The client should abort the connection when sending a 0-rtt handshake but
+// the servers responds with a TLS 1.2 ServerHello. (with app data)
+TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ server_->Set0RttEnabled(true); // set ticket_allow_early_data
+ Connect();
+
+ SendReceive(); // Need to read so that we absorb the session tickets.
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+ client_->StartConnect();
+ server_->StartConnect();
+
+ // Send the early data xtn in the CH, followed by early app data. The server
+ // will fail right after sending its flight, when receiving the early data.
+ client_->Set0RttEnabled(true);
+ ZeroRttSendReceive(true, false, [this]() {
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ }
+ return true;
+ });
+
+ client_->Handshake();
+ server_->Handshake();
+ ASSERT_TRUE_WAIT(
+ (client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000);
+
+ // DTLS will timeout as we bump the epoch when installing the early app data
+ // cipher suite. Thus the encrypted alert will be ignored.
+ if (variant_ == ssl_variant_stream) {
+ // The server sends an alert when receiving the early app data record.
+ ASSERT_TRUE_WAIT(
+ (server_->error_code() == SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA),
+ 2000);
+ }
+}
+
+static void CheckEarlyDataLimit(const std::shared_ptr<TlsAgent>& agent,
+ size_t expected_size) {
+ SSLPreliminaryChannelInfo preinfo;
+ SECStatus rv =
+ SSL_GetPreliminaryChannelInfo(agent->ssl_fd(), &preinfo, sizeof(preinfo));
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(expected_size, static_cast<size_t>(preinfo.maxEarlyDataSize));
+}
+
+TEST_P(TlsConnectTls13, SendTooMuchEarlyData) {
+ const char* big_message = "0123456789abcdef";
+ const size_t short_size = strlen(big_message) - 1;
+ const PRInt32 short_length = static_cast<PRInt32>(short_size);
+ SSLInt_SetMaxEarlyDataSize(static_cast<PRUint32>(short_size));
+ SetupForZeroRtt();
+
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+
+ ExpectAlert(client_, kTlsAlertEndOfEarlyData);
+ client_->Handshake();
+ CheckEarlyDataLimit(client_, short_size);
+
+ PRInt32 sent;
+ // Writing more than the limit will succeed in TLS, but fail in DTLS.
+ if (variant_ == ssl_variant_stream) {
+ sent = PR_Write(client_->ssl_fd(), big_message,
+ static_cast<PRInt32>(strlen(big_message)));
+ } else {
+ sent = PR_Write(client_->ssl_fd(), big_message,
+ static_cast<PRInt32>(strlen(big_message)));
+ EXPECT_GE(0, sent);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ // Try an exact-sized write now.
+ sent = PR_Write(client_->ssl_fd(), big_message, short_length);
+ }
+ EXPECT_EQ(short_length, sent);
+
+ // Even a single octet write should now fail.
+ sent = PR_Write(client_->ssl_fd(), big_message, 1);
+ EXPECT_GE(0, sent);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ // Process the ClientHello and read 0-RTT.
+ server_->Handshake();
+ CheckEarlyDataLimit(server_, short_size);
+
+ std::vector<uint8_t> buf(short_size + 1);
+ PRInt32 read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
+ EXPECT_EQ(short_length, read);
+ EXPECT_EQ(0, memcmp(big_message, buf.data(), short_size));
+
+ // Second read fails.
+ read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
+ EXPECT_EQ(SECFailure, read);
+ EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+ SendReceive();
+}
+
+TEST_P(TlsConnectTls13, ReceiveTooMuchEarlyData) {
+ const size_t limit = 5;
+ SSLInt_SetMaxEarlyDataSize(limit);
+ SetupForZeroRtt();
+
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+ ExpectResumption(RESUME_TICKET);
+
+ client_->ExpectSendAlert(kTlsAlertEndOfEarlyData);
+ client_->Handshake(); // Send ClientHello
+ CheckEarlyDataLimit(client_, limit);
+
+ // Lift the limit on the client.
+ EXPECT_EQ(SECSuccess,
+ SSLInt_SetSocketMaxEarlyDataSize(client_->ssl_fd(), 1000));
+
+ // Send message
+ const char* message = "0123456789abcdef";
+ const PRInt32 message_len = static_cast<PRInt32>(strlen(message));
+ EXPECT_EQ(message_len, PR_Write(client_->ssl_fd(), message, message_len));
+
+ if (variant_ == ssl_variant_stream) {
+ // This error isn't fatal for DTLS.
+ ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+ }
+ server_->Handshake(); // Process ClientHello, send server flight.
+ server_->Handshake(); // Just to make sure that we don't read ahead.
+ CheckEarlyDataLimit(server_, limit);
+
+ // Attempt to read early data.
+ std::vector<uint8_t> buf(strlen(message) + 1);
+ EXPECT_GT(0, PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()));
+ if (variant_ == ssl_variant_stream) {
+ server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA);
+ }
+
+ client_->Handshake(); // Process the handshake.
+ client_->Handshake(); // Process the alert.
+ if (variant_ == ssl_variant_stream) {
+ client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
+ }
+}
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
index 0e6ddaef8..5035a338d 100644
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -56,6 +56,7 @@ static const char *k0RttData = "ABCDEF";
TEST_P(TlsAgentTest, EarlyFinished) {
DataBuffer buffer;
MakeTrivialHandshakeRecord(kTlsHandshakeFinished, 0, &buffer);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_FINISHED);
}
@@ -63,15 +64,14 @@ TEST_P(TlsAgentTest, EarlyFinished) {
TEST_P(TlsAgentTest, EarlyCertificateVerify) {
DataBuffer buffer;
MakeTrivialHandshakeRecord(kTlsHandshakeCertificateVerify, 0, &buffer);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
}
-TEST_P(TlsAgentTestClient, CannedHello) {
+TEST_P(TlsAgentTestClient13, CannedHello) {
DataBuffer buffer;
EnsureInit();
- agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
- SSL_LIBRARY_VERSION_TLS_1_3);
DataBuffer server_hello;
MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
sizeof(kCannedTls13ServerHello), &server_hello);
@@ -80,7 +80,7 @@ TEST_P(TlsAgentTestClient, CannedHello) {
ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
}
-TEST_P(TlsAgentTestClient, EncryptedExtensionsInClear) {
+TEST_P(TlsAgentTestClient13, EncryptedExtensionsInClear) {
DataBuffer server_hello;
MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
sizeof(kCannedTls13ServerHello), &server_hello);
@@ -92,8 +92,7 @@ TEST_P(TlsAgentTestClient, EncryptedExtensionsInClear) {
MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
server_hello.data(), server_hello.len(), &buffer);
EnsureInit();
- agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
- SSL_LIBRARY_VERSION_TLS_1_3);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
}
@@ -118,6 +117,7 @@ TEST_F(TlsAgentStreamTestClient, EncryptedExtensionsInClearTwoPieces) {
agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
SSL_LIBRARY_VERSION_TLS_1_3);
ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
}
@@ -148,6 +148,7 @@ TEST_F(TlsAgentDgramTestClient, EncryptedExtensionsInClearTwoPieces) {
agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
SSL_LIBRARY_VERSION_TLS_1_3);
ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
}
@@ -158,8 +159,8 @@ TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
SSL_LIBRARY_VERSION_TLS_1_3);
agent_->StartConnect();
agent_->Set0RttEnabled(true);
- auto filter =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeClientHello);
+ auto filter = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeClientHello);
agent_->SetPacketFilter(filter);
PRInt32 rv = PR_Write(agent_->ssl_fd(), k0RttData, strlen(k0RttData));
EXPECT_EQ(-1, rv);
@@ -178,6 +179,7 @@ TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenRead) {
MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
reinterpret_cast<const uint8_t *>(k0RttData), strlen(k0RttData),
&buffer);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(buffer, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
}
@@ -198,13 +200,19 @@ TEST_F(TlsAgentStreamTestServer, Set0RttOptionClientHelloThenRead) {
MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
reinterpret_cast<const uint8_t *>(k0RttData), strlen(k0RttData),
&buffer);
+ ExpectAlert(kTlsAlertBadRecordMac);
ProcessMessage(buffer, TlsAgent::STATE_ERROR, SSL_ERROR_BAD_MAC_READ);
}
INSTANTIATE_TEST_CASE_P(
AgentTests, TlsAgentTest,
::testing::Combine(TlsAgentTestBase::kTlsRolesAll,
- TlsConnectTestBase::kTlsModesStream));
+ TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(ClientTests, TlsAgentTestClient,
- TlsConnectTestBase::kTlsModesAll);
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsVAll));
+INSTANTIATE_TEST_CASE_P(ClientTests13, TlsAgentTestClient13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
index d663d81e0..dbcbc9aa3 100644
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -77,9 +77,10 @@ TEST_P(TlsConnectGeneric, ClientAuthBigRsa) {
}
// Offset is the position in the captured buffer where the signature sits.
-static void CheckSigScheme(TlsInspectorRecordHandshakeMessage* capture,
- size_t offset, TlsAgent* peer,
- uint16_t expected_scheme, size_t expected_size) {
+static void CheckSigScheme(
+ std::shared_ptr<TlsInspectorRecordHandshakeMessage>& capture, size_t offset,
+ std::shared_ptr<TlsAgent>& peer, uint16_t expected_scheme,
+ size_t expected_size) {
EXPECT_LT(offset + 2U, capture->buffer().len());
uint32_t scheme = 0;
@@ -95,8 +96,8 @@ static void CheckSigScheme(TlsInspectorRecordHandshakeMessage* capture,
// in the default certificate.
TEST_P(TlsConnectTls12, ServerAuthCheckSigAlg) {
EnsureTlsSetup();
- auto capture_ske =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+ auto capture_ske = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerKeyExchange);
server_->SetPacketFilter(capture_ske);
Connect();
CheckKeys();
@@ -114,7 +115,8 @@ TEST_P(TlsConnectTls12, ServerAuthCheckSigAlg) {
TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) {
EnsureTlsSetup();
auto capture_cert_verify =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify);
+ std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeCertificateVerify);
client_->SetPacketFilter(capture_cert_verify);
client_->SetupClientAuth();
server_->RequestClientAuth(true);
@@ -127,7 +129,8 @@ TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) {
TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) {
Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048);
auto capture_cert_verify =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify);
+ std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeCertificateVerify);
client_->SetPacketFilter(capture_cert_verify);
client_->SetupClientAuth();
server_->RequestClientAuth(true);
@@ -136,6 +139,76 @@ TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) {
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_sha256, 2048);
}
+class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter {
+ public:
+ virtual PacketFilter::Action FilterHandshake(
+ const TlsHandshakeFilter::HandshakeHeader& header,
+ const DataBuffer& input, DataBuffer* output) {
+ if (header.handshake_type() != kTlsHandshakeCertificateRequest) {
+ return KEEP;
+ }
+
+ TlsParser parser(input);
+ std::cerr << "Zeroing CertReq.supported_signature_algorithms" << std::endl;
+
+ DataBuffer cert_types;
+ if (!parser.ReadVariable(&cert_types, 1)) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+
+ if (!parser.SkipVariable(2)) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+
+ DataBuffer cas;
+ if (!parser.ReadVariable(&cas, 2)) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+
+ size_t idx = 0;
+
+ // Write certificate types.
+ idx = output->Write(idx, cert_types.len(), 1);
+ idx = output->Write(idx, cert_types);
+
+ // Write zero signature algorithms.
+ idx = output->Write(idx, 0U, 2);
+
+ // Write certificate authorities.
+ idx = output->Write(idx, cas.len(), 2);
+ idx = output->Write(idx, cas);
+
+ return CHANGE;
+ }
+};
+
+// Check that we fall back to SHA-1 when the server doesn't provide any
+// supported_signature_algorithms in the CertificateRequest message.
+TEST_P(TlsConnectTls12, ClientAuthNoSigAlgsFallback) {
+ EnsureTlsSetup();
+ auto filter = std::make_shared<TlsZeroCertificateRequestSigAlgsFilter>();
+ server_->SetPacketFilter(filter);
+ auto capture_cert_verify =
+ std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeCertificateVerify);
+ client_->SetPacketFilter(capture_cert_verify);
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
+
+ // We're expecting a bad signature here because we tampered with a handshake
+ // message (CertReq). Previously, without the SHA-1 fallback, we would've
+ // seen a malformed record alert.
+ server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+ client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+
+ CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pkcs1_sha1, 1024);
+}
+
static const SSLSignatureScheme SignatureSchemeEcdsaSha384[] = {
ssl_sig_ecdsa_secp384r1_sha384};
static const SSLSignatureScheme SignatureSchemeEcdsaSha256[] = {
@@ -211,7 +284,7 @@ TEST_P(TlsConnectTls13, SignatureSchemeCurveMismatch) {
Reset(TlsAgent::kServerEcdsa256);
client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -229,7 +302,7 @@ TEST_P(TlsConnectTls13, SignatureSchemeBadConfig) {
Reset(TlsAgent::kServerEcdsa256); // P-256 cert can't be used.
server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -252,7 +325,7 @@ TEST_P(TlsConnectTls12Plus, SignatureAlgorithmNoOverlapEcdsa) {
PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384));
server_->SetSignatureSchemes(SignatureSchemeEcdsaSha256,
PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
}
@@ -270,8 +343,8 @@ TEST_P(TlsConnectPre12, SignatureAlgorithmNoOverlapEcdsa) {
// The signature_algorithms extension is mandatory in TLS 1.3.
TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) {
client_->SetPacketFilter(
- new TlsExtensionDropper(ssl_signature_algorithms_xtn));
- ConnectExpectFail();
+ std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
}
@@ -280,8 +353,8 @@ TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) {
// only fails when the Finished is checked.
TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) {
client_->SetPacketFilter(
- new TlsExtensionDropper(ssl_signature_algorithms_xtn));
- ConnectExpectFail();
+ std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
@@ -298,7 +371,8 @@ class BeforeFinished : public TlsRecordFilter {
enum HandshakeState { BEFORE_CCS, AFTER_CCS, DONE };
public:
- BeforeFinished(TlsAgent* client, TlsAgent* server, VoidFunction before_ccs,
+ BeforeFinished(std::shared_ptr<TlsAgent>& client,
+ std::shared_ptr<TlsAgent>& server, VoidFunction before_ccs,
VoidFunction before_finished)
: client_(client),
server_(server),
@@ -307,7 +381,7 @@ class BeforeFinished : public TlsRecordFilter {
state_(BEFORE_CCS) {}
protected:
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& body,
DataBuffer* out) {
switch (state_) {
@@ -321,8 +395,8 @@ class BeforeFinished : public TlsRecordFilter {
// but that means that they both get processed together.
DataBuffer ccs;
header.Write(&ccs, 0, body);
- server_->SendDirect(ccs);
- client_->Handshake();
+ server_.lock()->SendDirect(ccs);
+ client_.lock()->Handshake();
state_ = AFTER_CCS;
// Request that the original record be dropped by the filter.
return DROP;
@@ -345,8 +419,8 @@ class BeforeFinished : public TlsRecordFilter {
}
private:
- TlsAgent* client_;
- TlsAgent* server_;
+ std::weak_ptr<TlsAgent> client_;
+ std::weak_ptr<TlsAgent> server_;
VoidFunction before_ccs_;
VoidFunction before_finished_;
HandshakeState state_;
@@ -371,7 +445,8 @@ class BeforeFinished13 : public PacketFilter {
};
public:
- BeforeFinished13(TlsAgent* client, TlsAgent* server,
+ BeforeFinished13(std::shared_ptr<TlsAgent>& client,
+ std::shared_ptr<TlsAgent>& server,
VoidFunction before_finished)
: client_(client),
server_(server),
@@ -385,7 +460,7 @@ class BeforeFinished13 : public PacketFilter {
case 1:
// Packet 1 is the server's entire first flight. Drop it.
EXPECT_EQ(SECSuccess,
- SSLInt_SetMTU(server_->ssl_fd(), input.len() - 1));
+ SSLInt_SetMTU(server_.lock()->ssl_fd(), input.len() - 1));
return DROP;
// Packet 2 is the first part of the server's retransmitted first
@@ -395,7 +470,7 @@ class BeforeFinished13 : public PacketFilter {
// Packet 3 is the second part of the server's retransmitted first
// flight. Before passing that on, make sure that the client processes
// packet 2, then call the before_finished_() callback.
- client_->Handshake();
+ client_.lock()->Handshake();
before_finished_();
break;
@@ -406,8 +481,8 @@ class BeforeFinished13 : public PacketFilter {
}
private:
- TlsAgent* client_;
- TlsAgent* server_;
+ std::weak_ptr<TlsAgent> client_;
+ std::weak_ptr<TlsAgent> server_;
VoidFunction before_finished_;
size_t records_;
};
@@ -421,9 +496,11 @@ static SECStatus AuthCompleteBlock(TlsAgent*, PRBool, PRBool) {
// processed by the client, SSL_AuthCertificateComplete() is called.
TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
- server_->SetPacketFilter(new BeforeFinished13(client_, server_, [this]() {
- EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
- }));
+ server_->SetPacketFilter(
+ std::make_shared<BeforeFinished13>(client_, server_, [this]() {
+ EXPECT_EQ(SECSuccess,
+ SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
+ }));
Connect();
}
@@ -440,9 +517,9 @@ static void TriggerAuthComplete(PollTarget* target, Event event) {
TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) {
client_->SetAuthCertificateCallback(
[this](TlsAgent*, PRBool, PRBool) -> SECStatus {
- Poller::Timer* timer_handle;
+ std::shared_ptr<Poller::Timer> timer_handle;
// This is really just to unroll the stack.
- Poller::Instance()->SetTimer(1U, client_, TriggerAuthComplete,
+ Poller::Instance()->SetTimer(1U, client_.get(), TriggerAuthComplete,
&timer_handle);
return SECWouldBlock;
});
@@ -451,7 +528,7 @@ TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) {
TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) {
client_->EnableFalseStart();
- server_->SetPacketFilter(new BeforeFinished(
+ server_->SetPacketFilter(std::make_shared<BeforeFinished>(
client_, server_,
[this]() { EXPECT_TRUE(client_->can_falsestart_hook_called()); },
[this]() {
@@ -467,7 +544,7 @@ TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) {
TEST_P(TlsConnectGenericPre13, AuthCompleteBeforeFinishedWithFalseStart) {
client_->EnableFalseStart();
client_->SetAuthCertificateCallback(AuthCompleteBlock);
- server_->SetPacketFilter(new BeforeFinished(
+ server_->SetPacketFilter(std::make_shared<BeforeFinished>(
client_, server_,
[]() {
// Do nothing before CCS
@@ -514,7 +591,7 @@ TEST_P(TlsConnectGenericPre13, AuthCompleteDelayed) {
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
// The client should send nothing from here on.
- client_->SetPacketFilter(new EnforceNoActivity());
+ client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
@@ -525,7 +602,7 @@ TEST_P(TlsConnectGenericPre13, AuthCompleteDelayed) {
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
// Remove this before closing or the close_notify alert will trigger it.
- client_->SetPacketFilter(nullptr);
+ client_->DeletePacketFilter();
}
// TLS 1.3 handles a delayed AuthComplete callback differently since the
@@ -541,12 +618,12 @@ TEST_P(TlsConnectTls13, AuthCompleteDelayed) {
EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
// The client will send nothing until AuthCertificateComplete is called.
- client_->SetPacketFilter(new EnforceNoActivity());
+ client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// This should allow the handshake to complete now.
- client_->SetPacketFilter(nullptr);
+ client_->DeletePacketFilter();
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
client_->Handshake(); // Send Finished
server_->Handshake(); // Transition to connected and send NewSessionTicket
@@ -639,8 +716,8 @@ TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPss) {
&ServerCertDataRsaPss));
}
-// mode, version, certificate, auth type, signature scheme
-typedef std::tuple<std::string, uint16_t, std::string, SSLAuthType,
+// variant, version, certificate, auth type, signature scheme
+typedef std::tuple<SSLProtocolVariant, uint16_t, std::string, SSLAuthType,
SSLSignatureScheme>
SignatureSchemeProfile;
@@ -655,7 +732,7 @@ class TlsSignatureSchemeConfiguration
signature_scheme_(std::get<4>(GetParam())) {}
protected:
- void TestSignatureSchemeConfig(TlsAgent* configPeer) {
+ void TestSignatureSchemeConfig(std::shared_ptr<TlsAgent>& configPeer) {
EnsureTlsSetup();
configPeer->SetSignatureSchemes(&signature_scheme_, 1);
Connect();
@@ -675,8 +752,8 @@ TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigServer) {
TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigClient) {
Reset(certificate_);
- TlsExtensionCapture* capture =
- new TlsExtensionCapture(ssl_signature_algorithms_xtn);
+ auto capture =
+ std::make_shared<TlsExtensionCapture>(ssl_signature_algorithms_xtn);
client_->SetPacketFilter(capture);
TestSignatureSchemeConfig(client_);
@@ -701,7 +778,7 @@ TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigBoth) {
INSTANTIATE_TEST_CASE_P(
SignatureSchemeRsa, TlsSignatureSchemeConfiguration,
::testing::Combine(
- TlsConnectTestBase::kTlsModesAll, TlsConnectTestBase::kTlsV12Plus,
+ TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerRsaSign),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384,
@@ -710,42 +787,42 @@ INSTANTIATE_TEST_CASE_P(
// PSS with SHA-512 needs a bigger key to work.
INSTANTIATE_TEST_CASE_P(
SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kRsa2048),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pss_sha512)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeRsaSha1, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12,
::testing::Values(TlsAgent::kServerRsa),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pkcs1_sha1)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeEcdsaP256, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa256),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp256r1_sha256)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeEcdsaP384, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa384),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp384r1_sha384)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeEcdsaP521, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa521),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp521r1_sha512)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeEcdsaSha1, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12,
::testing::Values(TlsAgent::kServerEcdsa256,
TlsAgent::kServerEcdsa384),
diff --git a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
index 876c36881..3463782e0 100644
--- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -23,9 +23,10 @@ namespace nss_test {
// by the relevant callbacks on the client.
class SignedCertificateTimestampsExtractor {
public:
- SignedCertificateTimestampsExtractor(TlsAgent* client) : client_(client) {
- client_->SetAuthCertificateCallback(
- [&](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus {
+ SignedCertificateTimestampsExtractor(std::shared_ptr<TlsAgent>& client)
+ : client_(client) {
+ client->SetAuthCertificateCallback(
+ [this](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus {
const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
EXPECT_TRUE(scts);
if (!scts) {
@@ -34,7 +35,7 @@ class SignedCertificateTimestampsExtractor {
auth_timestamps_.reset(new DataBuffer(scts->data, scts->len));
return SECSuccess;
});
- client_->SetHandshakeCallback([&](TlsAgent* agent) {
+ client->SetHandshakeCallback([this](TlsAgent* agent) {
const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
ASSERT_TRUE(scts);
handshake_timestamps_.reset(new DataBuffer(scts->data, scts->len));
@@ -48,12 +49,13 @@ class SignedCertificateTimestampsExtractor {
EXPECT_TRUE(handshake_timestamps_);
EXPECT_EQ(timestamps, *handshake_timestamps_);
- const SECItem* current = SSL_PeerSignedCertTimestamps(client_->ssl_fd());
+ const SECItem* current =
+ SSL_PeerSignedCertTimestamps(client_.lock()->ssl_fd());
EXPECT_EQ(timestamps, DataBuffer(current->data, current->len));
}
private:
- TlsAgent* client_;
+ std::weak_ptr<TlsAgent> client_;
std::unique_ptr<DataBuffer> auth_timestamps_;
std::unique_ptr<DataBuffer> handshake_timestamps_;
};
@@ -62,10 +64,22 @@ static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
sizeof(kSctValue)};
static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
+static const SSLExtraServerCertData kExtraSctData = {ssl_auth_null, nullptr,
+ nullptr, &kSctItem};
// Test timestamps extraction during a successful handshake.
-TEST_P(TlsConnectGeneric, SignedCertificateTimestampsHandshake) {
+TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) {
EnsureTlsSetup();
+
+ // We have to use the legacy API consistently here for configuring certs.
+ // Also, this doesn't work in TLS 1.3 because this only configures the SCT for
+ // RSA decrypt and PKCS#1 signing, not PSS.
+ ScopedCERTCertificate cert;
+ ScopedSECKEYPrivateKey priv;
+ ASSERT_TRUE(TlsAgent::LoadCertificate(TlsAgent::kServerRsa, &cert, &priv));
+ EXPECT_EQ(SECSuccess, SSL_ConfigSecureServerWithCertChain(
+ server_->ssl_fd(), cert.get(), nullptr, priv.get(),
+ ssl_kea_rsa));
EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
&kSctItem, ssl_kea_rsa));
EXPECT_EQ(SECSuccess,
@@ -78,13 +92,10 @@ TEST_P(TlsConnectGeneric, SignedCertificateTimestampsHandshake) {
timestamps_extractor.assertTimestamps(kSctBuffer);
}
-TEST_P(TlsConnectGeneric, SignedCertificateTimestampsConfig) {
- static const SSLExtraServerCertData kExtraData = {ssl_auth_rsa_sign, nullptr,
- nullptr, &kSctItem};
-
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsSuccess) {
EnsureTlsSetup();
EXPECT_TRUE(
- server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraData));
+ server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData));
EXPECT_EQ(SECSuccess,
SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
PR_TRUE));
@@ -99,8 +110,8 @@ TEST_P(TlsConnectGeneric, SignedCertificateTimestampsConfig) {
// when the client / the server / both have not enabled the feature.
TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveClient) {
EnsureTlsSetup();
- EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
- &kSctItem, ssl_kea_rsa));
+ EXPECT_TRUE(
+ server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData));
SignedCertificateTimestampsExtractor timestamps_extractor(client_);
Connect();
@@ -141,8 +152,8 @@ static const SECItem kOcspItems[] = {
{siBuffer, const_cast<uint8_t*>(kOcspValue2), sizeof(kOcspValue2)}};
static const SECItemArray kOcspResponses = {const_cast<SECItem*>(kOcspItems),
PR_ARRAY_SIZE(kOcspItems)};
-const static SSLExtraServerCertData kOcspExtraData = {
- ssl_auth_rsa_sign, nullptr, &kOcspResponses, nullptr};
+const static SSLExtraServerCertData kOcspExtraData = {ssl_auth_null, nullptr,
+ &kOcspResponses, nullptr};
TEST_P(TlsConnectGeneric, NoOcsp) {
EnsureTlsSetup();
@@ -176,10 +187,10 @@ TEST_P(TlsConnectGenericPre13, OcspMangled) {
server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData));
static const uint8_t val[] = {1};
- auto replacer = new TlsExtensionReplacer(ssl_cert_status_xtn,
- DataBuffer(val, sizeof(val)));
+ auto replacer = std::make_shared<TlsExtensionReplacer>(
+ ssl_cert_status_xtn, DataBuffer(val, sizeof(val)));
server_->SetPacketFilter(replacer);
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
@@ -188,7 +199,8 @@ TEST_P(TlsConnectGeneric, OcspSuccess) {
EnsureTlsSetup();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
- auto capture_ocsp = new TlsExtensionCapture(ssl_cert_status_xtn);
+ auto capture_ocsp =
+ std::make_shared<TlsExtensionCapture>(ssl_cert_status_xtn);
server_->SetPacketFilter(capture_ocsp);
// The value should be available during the AuthCertificateCallback
@@ -211,4 +223,35 @@ TEST_P(TlsConnectGeneric, OcspSuccess) {
EXPECT_EQ(0U, capture_ocsp->extension().len());
}
+TEST_P(TlsConnectGeneric, OcspHugeSuccess) {
+ EnsureTlsSetup();
+ EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
+
+ uint8_t hugeOcspValue[16385];
+ memset(hugeOcspValue, 0xa1, sizeof(hugeOcspValue));
+ const SECItem hugeOcspItems[] = {
+ {siBuffer, const_cast<uint8_t*>(hugeOcspValue), sizeof(hugeOcspValue)}};
+ const SECItemArray hugeOcspResponses = {const_cast<SECItem*>(hugeOcspItems),
+ PR_ARRAY_SIZE(hugeOcspItems)};
+ const SSLExtraServerCertData hugeOcspExtraData = {
+ ssl_auth_null, nullptr, &hugeOcspResponses, nullptr};
+
+ // The value should be available during the AuthCertificateCallback
+ client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig,
+ bool isServer) -> SECStatus {
+ const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd());
+ if (!ocsp) {
+ return SECFailure;
+ }
+ EXPECT_EQ(1U, ocsp->len) << "We only provide the first item";
+ EXPECT_EQ(0, SECITEM_CompareItem(&hugeOcspItems[0], &ocsp->items[0]));
+ return SECSuccess;
+ });
+ EXPECT_TRUE(server_->ConfigServerCert(TlsAgent::kServerRsa, true,
+ &hugeOcspExtraData));
+
+ Connect();
+}
+
} // namespace nspr_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
index ab10a84a0..85c30b2bf 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -22,17 +22,17 @@ extern "C" {
namespace nss_test {
-// mode, version, cipher suite
-typedef std::tuple<std::string, uint16_t, uint16_t, SSLNamedGroup,
+// variant, version, cipher suite
+typedef std::tuple<SSLProtocolVariant, uint16_t, uint16_t, SSLNamedGroup,
SSLSignatureScheme>
CipherSuiteProfile;
class TlsCipherSuiteTestBase : public TlsConnectTestBase {
public:
- TlsCipherSuiteTestBase(const std::string &mode, uint16_t version,
+ TlsCipherSuiteTestBase(SSLProtocolVariant variant, uint16_t version,
uint16_t cipher_suite, SSLNamedGroup group,
SSLSignatureScheme signature_scheme)
- : TlsConnectTestBase(mode, version),
+ : TlsConnectTestBase(variant, version),
cipher_suite_(cipher_suite),
group_(group),
signature_scheme_(signature_scheme),
@@ -128,16 +128,22 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
Connect();
SendReceive();
- // Check that we used the right cipher suite.
+ // Check that we used the right cipher suite, auth type and kea type.
uint16_t actual;
- EXPECT_TRUE(client_->cipher_suite(&actual) && actual == cipher_suite_);
- EXPECT_TRUE(server_->cipher_suite(&actual) && actual == cipher_suite_);
+ EXPECT_TRUE(client_->cipher_suite(&actual));
+ EXPECT_EQ(cipher_suite_, actual);
+ EXPECT_TRUE(server_->cipher_suite(&actual));
+ EXPECT_EQ(cipher_suite_, actual);
SSLAuthType auth;
- EXPECT_TRUE(client_->auth_type(&auth) && auth == auth_type_);
- EXPECT_TRUE(server_->auth_type(&auth) && auth == auth_type_);
+ EXPECT_TRUE(client_->auth_type(&auth));
+ EXPECT_EQ(auth_type_, auth);
+ EXPECT_TRUE(server_->auth_type(&auth));
+ EXPECT_EQ(auth_type_, auth);
SSLKEAType kea;
- EXPECT_TRUE(client_->kea_type(&kea) && kea == kea_type_);
- EXPECT_TRUE(server_->kea_type(&kea) && kea == kea_type_);
+ EXPECT_TRUE(client_->kea_type(&kea));
+ EXPECT_EQ(kea_type_, kea);
+ EXPECT_TRUE(server_->kea_type(&kea));
+ EXPECT_EQ(kea_type_, kea);
}
// Get the expected limit on the number of records that can be sent for the
@@ -252,14 +258,17 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) {
// authentication tag.
static const uint8_t payload[18] = {6};
DataBuffer record;
- uint64_t epoch = 0;
- if (mode_ == DGRAM) {
- epoch++;
+ uint64_t epoch;
+ if (variant_ == ssl_variant_datagram) {
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
- epoch++;
+ epoch = 3; // Application traffic keys.
+ } else {
+ epoch = 1;
}
+ } else {
+ epoch = 0;
}
- TlsAgentTestBase::MakeRecord(mode_, kTlsApplicationDataType, version_,
+ TlsAgentTestBase::MakeRecord(variant_, kTlsApplicationDataType, version_,
payload, sizeof(payload), &record,
(epoch << 48) | record_limit());
server_->adapter()->PacketReceived(record);
@@ -287,7 +296,7 @@ TEST_P(TlsCipherSuiteTest, WriteLimit) {
k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr); \
INSTANTIATE_TEST_CASE_P( \
CipherSuite##name, TlsCipherSuiteTest, \
- ::testing::Combine(TlsConnectTestBase::kTlsModes##modes, \
+ ::testing::Combine(TlsConnectTestBase::kTlsVariants##modes, \
TlsConnectTestBase::kTls##versions, k##name##Ciphers, \
groups, sigalgs));
@@ -396,7 +405,7 @@ class SecurityStatusTest
public ::testing::WithParamInterface<SecStatusParams> {
public:
SecurityStatusTest()
- : TlsCipherSuiteTestBase("TLS", GetParam().version,
+ : TlsCipherSuiteTestBase(ssl_variant_stream, GetParam().version,
GetParam().cipher_suite, ssl_grp_none,
ssl_sig_none) {}
};
diff --git a/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
index 9dadcbdf6..69fd00331 100644
--- a/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
@@ -33,12 +33,14 @@ TEST_F(TlsConnectTest, DamageSecretHandleClientFinished) {
client_->StartConnect();
client_->Handshake();
server_->Handshake();
- std::cerr << "Damaging HS secret\n";
+ std::cerr << "Damaging HS secret" << std::endl;
SSLInt_DamageClientHsTrafficSecret(server_->ssl_fd());
client_->Handshake();
- server_->Handshake();
// The client thinks it has connected.
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+
+ ExpectAlert(server_, kTlsAlertDecryptError);
+ server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
@@ -49,7 +51,10 @@ TEST_F(TlsConnectTest, DamageSecretHandleServerFinished) {
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_3);
- server_->SetPacketFilter(new AfterRecordN(
+ client_->ExpectSendAlert(kTlsAlertDecryptError);
+ // The server can't read the client's alert, so it also sends an alert.
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->SetPacketFilter(std::make_shared<AfterRecordN>(
server_, client_,
0, // ServerHello.
[this]() { SSLInt_DamageServerHsTrafficSecret(client_->ssl_fd()); }));
@@ -58,4 +63,57 @@ TEST_F(TlsConnectTest, DamageSecretHandleServerFinished) {
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
}
+TEST_P(TlsConnectGenericPre13, DamageServerSignature) {
+ EnsureTlsSetup();
+ auto filter =
+ std::make_shared<TlsLastByteDamager>(kTlsHandshakeServerKeyExchange);
+ server_->SetTlsRecordFilter(filter);
+ ExpectAlert(client_, kTlsAlertDecryptError);
+ ConnectExpectFail();
+ client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+ server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+}
+
+TEST_P(TlsConnectTls13, DamageServerSignature) {
+ EnsureTlsSetup();
+ auto filter =
+ std::make_shared<TlsLastByteDamager>(kTlsHandshakeCertificateVerify);
+ server_->SetTlsRecordFilter(filter);
+ filter->EnableDecryption();
+ client_->ExpectSendAlert(kTlsAlertDecryptError);
+ // The server can't read the client's alert, so it also sends an alert.
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+ } else {
+ ConnectExpectFailOneSide(TlsAgent::CLIENT);
+ }
+ client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+}
+
+TEST_P(TlsConnectGeneric, DamageClientSignature) {
+ EnsureTlsSetup();
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+ auto filter =
+ std::make_shared<TlsLastByteDamager>(kTlsHandshakeCertificateVerify);
+ client_->SetTlsRecordFilter(filter);
+ server_->ExpectSendAlert(kTlsAlertDecryptError);
+ filter->EnableDecryption();
+ // Do these handshakes by hand to avoid race condition on
+ // the client processing the server's alert.
+ client_->StartConnect();
+ server_->StartConnect();
+ client_->Handshake();
+ server_->Handshake();
+ client_->Handshake();
+ server_->Handshake();
+ EXPECT_EQ(version_ >= SSL_LIBRARY_VERSION_TLS_1_3
+ ? TlsAgent::STATE_CONNECTED
+ : TlsAgent::STATE_CONNECTING,
+ client_->state());
+ server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+}
+
} // namespace nspr_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
index 82d55586b..97943303a 100644
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -31,12 +31,13 @@ TEST_P(TlsConnectTls13, SharesForBothEcdheAndDhe) {
EnsureTlsSetup();
client_->ConfigNamedGroups(kAllDHEGroups);
- auto groups_capture = new TlsExtensionCapture(ssl_supported_groups_xtn);
- auto shares_capture = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
- std::vector<PacketFilter*> captures;
- captures.push_back(groups_capture);
- captures.push_back(shares_capture);
- client_->SetPacketFilter(new ChainedPacketFilter(captures));
+ auto groups_capture =
+ std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+ auto shares_capture =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+ std::vector<std::shared_ptr<PacketFilter>> captures = {groups_capture,
+ shares_capture};
+ client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
Connect();
@@ -60,12 +61,13 @@ TEST_P(TlsConnectGeneric, ConnectFfdheClient) {
EnableOnlyDheCiphers();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
- auto groups_capture = new TlsExtensionCapture(ssl_supported_groups_xtn);
- auto shares_capture = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
- std::vector<PacketFilter*> captures;
- captures.push_back(groups_capture);
- captures.push_back(shares_capture);
- client_->SetPacketFilter(new ChainedPacketFilter(captures));
+ auto groups_capture =
+ std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+ auto shares_capture =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+ std::vector<std::shared_ptr<PacketFilter>> captures = {groups_capture,
+ shares_capture};
+ client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
Connect();
@@ -95,7 +97,7 @@ TEST_P(TlsConnectGenericPre13, ConnectFfdheServer) {
Connect();
CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
} else {
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -126,9 +128,9 @@ TEST_P(TlsConnectGenericPre13, DamageServerKeyShare) {
EnableOnlyDheCiphers();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
- server_->SetPacketFilter(new TlsDheServerKeyExchangeDamager());
+ server_->SetPacketFilter(std::make_shared<TlsDheServerKeyExchangeDamager>());
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@@ -249,8 +251,9 @@ class TlsDheSkeChangeYServer : public TlsDheSkeChangeY {
class TlsDheSkeChangeYClient : public TlsDheSkeChangeY {
public:
- TlsDheSkeChangeYClient(ChangeYTo change,
- const TlsDheSkeChangeYServer* server_filter)
+ TlsDheSkeChangeYClient(
+ ChangeYTo change,
+ std::shared_ptr<const TlsDheSkeChangeYServer> server_filter)
: TlsDheSkeChangeY(change), server_filter_(server_filter) {}
protected:
@@ -266,13 +269,14 @@ class TlsDheSkeChangeYClient : public TlsDheSkeChangeY {
}
private:
- const TlsDheSkeChangeYServer* server_filter_;
+ std::shared_ptr<const TlsDheSkeChangeYServer> server_filter_;
};
-/* This matrix includes: mode (stream/datagram), TLS version, what change to
+/* This matrix includes: variant (stream/datagram), TLS version, what change to
* make to dh_Ys, whether the client will be configured to require DH named
* groups. Test all combinations. */
-typedef std::tuple<std::string, uint16_t, TlsDheSkeChangeY::ChangeYTo, bool>
+typedef std::tuple<SSLProtocolVariant, uint16_t, TlsDheSkeChangeY::ChangeYTo,
+ bool>
DamageDHYProfile;
class TlsDamageDHYTest
: public TlsConnectTestBase,
@@ -289,8 +293,14 @@ TEST_P(TlsDamageDHYTest, DamageServerY) {
SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
}
TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
- server_->SetPacketFilter(new TlsDheSkeChangeYServer(change, true));
+ server_->SetPacketFilter(
+ std::make_shared<TlsDheSkeChangeYServer>(change, true));
+ if (change == TlsDheSkeChangeY::kYZeroPad) {
+ ExpectAlert(client_, kTlsAlertDecryptError);
+ } else {
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
+ }
ConnectExpectFail();
if (change == TlsDheSkeChangeY::kYZeroPad) {
// Zero padding Y only manifests in a signature failure.
@@ -314,14 +324,20 @@ TEST_P(TlsDamageDHYTest, DamageClientY) {
SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
}
// The filter on the server is required to capture the prime.
- TlsDheSkeChangeYServer* server_filter =
- new TlsDheSkeChangeYServer(TlsDheSkeChangeY::kYZero, false);
+ auto server_filter =
+ std::make_shared<TlsDheSkeChangeYServer>(TlsDheSkeChangeY::kYZero, false);
server_->SetPacketFilter(server_filter);
// The client filter does the damage.
TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
- client_->SetPacketFilter(new TlsDheSkeChangeYClient(change, server_filter));
+ client_->SetPacketFilter(
+ std::make_shared<TlsDheSkeChangeYClient>(change, server_filter));
+ if (change == TlsDheSkeChangeY::kYZeroPad) {
+ ExpectAlert(server_, kTlsAlertDecryptError);
+ } else {
+ ExpectAlert(server_, kTlsAlertHandshakeFailure);
+ }
ConnectExpectFail();
if (change == TlsDheSkeChangeY::kYZeroPad) {
// Zero padding Y only manifests in a finished error.
@@ -343,13 +359,13 @@ static const bool kTrueFalseArr[] = {true, false};
static ::testing::internal::ParamGenerator<bool> kTrueFalse =
::testing::ValuesIn(kTrueFalseArr);
-INSTANTIATE_TEST_CASE_P(DamageYStream, TlsDamageDHYTest,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsV10ToV12,
- kAllY, kTrueFalse));
+INSTANTIATE_TEST_CASE_P(
+ DamageYStream, TlsDamageDHYTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12, kAllY, kTrueFalse));
INSTANTIATE_TEST_CASE_P(
DamageYDatagram, TlsDamageDHYTest,
- ::testing::Combine(TlsConnectTestBase::kTlsModesDatagram,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11V12, kAllY, kTrueFalse));
class TlsDheSkeMakePEven : public TlsHandshakeFilter {
@@ -378,9 +394,9 @@ class TlsDheSkeMakePEven : public TlsHandshakeFilter {
// Even without requiring named groups, an even value for p is bad news.
TEST_P(TlsConnectGenericPre13, MakeDhePEven) {
EnableOnlyDheCiphers();
- server_->SetPacketFilter(new TlsDheSkeMakePEven());
+ server_->SetPacketFilter(std::make_shared<TlsDheSkeMakePEven>());
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@@ -409,9 +425,9 @@ class TlsDheSkeZeroPadP : public TlsHandshakeFilter {
// Zero padding only causes signature failure.
TEST_P(TlsConnectGenericPre13, PadDheP) {
EnableOnlyDheCiphers();
- server_->SetPacketFilter(new TlsDheSkeZeroPadP());
+ server_->SetPacketFilter(std::make_shared<TlsDheSkeZeroPadP>());
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertDecryptError);
// In TLS 1.0 and 1.1, the client reports a device error.
if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
@@ -470,7 +486,7 @@ TEST_P(TlsConnectTls13, NamedGroupMismatch13) {
server_->ConfigNamedGroups(server_groups);
client_->ConfigNamedGroups(client_groups);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -488,7 +504,7 @@ TEST_P(TlsConnectGenericPre13, RequireNamedGroupsMismatchPre13) {
server_->ConfigNamedGroups(server_groups);
client_->ConfigNamedGroups(client_groups);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -518,7 +534,7 @@ TEST_P(TlsConnectGenericPre13, MismatchDHE) {
EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(client_->ssl_fd(), clientGroups,
PR_ARRAY_SIZE(clientGroups)));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -533,11 +549,11 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
EnableOnlyDheCiphers();
- TlsExtensionCapture* clientCapture =
- new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+ auto clientCapture =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
client_->SetPacketFilter(clientCapture);
- TlsExtensionCapture* serverCapture =
- new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+ auto serverCapture =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
server_->SetPacketFilter(serverCapture);
ExpectResumption(RESUME_TICKET);
Connect();
@@ -599,10 +615,10 @@ TEST_P(TlsConnectGenericPre13, InvalidDERSignatureFfdhe) {
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ffdhe_2048};
client_->ConfigNamedGroups(client_groups);
- server_->SetPacketFilter(new TlsDheSkeChangeSignature(
+ server_->SetPacketFilter(std::make_shared<TlsDheSkeChangeSignature>(
version_, kBogusDheSignature, sizeof(kBogusDheSignature)));
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
index 89ca28e97..3cc3b0e62 100644
--- a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
@@ -21,13 +21,13 @@ extern "C" {
namespace nss_test {
TEST_P(TlsConnectDatagram, DropClientFirstFlightOnce) {
- client_->SetPacketFilter(new SelectiveDropFilter(0x1));
+ client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x1));
Connect();
SendReceive();
}
TEST_P(TlsConnectDatagram, DropServerFirstFlightOnce) {
- server_->SetPacketFilter(new SelectiveDropFilter(0x1));
+ server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x1));
Connect();
SendReceive();
}
@@ -36,32 +36,32 @@ TEST_P(TlsConnectDatagram, DropServerFirstFlightOnce) {
// flights that they send. Note: In DTLS 1.3, the shorter handshake means that
// this will also drop some application data, so we can't call SendReceive().
TEST_P(TlsConnectDatagram, DropAllFirstTransmissions) {
- client_->SetPacketFilter(new SelectiveDropFilter(0x15));
- server_->SetPacketFilter(new SelectiveDropFilter(0x5));
+ client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x15));
+ server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x5));
Connect();
}
// This drops the server's first flight three times.
TEST_P(TlsConnectDatagram, DropServerFirstFlightThrice) {
- server_->SetPacketFilter(new SelectiveDropFilter(0x7));
+ server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x7));
Connect();
}
// This drops the client's second flight once
TEST_P(TlsConnectDatagram, DropClientSecondFlightOnce) {
- client_->SetPacketFilter(new SelectiveDropFilter(0x2));
+ client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x2));
Connect();
}
// This drops the client's second flight three times.
TEST_P(TlsConnectDatagram, DropClientSecondFlightThrice) {
- client_->SetPacketFilter(new SelectiveDropFilter(0xe));
+ client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0xe));
Connect();
}
// This drops the server's second flight three times.
TEST_P(TlsConnectDatagram, DropServerSecondFlightThrice) {
- server_->SetPacketFilter(new SelectiveDropFilter(0xe));
+ server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0xe));
Connect();
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
index 79b7736e4..1e406b6c2 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -75,8 +75,8 @@ TEST_P(TlsConnectGeneric, ConnectEcdheP384Client) {
// This causes a HelloRetryRequest in TLS 1.3. Earlier versions don't care.
TEST_P(TlsConnectGeneric, ConnectEcdheP384Server) {
EnsureTlsSetup();
- auto hrr_capture =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+ auto hrr_capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeHelloRetryRequest);
server_->SetPacketFilter(hrr_capture);
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
server_->ConfigNamedGroups(groups);
@@ -223,11 +223,12 @@ class TlsKeyExchangeGroupCapture : public TlsHandshakeFilter {
// P-256 is supported by the client (<= 1.2 only).
TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
EnsureTlsSetup();
- client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
- auto group_capture = new TlsKeyExchangeGroupCapture();
+ client_->SetPacketFilter(
+ std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
+ auto group_capture = std::make_shared<TlsKeyExchangeGroupCapture>();
server_->SetPacketFilter(group_capture);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
@@ -237,8 +238,9 @@ TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
// Supported groups is mandatory in TLS 1.3.
TEST_P(TlsConnectTls13, DropSupportedGroupExtension) {
EnsureTlsSetup();
- client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
- ConnectExpectFail();
+ client_->SetPacketFilter(
+ std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
}
@@ -483,7 +485,7 @@ TEST_P(TlsConnectGeneric, P256ClientAndCurve25519Server) {
client_->ConfigNamedGroups(client_groups);
server_->ConfigNamedGroups(server_groups);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
@@ -559,25 +561,25 @@ class ECCServerKEXFilter : public TlsHandshakeFilter {
TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyServerPoint) {
// add packet filter
- server_->SetPacketFilter(new ECCServerKEXFilter());
- ConnectExpectFail();
+ server_->SetPacketFilter(std::make_shared<ECCServerKEXFilter>());
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH);
}
TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
// add packet filter
- client_->SetPacketFilter(new ECCClientKEXFilter());
- ConnectExpectFail();
+ client_->SetPacketFilter(std::make_shared<ECCClientKEXFilter>());
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
}
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV11Plus));
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
#endif
diff --git a/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
index b9c725b36..dad6ca026 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
@@ -79,11 +79,7 @@ TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretResumeWithout) {
Reset();
server_->EnableExtendedMasterSecret();
- auto alert_recorder = new TlsAlertRecorder();
- server_->SetPacketFilter(alert_recorder);
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertHandshakeFailure, alert_recorder->description());
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
}
TEST_P(TlsConnectGenericPre13, ConnectNormalResumeWithExtendedMasterSecret) {
diff --git a/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
index 0a0d9f25f..be407b42e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
@@ -14,7 +14,8 @@ namespace nss_test {
static const char* kExporterLabel = "EXPORTER-duck";
static const uint8_t kExporterContext[] = {0x12, 0x34, 0x56};
-static void ExportAndCompare(TlsAgent* client, TlsAgent* server, bool context) {
+static void ExportAndCompare(std::shared_ptr<TlsAgent>& client,
+ std::shared_ptr<TlsAgent>& server, bool context) {
static const size_t exporter_len = 10;
uint8_t client_value[exporter_len] = {0};
EXPECT_EQ(SECSuccess,
@@ -76,6 +77,33 @@ TEST_P(TlsConnectTls13, ExporterContextEmptyIsSameAsNone) {
ExportAndCompare(client_, server_, false);
}
+TEST_P(TlsConnectGenericPre13, ExporterContextLengthTooLong) {
+ static const uint8_t kExporterContextTooLong[PR_UINT16_MAX] = {
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF};
+
+ EnsureTlsSetup();
+ Connect();
+ CheckKeys();
+
+ static const size_t exporter_len = 10;
+ uint8_t client_value[exporter_len] = {0};
+ EXPECT_EQ(SECFailure,
+ SSL_ExportKeyingMaterial(client_->ssl_fd(), kExporterLabel,
+ strlen(kExporterLabel), PR_TRUE,
+ kExporterContextTooLong,
+ sizeof(kExporterContextTooLong),
+ client_value, sizeof(client_value)));
+ EXPECT_EQ(PORT_GetError(), SEC_ERROR_INVALID_ARGS);
+ uint8_t server_value[exporter_len] = {0xff};
+ EXPECT_EQ(SECFailure,
+ SSL_ExportKeyingMaterial(server_->ssl_fd(), kExporterLabel,
+ strlen(kExporterLabel), PR_TRUE,
+ kExporterContextTooLong,
+ sizeof(kExporterContextTooLong),
+ server_value, sizeof(server_value)));
+ EXPECT_EQ(PORT_GetError(), SEC_ERROR_INVALID_ARGS);
+}
+
// This has a weird signature so that it can be passed to the SNI callback.
int32_t RegularExporterShouldFail(TlsAgent* agent, const SECItem* srvNameArr,
PRUint32 srvNameArrSize) {
@@ -90,13 +118,15 @@ int32_t RegularExporterShouldFail(TlsAgent* agent, const SECItem* srvNameArr,
TEST_P(TlsConnectTls13, EarlyExporter) {
SetupForZeroRtt();
+ ExpectAlert(client_, kTlsAlertEndOfEarlyData);
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
client_->Handshake(); // Send ClientHello.
uint8_t client_value[10] = {0};
- RegularExporterShouldFail(client_, nullptr, 0);
+ RegularExporterShouldFail(client_.get(), nullptr, 0);
+
EXPECT_EQ(SECSuccess,
SSL_ExportEarlyKeyingMaterial(
client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
diff --git a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
index 9200e724b..d15139419 100644
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -69,22 +69,11 @@ class TlsExtensionInjector : public TlsHandshakeFilter {
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
- size_t offset;
- if (header.handshake_type() == kTlsHandshakeClientHello) {
- TlsParser parser(input);
- if (!TlsExtensionFilter::FindClientHelloExtensions(&parser, header)) {
- return KEEP;
- }
- offset = parser.consumed();
- } else if (header.handshake_type() == kTlsHandshakeServerHello) {
- TlsParser parser(input);
- if (!TlsExtensionFilter::FindServerHelloExtensions(&parser)) {
- return KEEP;
- }
- offset = parser.consumed();
- } else {
+ TlsParser parser(input);
+ if (!TlsExtensionFilter::FindExtensions(&parser, header)) {
return KEEP;
}
+ size_t offset = parser.consumed();
*output = input;
@@ -116,38 +105,41 @@ class TlsExtensionInjector : public TlsHandshakeFilter {
class TlsExtensionAppender : public TlsHandshakeFilter {
public:
- TlsExtensionAppender(uint16_t ext, DataBuffer& data)
- : extension_(ext), data_(data) {}
+ TlsExtensionAppender(uint8_t handshake_type, uint16_t ext, DataBuffer& data)
+ : handshake_type_(handshake_type), extension_(ext), data_(data) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
- size_t offset;
+ if (header.handshake_type() != handshake_type_) {
+ return KEEP;
+ }
+
TlsParser parser(input);
- if (header.handshake_type() == kTlsHandshakeClientHello) {
- if (!TlsExtensionFilter::FindClientHelloExtensions(&parser, header)) {
- return KEEP;
- }
- } else if (header.handshake_type() == kTlsHandshakeServerHello) {
- if (!TlsExtensionFilter::FindServerHelloExtensions(&parser)) {
- return KEEP;
- }
- } else {
+ if (!TlsExtensionFilter::FindExtensions(&parser, header)) {
return KEEP;
}
- offset = parser.consumed();
*output = input;
- uint32_t ext_len;
- if (!parser.Read(&ext_len, 2)) {
- ADD_FAILURE();
+ // Increase the length of the extensions block.
+ if (!UpdateLength(output, parser.consumed(), 2)) {
return KEEP;
}
- ext_len += 4 + data_.len();
- output->Write(offset, ext_len, 2);
+ // Extensions in Certificate are nested twice. Increase the size of the
+ // certificate list.
+ if (header.handshake_type() == kTlsHandshakeCertificate) {
+ TlsParser p2(input);
+ if (!p2.SkipVariable(1)) {
+ ADD_FAILURE();
+ return KEEP;
+ }
+ if (!UpdateLength(output, p2.consumed(), 3)) {
+ return KEEP;
+ }
+ }
- offset = output->len();
+ size_t offset = output->len();
offset = output->Write(offset, extension_, 2);
WriteVariable(output, offset, data_, 2);
@@ -155,39 +147,38 @@ class TlsExtensionAppender : public TlsHandshakeFilter {
}
private:
+ bool UpdateLength(DataBuffer* output, size_t offset, size_t size) {
+ uint32_t len;
+ if (!output->Read(offset, size, &len)) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ len += 4 + data_.len();
+ output->Write(offset, len, size);
+ return true;
+ }
+
+ const uint8_t handshake_type_;
const uint16_t extension_;
const DataBuffer data_;
};
class TlsExtensionTestBase : public TlsConnectTestBase {
protected:
- TlsExtensionTestBase(Mode mode, uint16_t version)
- : TlsConnectTestBase(mode, version) {}
- TlsExtensionTestBase(const std::string& 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();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(alert, alert_recorder->description());
+ TlsExtensionTestBase(SSLProtocolVariant variant, uint16_t version)
+ : TlsConnectTestBase(variant, version) {}
+
+ void ClientHelloErrorTest(std::shared_ptr<PacketFilter> filter,
+ uint8_t desc = kTlsAlertDecodeError) {
+ client_->SetPacketFilter(filter);
+ ConnectExpectAlert(server_, desc);
}
- void ServerHelloErrorTest(PacketFilter* filter,
- uint8_t alert = kTlsAlertDecodeError) {
- auto alert_recorder = new TlsAlertRecorder();
- client_->SetPacketFilter(alert_recorder);
- if (filter) {
- server_->SetPacketFilter(filter);
- }
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(alert, alert_recorder->description());
+ void ServerHelloErrorTest(std::shared_ptr<PacketFilter> filter,
+ uint8_t desc = kTlsAlertDecodeError) {
+ server_->SetPacketFilter(filter);
+ ConnectExpectAlert(client_, desc);
}
static void InitSimpleSni(DataBuffer* extension) {
@@ -213,7 +204,7 @@ class TlsExtensionTestBase : public TlsConnectTestBase {
server_->StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send HRR.
- client_->SetPacketFilter(new TlsExtensionDropper(type));
+ client_->SetPacketFilter(std::make_shared<TlsExtensionDropper>(type));
Handshake();
client_->CheckErrorCode(client_error);
server_->CheckErrorCode(server_error);
@@ -223,38 +214,40 @@ class TlsExtensionTestBase : public TlsConnectTestBase {
class TlsExtensionTestDtls : public TlsExtensionTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
- TlsExtensionTestDtls() : TlsExtensionTestBase(DGRAM, GetParam()) {}
+ TlsExtensionTestDtls()
+ : TlsExtensionTestBase(ssl_variant_datagram, GetParam()) {}
};
-class TlsExtensionTest12Plus
- : public TlsExtensionTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsExtensionTest12Plus : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsExtensionTest12Plus()
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
}
};
-class TlsExtensionTest12
- : public TlsExtensionTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsExtensionTest12 : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsExtensionTest12()
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
}
};
-class TlsExtensionTest13 : public TlsExtensionTestBase,
- public ::testing::WithParamInterface<std::string> {
+class TlsExtensionTest13
+ : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<SSLProtocolVariant> {
public:
TlsExtensionTest13()
: TlsExtensionTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
void ConnectWithBogusVersionList(const uint8_t* buf, size_t len) {
DataBuffer versions_buf(buf, len);
- client_->SetPacketFilter(new TlsExtensionReplacer(
+ client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
ssl_tls13_supported_versions_xtn, versions_buf));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -264,7 +257,7 @@ class TlsExtensionTest13 : public TlsExtensionTestBase,
size_t index = versions_buf.Write(0, 2, 1);
versions_buf.Write(index, version, 2);
- client_->SetPacketFilter(new TlsExtensionReplacer(
+ client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
ssl_tls13_supported_versions_xtn, versions_buf));
ConnectExpectFail();
}
@@ -273,21 +266,21 @@ class TlsExtensionTest13 : public TlsExtensionTestBase,
class TlsExtensionTest13Stream : public TlsExtensionTestBase {
public:
TlsExtensionTest13Stream()
- : TlsExtensionTestBase(STREAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
+ : TlsExtensionTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
};
-class TlsExtensionTestGeneric
- : public TlsExtensionTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsExtensionTestGeneric : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsExtensionTestGeneric()
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
}
};
-class TlsExtensionTestPre13
- : public TlsExtensionTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsExtensionTestPre13 : public TlsExtensionTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsExtensionTestPre13()
: TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
@@ -295,23 +288,27 @@ class TlsExtensionTestPre13
};
TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
- ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 1));
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDamager>(ssl_server_name_xtn, 1));
}
TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
- ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 4));
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDamager>(ssl_server_name_xtn, 4));
}
TEST_P(TlsExtensionTestGeneric, TruncateSni) {
- ClientHelloErrorTest(new TlsExtensionTruncator(ssl_server_name_xtn, 7));
+ ClientHelloErrorTest(
+ std::make_shared<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);
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionInjector>(ssl_server_name_xtn, extension),
+ kTlsAlertIllegalParameter);
}
// An SNI entry with zero length is considered invalid (strangely, not if it is
@@ -324,7 +321,7 @@ TEST_P(TlsExtensionTestGeneric, BadSni) {
extension.Write(0, static_cast<uint32_t>(0), 3);
extension.Write(3, simple);
ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_server_name_xtn, extension));
+ std::make_shared<TlsExtensionReplacer>(ssl_server_name_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, EmptySni) {
@@ -332,15 +329,15 @@ TEST_P(TlsExtensionTestGeneric, EmptySni) {
extension.Allocate(2);
extension.Write(0, static_cast<uint32_t>(0), 2);
ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_server_name_xtn, extension));
+ std::make_shared<TlsExtensionReplacer>(ssl_server_name_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
EnableAlpn();
DataBuffer extension;
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
- kTlsAlertIllegalParameter);
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertIllegalParameter);
}
// An empty ALPN isn't considered bad, though it does lead to there being no
@@ -349,30 +346,30 @@ 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);
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertNoApplicationProtocol);
}
TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
EnableAlpn();
ClientHelloErrorTest(
- new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 1));
+ std::make_shared<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));
+ std::make_shared<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));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
@@ -390,158 +387,169 @@ TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyList) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x00};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyName) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x01, 0x00};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, AlpnReturnedListTrailingData) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x02, 0x01, 0x61, 0x00};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, AlpnReturnedExtraEntry) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x04, 0x01, 0x61, 0x01, 0x62};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, AlpnReturnedBadListLength) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x99, 0x01, 0x61, 0x00};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, AlpnReturnedBadNameLength) {
EnableAlpn();
const uint8_t val[] = {0x00, 0x02, 0x99, 0x61};
DataBuffer extension(val, sizeof(val));
- ServerHelloErrorTest(
- new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestPre13, AlpnReturnedUnknownName) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x02, 0x01, 0x67};
+ DataBuffer extension(val, sizeof(val));
+ ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_app_layer_protocol_xtn, extension),
+ kTlsAlertIllegalParameter);
}
TEST_P(TlsExtensionTestDtls, SrtpShort) {
EnableSrtp();
- ClientHelloErrorTest(new TlsExtensionTruncator(ssl_use_srtp_xtn, 3));
+ ClientHelloErrorTest(
+ std::make_shared<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));
+ ClientHelloErrorTest(
+ std::make_shared<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));
+ ClientHelloErrorTest(std::make_shared<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));
+ ClientHelloErrorTest(std::make_shared<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));
+ ClientHelloErrorTest(std::make_shared<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));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_signature_algorithms_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, NoSupportedGroups) {
- ClientHelloErrorTest(new TlsExtensionDropper(ssl_supported_groups_xtn),
- version_ < SSL_LIBRARY_VERSION_TLS_1_3
- ? kTlsAlertDecryptError
- : kTlsAlertMissingExtension);
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn),
+ version_ < SSL_LIBRARY_VERSION_TLS_1_3 ? kTlsAlertDecryptError
+ : kTlsAlertMissingExtension);
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
const uint8_t val[] = {0x00, 0x01, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_elliptic_curves_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
const uint8_t val[] = {0x09, 0x99, 0x00, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_elliptic_curves_xtn, extension));
}
TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
const uint8_t val[] = {0x00, 0x02, 0x00, 0x00, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_elliptic_curves_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, SupportedPointsEmpty) {
const uint8_t val[] = {0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_ec_point_formats_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, SupportedPointsBadLength) {
const uint8_t val[] = {0x99, 0x00, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_ec_point_formats_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, SupportedPointsTrailingData) {
const uint8_t val[] = {0x01, 0x00, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_ec_point_formats_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, RenegotiationInfoBadLength) {
const uint8_t val[] = {0x99};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_renegotiation_info_xtn, extension));
}
TEST_P(TlsExtensionTestPre13, RenegotiationInfoMismatch) {
const uint8_t val[] = {0x01, 0x00};
DataBuffer extension(val, sizeof(val));
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_renegotiation_info_xtn, extension));
}
// The extension has to contain a length.
TEST_P(TlsExtensionTestPre13, RenegotiationInfoExtensionEmpty) {
DataBuffer extension;
- ClientHelloErrorTest(
- new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ ssl_renegotiation_info_xtn, extension));
}
// This only works on TLS 1.2, since it relies on static RSA; otherwise libssl
@@ -550,8 +558,8 @@ TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_sha512,
ssl_sig_rsa_pss_sha384};
- TlsExtensionCapture* capture =
- new TlsExtensionCapture(ssl_signature_algorithms_xtn);
+ auto capture =
+ std::make_shared<TlsExtensionCapture>(ssl_signature_algorithms_xtn);
client_->SetSignatureSchemes(schemes, PR_ARRAY_SIZE(schemes));
client_->SetPacketFilter(capture);
EnableOnlyStaticRsaCiphers();
@@ -571,8 +579,9 @@ TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
// Temporary test to verify that we choke on an empty ClientKeyShare.
// This test will fail when we implement HelloRetryRequest.
TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
- ClientHelloErrorTest(new TlsExtensionTruncator(ssl_tls13_key_share_xtn, 2),
- kTlsAlertHandshakeFailure);
+ ClientHelloErrorTest(
+ std::make_shared<TlsExtensionTruncator>(ssl_tls13_key_share_xtn, 2),
+ kTlsAlertHandshakeFailure);
}
// These tests only work in stream mode because the client sends a
@@ -581,7 +590,10 @@ TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
// packet gets dropped.
TEST_F(TlsExtensionTest13Stream, DropServerKeyShare) {
EnsureTlsSetup();
- server_->SetPacketFilter(new TlsExtensionDropper(ssl_tls13_key_share_xtn));
+ server_->SetPacketFilter(
+ std::make_shared<TlsExtensionDropper>(ssl_tls13_key_share_xtn));
+ client_->ExpectSendAlert(kTlsAlertMissingExtension);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
@@ -600,7 +612,9 @@ TEST_F(TlsExtensionTest13Stream, WrongServerKeyShare) {
DataBuffer buf(key_share, sizeof(key_share));
EnsureTlsSetup();
server_->SetPacketFilter(
- new TlsExtensionReplacer(ssl_tls13_key_share_xtn, buf));
+ std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
@@ -620,7 +634,9 @@ TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
DataBuffer buf(key_share, sizeof(key_share));
EnsureTlsSetup();
server_->SetPacketFilter(
- new TlsExtensionReplacer(ssl_tls13_key_share_xtn, buf));
+ std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
+ client_->ExpectSendAlert(kTlsAlertMissingExtension);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
@@ -629,8 +645,10 @@ TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
TEST_F(TlsExtensionTest13Stream, AddServerSignatureAlgorithmsOnResumption) {
SetupForResume();
DataBuffer empty;
- server_->SetPacketFilter(
- new TlsExtensionInjector(ssl_signature_algorithms_xtn, empty));
+ server_->SetPacketFilter(std::make_shared<TlsExtensionInjector>(
+ ssl_signature_algorithms_xtn, empty));
+ client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
EXPECT_EQ(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, client_->error_code());
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
@@ -763,9 +781,9 @@ class TlsPreSharedKeyReplacer : public TlsExtensionFilter {
TEST_F(TlsExtensionTest13Stream, ResumeEmptyPskLabel) {
SetupForResume();
- client_->SetPacketFilter(new TlsPreSharedKeyReplacer([](
+ client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
TlsPreSharedKeyReplacer* r) { r->identities_[0].identity.Truncate(0); }));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -775,10 +793,10 @@ TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderValue) {
SetupForResume();
client_->SetPacketFilter(
- new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+ std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
}));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
@@ -788,10 +806,10 @@ TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderLength) {
SetupForResume();
client_->SetPacketFilter(
- new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+ std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
r->binders_[0].Write(r->binders_[0].len(), 0xff, 1);
}));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -800,9 +818,9 @@ TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderLength) {
TEST_F(TlsExtensionTest13Stream, ResumeBinderTooShort) {
SetupForResume();
- client_->SetPacketFilter(new TlsPreSharedKeyReplacer(
+ client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>(
[](TlsPreSharedKeyReplacer* r) { r->binders_[0].Truncate(31); }));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -813,11 +831,11 @@ TEST_F(TlsExtensionTest13Stream, ResumeTwoPsks) {
SetupForResume();
client_->SetPacketFilter(
- new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+ std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
r->identities_.push_back(r->identities_[0]);
r->binders_.push_back(r->binders_[0]);
}));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
@@ -828,10 +846,10 @@ TEST_F(TlsExtensionTest13Stream, ResumeTwoIdentitiesOneBinder) {
SetupForResume();
client_->SetPacketFilter(
- new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+ std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
r->identities_.push_back(r->identities_[0]);
}));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -839,9 +857,9 @@ TEST_F(TlsExtensionTest13Stream, ResumeTwoIdentitiesOneBinder) {
TEST_F(TlsExtensionTest13Stream, ResumeOneIdentityTwoBinders) {
SetupForResume();
- client_->SetPacketFilter(new TlsPreSharedKeyReplacer([](
+ client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
TlsPreSharedKeyReplacer* r) { r->binders_.push_back(r->binders_[0]); }));
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -851,10 +869,10 @@ TEST_F(TlsExtensionTest13Stream, ResumePskExtensionNotLast) {
const uint8_t empty_buf[] = {0};
DataBuffer empty(empty_buf, 0);
- client_->SetPacketFilter(
- // Inject an unused extension.
- new TlsExtensionAppender(0xffff, empty));
- ConnectExpectFail();
+ // Inject an unused extension after the PSK extension.
+ client_->SetPacketFilter(std::make_shared<TlsExtensionAppender>(
+ kTlsHandshakeClientHello, 0xffff, empty));
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
@@ -863,9 +881,9 @@ TEST_F(TlsExtensionTest13Stream, ResumeNoKeModes) {
SetupForResume();
DataBuffer empty;
- client_->SetPacketFilter(
- new TlsExtensionDropper(ssl_tls13_psk_key_exchange_modes_xtn));
- ConnectExpectFail();
+ client_->SetPacketFilter(std::make_shared<TlsExtensionDropper>(
+ ssl_tls13_psk_key_exchange_modes_xtn));
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES);
}
@@ -879,8 +897,10 @@ TEST_F(TlsExtensionTest13Stream, ResumeBogusKeModes) {
kTls13PskKe};
DataBuffer modes(ke_modes, sizeof(ke_modes));
- client_->SetPacketFilter(
- new TlsExtensionReplacer(ssl_tls13_psk_key_exchange_modes_xtn, modes));
+ client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
+ ssl_tls13_psk_key_exchange_modes_xtn, modes));
+ client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
@@ -888,7 +908,8 @@ TEST_F(TlsExtensionTest13Stream, ResumeBogusKeModes) {
TEST_P(TlsExtensionTest13, NoKeModesIfResumptionOff) {
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
- auto capture = new TlsExtensionCapture(ssl_tls13_psk_key_exchange_modes_xtn);
+ auto capture = std::make_shared<TlsExtensionCapture>(
+ ssl_tls13_psk_key_exchange_modes_xtn);
client_->SetPacketFilter(capture);
Connect();
EXPECT_FALSE(capture->captured());
@@ -899,6 +920,7 @@ TEST_P(TlsExtensionTest13, NoKeModesIfResumptionOff) {
// 1. Both sides only support TLS 1.3, so we get a cipher version
// error.
TEST_P(TlsExtensionTest13, RemoveTls13FromVersionList) {
+ ExpectAlert(server_, kTlsAlertProtocolVersion);
ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
@@ -909,6 +931,7 @@ TEST_P(TlsExtensionTest13, RemoveTls13FromVersionList) {
TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListServerV12) {
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
+ ExpectAlert(server_, kTlsAlertHandshakeFailure);
ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
@@ -921,6 +944,11 @@ TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListBothV12) {
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
+#ifndef TLS_1_3_DRAFT_VERSION
+ ExpectAlert(server_, kTlsAlertIllegalParameter);
+#else
+ ExpectAlert(server_, kTlsAlertDecryptError);
+#endif
ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
#ifndef TLS_1_3_DRAFT_VERSION
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
@@ -932,18 +960,21 @@ TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListBothV12) {
}
TEST_P(TlsExtensionTest13, HrrThenRemoveSignatureAlgorithms) {
+ ExpectAlert(server_, kTlsAlertMissingExtension);
HrrThenRemoveExtensionsTest(ssl_signature_algorithms_xtn,
SSL_ERROR_MISSING_EXTENSION_ALERT,
SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
}
TEST_P(TlsExtensionTest13, HrrThenRemoveKeyShare) {
+ ExpectAlert(server_, kTlsAlertIllegalParameter);
HrrThenRemoveExtensionsTest(ssl_tls13_key_share_xtn,
SSL_ERROR_ILLEGAL_PARAMETER_ALERT,
SSL_ERROR_BAD_2ND_CLIENT_HELLO);
}
TEST_P(TlsExtensionTest13, HrrThenRemoveSupportedGroups) {
+ ExpectAlert(server_, kTlsAlertMissingExtension);
HrrThenRemoveExtensionsTest(ssl_supported_groups_xtn,
SSL_ERROR_MISSING_EXTENSION_ALERT,
SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
@@ -959,27 +990,192 @@ TEST_P(TlsExtensionTest13, OddVersionList) {
ConnectWithBogusVersionList(ext, sizeof(ext));
}
-INSTANTIATE_TEST_CASE_P(ExtensionStream, TlsExtensionTestGeneric,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsVAll));
-INSTANTIATE_TEST_CASE_P(ExtensionDatagram, TlsExtensionTestGeneric,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
- TlsConnectTestBase::kTlsV11Plus));
+// TODO: this only tests extensions in server messages. The client can extend
+// Certificate messages, which is not checked here.
+class TlsBogusExtensionTest : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
+ public:
+ TlsBogusExtensionTest()
+ : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
+
+ protected:
+ virtual void ConnectAndFail(uint8_t message) = 0;
+
+ void AddFilter(uint8_t message, uint16_t extension) {
+ static uint8_t empty_buf[1] = {0};
+ DataBuffer empty(empty_buf, 0);
+ auto filter =
+ std::make_shared<TlsExtensionAppender>(message, extension, empty);
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ server_->SetTlsRecordFilter(filter);
+ filter->EnableDecryption();
+ } else {
+ server_->SetPacketFilter(filter);
+ }
+ }
+
+ void Run(uint8_t message, uint16_t extension = 0xff) {
+ EnsureTlsSetup();
+ AddFilter(message, extension);
+ ConnectAndFail(message);
+ }
+};
+
+class TlsBogusExtensionTestPre13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t) override {
+ ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
+ }
+};
+
+class TlsBogusExtensionTest13 : public TlsBogusExtensionTest {
+ protected:
+ void ConnectAndFail(uint8_t message) override {
+ if (message == kTlsHandshakeHelloRetryRequest) {
+ ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
+ return;
+ }
+
+ client_->StartConnect();
+ server_->StartConnect();
+ client_->Handshake(); // ClientHello
+ server_->Handshake(); // ServerHello
+
+ client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
+ client_->Handshake();
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ }
+ server_->Handshake();
+ }
+};
+
+TEST_P(TlsBogusExtensionTestPre13, AddBogusExtensionServerHello) {
+ Run(kTlsHandshakeServerHello);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionServerHello) {
+ Run(kTlsHandshakeServerHello);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionEncryptedExtensions) {
+ Run(kTlsHandshakeEncryptedExtensions);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificate) {
+ Run(kTlsHandshakeCertificate);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificateRequest) {
+ server_->RequestClientAuth(false);
+ Run(kTlsHandshakeCertificateRequest);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
+ static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
+ server_->ConfigNamedGroups(groups);
+
+ Run(kTlsHandshakeHelloRetryRequest);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddVersionExtensionServerHello) {
+ Run(kTlsHandshakeServerHello, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddVersionExtensionEncryptedExtensions) {
+ Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificate) {
+ Run(kTlsHandshakeCertificate, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificateRequest) {
+ server_->RequestClientAuth(false);
+ Run(kTlsHandshakeCertificateRequest, ssl_tls13_supported_versions_xtn);
+}
+
+TEST_P(TlsBogusExtensionTest13, AddVersionExtensionHelloRetryRequest) {
+ static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
+ server_->ConfigNamedGroups(groups);
+
+ Run(kTlsHandshakeHelloRetryRequest, ssl_tls13_supported_versions_xtn);
+}
+
+// NewSessionTicket allows unknown extensions AND it isn't protected by the
+// Finished. So adding an unknown extension doesn't cause an error.
+TEST_P(TlsBogusExtensionTest13, AddBogusExtensionNewSessionTicket) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+
+ AddFilter(kTlsHandshakeNewSessionTicket, 0xff);
+ Connect();
+ SendReceive();
+ CheckKeys();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+ Connect();
+ SendReceive();
+}
+
+TEST_P(TlsConnectStream, IncludePadding) {
+ EnsureTlsSetup();
+
+ // This needs to be long enough to push a TLS 1.0 ClientHello over 255, but
+ // short enough not to push a TLS 1.3 ClientHello over 511.
+ static const char* long_name =
+ "chickenchickenchickenchickenchickenchickenchickenchicken."
+ "chickenchickenchickenchickenchickenchickenchickenchicken."
+ "chickenchickenchickenchickenchicken.";
+ SECStatus rv = SSL_SetURL(client_->ssl_fd(), long_name);
+ EXPECT_EQ(SECSuccess, rv);
+
+ auto capture = std::make_shared<TlsExtensionCapture>(ssl_padding_xtn);
+ client_->SetPacketFilter(capture);
+ client_->StartConnect();
+ client_->Handshake();
+ EXPECT_TRUE(capture->captured());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ExtensionStream, TlsExtensionTestGeneric,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll));
+INSTANTIATE_TEST_CASE_P(
+ ExtensionDatagram, TlsExtensionTestGeneric,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+ TlsConnectTestBase::kTlsV11Plus));
INSTANTIATE_TEST_CASE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
TlsConnectTestBase::kTlsV11Plus);
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus));
-INSTANTIATE_TEST_CASE_P(ExtensionPre13Stream, TlsExtensionTestPre13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsV10ToV12));
+INSTANTIATE_TEST_CASE_P(
+ ExtensionPre13Stream, TlsExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12));
INSTANTIATE_TEST_CASE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(ExtensionTls13, TlsExtensionTest13,
- TlsConnectTestBase::kTlsModesAll);
-
-} // namespace nspr_test
+ TlsConnectTestBase::kTlsVariantsAll);
+
+INSTANTIATE_TEST_CASE_P(
+ BogusExtensionStream, TlsBogusExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12));
+INSTANTIATE_TEST_CASE_P(
+ BogusExtensionDatagram, TlsBogusExtensionTestPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+ TlsConnectTestBase::kTlsV11V12));
+
+INSTANTIATE_TEST_CASE_P(BogusExtension13, TlsBogusExtensionTest13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
new file mode 100644
index 000000000..44cacce46
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+// This class cuts every unencrypted handshake record into two parts.
+class RecordFragmenter : public PacketFilter {
+ public:
+ RecordFragmenter() : sequence_number_(0), splitting_(true) {}
+
+ private:
+ class HandshakeSplitter {
+ public:
+ HandshakeSplitter(const DataBuffer& input, DataBuffer* output,
+ uint64_t* sequence_number)
+ : input_(input),
+ output_(output),
+ cursor_(0),
+ sequence_number_(sequence_number) {}
+
+ private:
+ void WriteRecord(TlsRecordHeader& record_header,
+ DataBuffer& record_fragment) {
+ TlsRecordHeader fragment_header(record_header.version(),
+ record_header.content_type(),
+ *sequence_number_);
+ ++*sequence_number_;
+ if (::g_ssl_gtest_verbose) {
+ std::cerr << "Fragment: " << fragment_header << ' ' << record_fragment
+ << std::endl;
+ }
+ cursor_ = fragment_header.Write(output_, cursor_, record_fragment);
+ }
+
+ bool SplitRecord(TlsRecordHeader& record_header, DataBuffer& record) {
+ TlsParser parser(record);
+ while (parser.remaining()) {
+ TlsHandshakeFilter::HandshakeHeader handshake_header;
+ DataBuffer handshake_body;
+ if (!handshake_header.Parse(&parser, record_header, &handshake_body)) {
+ ADD_FAILURE() << "couldn't parse handshake header";
+ return false;
+ }
+
+ DataBuffer record_fragment;
+ // We can't fragment handshake records that are too small.
+ if (handshake_body.len() < 2) {
+ handshake_header.Write(&record_fragment, 0U, handshake_body);
+ WriteRecord(record_header, record_fragment);
+ continue;
+ }
+
+ size_t cut = handshake_body.len() / 2;
+ handshake_header.WriteFragment(&record_fragment, 0U, handshake_body, 0U,
+ cut);
+ WriteRecord(record_header, record_fragment);
+
+ handshake_header.WriteFragment(&record_fragment, 0U, handshake_body,
+ cut, handshake_body.len() - cut);
+ WriteRecord(record_header, record_fragment);
+ }
+ return true;
+ }
+
+ public:
+ bool Split() {
+ TlsParser parser(input_);
+ while (parser.remaining()) {
+ TlsRecordHeader header;
+ DataBuffer record;
+ if (!header.Parse(&parser, &record)) {
+ ADD_FAILURE() << "bad record header";
+ return false;
+ }
+
+ if (::g_ssl_gtest_verbose) {
+ std::cerr << "Record: " << header << ' ' << record << std::endl;
+ }
+
+ // Don't touch packets from a non-zero epoch. Leave these unmodified.
+ if ((header.sequence_number() >> 48) != 0ULL) {
+ cursor_ = header.Write(output_, cursor_, record);
+ continue;
+ }
+
+ // Just rewrite the sequence number (CCS only).
+ if (header.content_type() != kTlsHandshakeType) {
+ EXPECT_EQ(kTlsChangeCipherSpecType, header.content_type());
+ WriteRecord(header, record);
+ continue;
+ }
+
+ if (!SplitRecord(header, record)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ const DataBuffer& input_;
+ DataBuffer* output_;
+ size_t cursor_;
+ uint64_t* sequence_number_;
+ };
+
+ protected:
+ virtual PacketFilter::Action Filter(const DataBuffer& input,
+ DataBuffer* output) override {
+ if (!splitting_) {
+ return KEEP;
+ }
+
+ output->Allocate(input.len());
+ HandshakeSplitter splitter(input, output, &sequence_number_);
+ if (!splitter.Split()) {
+ // If splitting fails, we obviously reached encrypted packets.
+ // Stop splitting from that point onward.
+ splitting_ = false;
+ return KEEP;
+ }
+
+ return CHANGE;
+ }
+
+ private:
+ uint64_t sequence_number_;
+ bool splitting_;
+};
+
+TEST_P(TlsConnectDatagram, FragmentClientPackets) {
+ client_->SetPacketFilter(std::make_shared<RecordFragmenter>());
+ Connect();
+ SendReceive();
+}
+
+TEST_P(TlsConnectDatagram, FragmentServerPackets) {
+ server_->SetPacketFilter(std::make_shared<RecordFragmenter>());
+ Connect();
+ SendReceive();
+}
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
index d144cd7d9..1587b66de 100644
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -12,6 +12,12 @@
namespace nss_test {
#ifdef UNSAFE_FUZZER_MODE
+#define FUZZ_F(c, f) TEST_F(c, Fuzz_##f)
+#define FUZZ_P(c, f) TEST_P(c, Fuzz_##f)
+#else
+#define FUZZ_F(c, f) TEST_F(c, DISABLED_Fuzz_##f)
+#define FUZZ_P(c, f) TEST_P(c, DISABLED_Fuzz_##f)
+#endif
const uint8_t kShortEmptyFinished[8] = {0};
const uint8_t kLongEmptyFinished[128] = {0};
@@ -23,7 +29,7 @@ class TlsApplicationDataRecorder : public TlsRecordFilter {
public:
TlsApplicationDataRecorder() : buffer_() {}
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output) {
if (header.content_type() == kTlsApplicationDataType) {
@@ -39,56 +45,28 @@ class TlsApplicationDataRecorder : public TlsRecordFilter {
DataBuffer buffer_;
};
-// Damages an SKE or CV signature.
-class TlsSignatureDamager : public TlsHandshakeFilter {
- public:
- TlsSignatureDamager(uint8_t type) : type_(type) {}
- virtual PacketFilter::Action FilterHandshake(
- const TlsHandshakeFilter::HandshakeHeader& header,
- const DataBuffer& input, DataBuffer* output) {
- if (header.handshake_type() != type_) {
- return KEEP;
- }
-
- *output = input;
-
- // Modify the last byte of the signature.
- output->data()[output->len() - 1]++;
- return CHANGE;
- }
-
- private:
- uint8_t type_;
-};
-
-void ResetState() {
- // Clear the list of RSA blinding params.
- BL_Cleanup();
-
- // Reinit the list of RSA blinding params.
- EXPECT_EQ(SECSuccess, BL_Init());
-
- // Reset the RNG state.
- EXPECT_EQ(SECSuccess, RNG_ResetForFuzzing());
-}
-
// Ensure that ssl_Time() returns a constant value.
-TEST_F(TlsFuzzTest, Fuzz_SSL_Time_Constant) {
- PRInt32 now = ssl_Time();
+FUZZ_F(TlsFuzzTest, SSL_Time_Constant) {
+ PRUint32 now = ssl_Time();
PR_Sleep(PR_SecondsToInterval(2));
EXPECT_EQ(ssl_Time(), now);
}
// Check that due to the deterministic PRNG we derive
// the same master secret in two consecutive TLS sessions.
-TEST_P(TlsConnectGeneric, Fuzz_DeterministicExporter) {
+FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
const char kLabel[] = "label";
std::vector<unsigned char> out1(32), out2(32);
+ // Make sure we have RSA blinding params.
+ Connect();
+
+ Reset();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
DisableECDHEServerKeyReuse();
- ResetState();
+ // Reset the RNG state.
+ EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
Connect();
// Export a key derived from the MS and nonces.
@@ -101,7 +79,8 @@ TEST_P(TlsConnectGeneric, Fuzz_DeterministicExporter) {
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
DisableECDHEServerKeyReuse();
- ResetState();
+ // Reset the RNG state.
+ EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
Connect();
// Export another key derived from the MS and nonces.
@@ -115,7 +94,10 @@ TEST_P(TlsConnectGeneric, Fuzz_DeterministicExporter) {
// Check that due to the deterministic RNG two consecutive
// TLS sessions will have the exact same transcript.
-TEST_P(TlsConnectGeneric, Fuzz_DeterministicTranscript) {
+FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
+ // Make sure we have RSA blinding params.
+ Connect();
+
// Connect a few times and compare the transcripts byte-by-byte.
DataBuffer last;
for (size_t i = 0; i < 5; i++) {
@@ -124,15 +106,16 @@ TEST_P(TlsConnectGeneric, Fuzz_DeterministicTranscript) {
DisableECDHEServerKeyReuse();
DataBuffer buffer;
- client_->SetPacketFilter(new TlsConversationRecorder(buffer));
- server_->SetPacketFilter(new TlsConversationRecorder(buffer));
+ client_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
+ server_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
- ResetState();
+ // Reset the RNG state.
+ EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
Connect();
// Ensure the filters go away before |buffer| does.
- client_->SetPacketFilter(nullptr);
- server_->SetPacketFilter(nullptr);
+ client_->DeletePacketFilter();
+ server_->DeletePacketFilter();
if (last.len() > 0) {
EXPECT_EQ(last, buffer);
@@ -146,13 +129,13 @@ TEST_P(TlsConnectGeneric, Fuzz_DeterministicTranscript) {
// with all supported TLS versions, STREAM and DGRAM.
// Check that records are NOT encrypted.
// Check that records don't have a MAC.
-TEST_P(TlsConnectGeneric, Fuzz_ConnectSendReceive_NullCipher) {
+FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
EnsureTlsSetup();
// Set up app data filters.
- auto client_recorder = new TlsApplicationDataRecorder();
+ auto client_recorder = std::make_shared<TlsApplicationDataRecorder>();
client_->SetPacketFilter(client_recorder);
- auto server_recorder = new TlsApplicationDataRecorder();
+ auto server_recorder = std::make_shared<TlsApplicationDataRecorder>();
server_->SetPacketFilter(server_recorder);
Connect();
@@ -175,10 +158,10 @@ TEST_P(TlsConnectGeneric, Fuzz_ConnectSendReceive_NullCipher) {
}
// Check that an invalid Finished message doesn't abort the connection.
-TEST_P(TlsConnectGeneric, Fuzz_BogusClientFinished) {
+FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
EnsureTlsSetup();
- auto i1 = new TlsInspectorReplaceHandshakeMessage(
+ auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
kTlsHandshakeFinished,
DataBuffer(kShortEmptyFinished, sizeof(kShortEmptyFinished)));
client_->SetPacketFilter(i1);
@@ -187,10 +170,10 @@ TEST_P(TlsConnectGeneric, Fuzz_BogusClientFinished) {
}
// Check that an invalid Finished message doesn't abort the connection.
-TEST_P(TlsConnectGeneric, Fuzz_BogusServerFinished) {
+FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
EnsureTlsSetup();
- auto i1 = new TlsInspectorReplaceHandshakeMessage(
+ auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
kTlsHandshakeFinished,
DataBuffer(kLongEmptyFinished, sizeof(kLongEmptyFinished)));
server_->SetPacketFilter(i1);
@@ -199,25 +182,115 @@ TEST_P(TlsConnectGeneric, Fuzz_BogusServerFinished) {
}
// Check that an invalid server auth signature doesn't abort the connection.
-TEST_P(TlsConnectGeneric, Fuzz_BogusServerAuthSignature) {
+FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
EnsureTlsSetup();
uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
? kTlsHandshakeCertificateVerify
: kTlsHandshakeServerKeyExchange;
- server_->SetPacketFilter(new TlsSignatureDamager(msg_type));
+ server_->SetPacketFilter(std::make_shared<TlsLastByteDamager>(msg_type));
Connect();
SendReceive();
}
// Check that an invalid client auth signature doesn't abort the connection.
-TEST_P(TlsConnectGeneric, Fuzz_BogusClientAuthSignature) {
+FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
EnsureTlsSetup();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
client_->SetPacketFilter(
- new TlsSignatureDamager(kTlsHandshakeCertificateVerify));
+ std::make_shared<TlsLastByteDamager>(kTlsHandshakeCertificateVerify));
Connect();
}
-#endif
+// Check that session ticket resumption works.
+FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+ Connect();
+ SendReceive();
+}
+
+class TlsSessionTicketMacDamager : public TlsExtensionFilter {
+ public:
+ TlsSessionTicketMacDamager() {}
+ virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ if (extension_type != ssl_session_ticket_xtn &&
+ extension_type != ssl_tls13_pre_shared_key_xtn) {
+ return KEEP;
+ }
+
+ *output = input;
+
+ // Handle everything before TLS 1.3.
+ if (extension_type == ssl_session_ticket_xtn) {
+ // Modify the last byte of the MAC.
+ output->data()[output->len() - 1] ^= 0xff;
+ }
+
+ // Handle TLS 1.3.
+ if (extension_type == ssl_tls13_pre_shared_key_xtn) {
+ TlsParser parser(input);
+
+ uint32_t ids_len;
+ EXPECT_TRUE(parser.Read(&ids_len, 2) && ids_len > 0);
+
+ uint32_t ticket_len;
+ EXPECT_TRUE(parser.Read(&ticket_len, 2) && ticket_len > 0);
+
+ // Modify the last byte of the MAC.
+ output->data()[2 + 2 + ticket_len - 1] ^= 0xff;
+ }
+
+ return CHANGE;
+ }
+};
+
+// Check that session ticket resumption works with a bad MAC.
+FUZZ_P(TlsConnectGeneric, SessionTicketResumptionBadMac) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_TICKET);
+
+ client_->SetPacketFilter(std::make_shared<TlsSessionTicketMacDamager>());
+ Connect();
+ SendReceive();
+}
+
+// Check that session tickets are not encrypted.
+FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
+ ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
+
+ auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeNewSessionTicket);
+ server_->SetPacketFilter(i1);
+ Connect();
+
+ size_t offset = 4; /* lifetime */
+ if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
+ offset += 1 + 1 + /* ke_modes */
+ 1 + 1; /* auth_modes */
+ }
+ offset += 2 + /* ticket length */
+ 2; /* TLS_EX_SESS_TICKET_VERSION */
+ // Check the protocol version number.
+ uint32_t tls_version = 0;
+ EXPECT_TRUE(i1->buffer().Read(offset, sizeof(version_), &tls_version));
+ EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
+
+ // Check the cipher suite.
+ uint32_t suite = 0;
+ EXPECT_TRUE(i1->buffer().Read(offset + sizeof(version_), 2, &suite));
+ client_->CheckCipherSuite(static_cast<uint16_t>(suite));
+}
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
new file mode 100644
index 000000000..f47b2f445
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
@@ -0,0 +1,143 @@
+/* -*- 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 "gtest_utils.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+class GatherV2ClientHelloTest : public TlsConnectTestBase {
+ public:
+ GatherV2ClientHelloTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
+
+ void ConnectExpectMalformedClientHello(const DataBuffer &data) {
+ EnsureTlsSetup();
+ server_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ client_->SendDirect(data);
+ server_->StartConnect();
+ server_->Handshake();
+ ASSERT_TRUE_WAIT(
+ (server_->error_code() == SSL_ERROR_RX_MALFORMED_CLIENT_HELLO), 2000);
+ }
+};
+
+// Gather a 5-byte v3 record, with a zero fragment length. The empty handshake
+// message should be ignored, and the connection will succeed afterwards.
+TEST_F(TlsConnectTest, GatherEmptyV3Record) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x16, 1); // handshake
+ idx = buffer.Write(idx, 0x0301, 2); // record_version
+ (void)buffer.Write(idx, 0U, 2); // length=0
+
+ EnsureTlsSetup();
+ client_->SendDirect(buffer);
+ Connect();
+}
+
+// Gather a 5-byte v3 record, with a fragment length exceeding the maximum.
+TEST_F(TlsConnectTest, GatherExcessiveV3Record) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x16, 1); // handshake
+ idx = buffer.Write(idx, 0x0301, 2); // record_version
+ (void)buffer.Write(idx, MAX_FRAGMENT_LENGTH + 2048 + 1, 2); // length=max+1
+
+ EnsureTlsSetup();
+ server_->ExpectSendAlert(kTlsAlertRecordOverflow);
+ client_->SendDirect(buffer);
+ server_->StartConnect();
+ server_->Handshake();
+ ASSERT_TRUE_WAIT((server_->error_code() == SSL_ERROR_RX_RECORD_TOO_LONG),
+ 2000);
+}
+
+// Gather a 3-byte v2 header, with a fragment length of 2.
+TEST_F(GatherV2ClientHelloTest, GatherV2RecordLongHeader) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x0002, 2); // length=2 (long header)
+ idx = buffer.Write(idx, 0U, 1); // padding=0
+ (void)buffer.Write(idx, 0U, 2); // data
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 3-byte v2 header, with a fragment length of 1.
+TEST_F(GatherV2ClientHelloTest, GatherV2RecordLongHeader2) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x0001, 2); // length=1 (long header)
+ idx = buffer.Write(idx, 0U, 1); // padding=0
+ idx = buffer.Write(idx, 0U, 1); // data
+ (void)buffer.Write(idx, 0U, 1); // surplus (need 5 bytes total)
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 3-byte v2 header, with a zero fragment length.
+TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordLongHeader) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0U, 2); // length=0 (long header)
+ idx = buffer.Write(idx, 0U, 1); // padding=0
+ (void)buffer.Write(idx, 0U, 2); // surplus (need 5 bytes total)
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 2-byte v2 header, with a fragment length of 3.
+TEST_F(GatherV2ClientHelloTest, GatherV2RecordShortHeader) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x8003, 2); // length=3 (short header)
+ (void)buffer.Write(idx, 0U, 3); // data
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 2-byte v2 header, with a fragment length of 2.
+TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader2) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x8002, 2); // length=2 (short header)
+ idx = buffer.Write(idx, 0U, 2); // data
+ (void)buffer.Write(idx, 0U, 1); // surplus (need 5 bytes total)
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 2-byte v2 header, with a fragment length of 1.
+TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader3) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x8001, 2); // length=1 (short header)
+ idx = buffer.Write(idx, 0U, 1); // data
+ (void)buffer.Write(idx, 0U, 2); // surplus (need 5 bytes total)
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+// Gather a 2-byte v2 header, with a zero fragment length.
+TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x8000, 2); // length=0 (short header)
+ (void)buffer.Write(idx, 0U, 3); // surplus (need 5 bytes total)
+
+ ConnectExpectMalformedClientHello(buffer);
+}
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_gtest.cc b/security/nss/gtests/ssl_gtest/ssl_gtest.cc
index 2d08dd865..cd10076b8 100644
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.cc
@@ -31,12 +31,18 @@ int main(int argc, char** argv) {
}
}
- NSS_Initialize(g_working_dir_path.c_str(), "", "", SECMOD_DB,
- NSS_INIT_READONLY);
- NSS_SetDomesticPolicy();
+ if (NSS_Initialize(g_working_dir_path.c_str(), "", "", SECMOD_DB,
+ NSS_INIT_READONLY) != SECSuccess) {
+ return 1;
+ }
+ if (NSS_SetDomesticPolicy() != SECSuccess) {
+ return 1;
+ }
int rv = RUN_ALL_TESTS();
- NSS_Shutdown();
+ if (NSS_Shutdown() != SECSuccess) {
+ return 1;
+ }
nss_test::Poller::Shutdown();
diff --git a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
index e232a8b7e..8cd7d1009 100644
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -12,6 +12,7 @@
'type': 'executable',
'sources': [
'libssl_internals.c',
+ 'selfencrypt_unittest.cc',
'ssl_0rtt_unittest.cc',
'ssl_agent_unittest.cc',
'ssl_auth_unittest.cc',
@@ -25,6 +26,8 @@
'ssl_exporter_unittest.cc',
'ssl_extension_unittest.cc',
'ssl_fuzz_unittest.cc',
+ 'ssl_fragment_unittest.cc',
+ 'ssl_gather_unittest.cc',
'ssl_gtest.cc',
'ssl_hrr_unittest.cc',
'ssl_loopback_unittest.cc',
@@ -34,55 +37,49 @@
'ssl_staticrsa_unittest.cc',
'ssl_v2_client_hello_unittest.cc',
'ssl_version_unittest.cc',
+ 'ssl_versionpolicy_unittest.cc',
'test_io.cc',
'tls_agent.cc',
'tls_connect.cc',
'tls_filter.cc',
'tls_hkdf_unittest.cc',
- 'tls_parser.cc'
+ 'tls_protect.cc'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'<(DEPTH)/lib/util/util.gyp:nssutil3',
- '<(DEPTH)/lib/sqlite/sqlite.gyp:sqlite3',
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
- '<(DEPTH)/lib/softoken/softoken.gyp:softokn',
'<(DEPTH)/lib/smime/smime.gyp:smime',
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
- '<(DEPTH)/cmd/lib/lib.gyp:sectool',
'<(DEPTH)/lib/pkcs12/pkcs12.gyp:pkcs12',
'<(DEPTH)/lib/pkcs7/pkcs7.gyp:pkcs7',
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
- '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
- '<(DEPTH)/lib/softoken/softoken.gyp:softokn',
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/base/base.gyp:nssb',
- '<(DEPTH)/lib/freebl/freebl.gyp:<(freebl_name)',
- '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
+ '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib',
+ '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
+ '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
],
'conditions': [
- [ 'disable_dbm==0', {
+ [ 'test_build==1', {
'dependencies': [
- '<(DEPTH)/lib/dbm/src/src.gyp:dbm',
+ '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
+ ],
+ }, {
+ 'dependencies': [
+ '<(DEPTH)/lib/sqlite/sqlite.gyp:sqlite3',
+ '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
+ '<(DEPTH)/lib/softoken/softoken.gyp:softokn',
+ '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
],
}],
- [ 'disable_libpkix==0', {
+ [ 'disable_dbm==0', {
'dependencies': [
- '<(DEPTH)/lib/libpkix/pkix/certsel/certsel.gyp:pkixcertsel',
- '<(DEPTH)/lib/libpkix/pkix/checker/checker.gyp:pkixchecker',
- '<(DEPTH)/lib/libpkix/pkix/crlsel/crlsel.gyp:pkixcrlsel',
- '<(DEPTH)/lib/libpkix/pkix/params/params.gyp:pkixparams',
- '<(DEPTH)/lib/libpkix/pkix/results/results.gyp:pkixresults',
- '<(DEPTH)/lib/libpkix/pkix/store/store.gyp:pkixstore',
- '<(DEPTH)/lib/libpkix/pkix/top/top.gyp:pkixtop',
- '<(DEPTH)/lib/libpkix/pkix/util/util.gyp:pkixutil',
- '<(DEPTH)/lib/libpkix/pkix_pl_nss/system/system.gyp:pkixsystem',
- '<(DEPTH)/lib/libpkix/pkix_pl_nss/module/module.gyp:pkixmodule',
- '<(DEPTH)/lib/libpkix/pkix_pl_nss/pki/pki.gyp:pkixpki',
+ '<(DEPTH)/lib/dbm/src/src.gyp:dbm',
],
}],
],
@@ -90,10 +87,11 @@
],
'target_defaults': {
'include_dirs': [
- '../../gtests/google_test/gtest/include',
- '../../gtests/common',
'../../lib/ssl'
],
+ 'defines': [
+ 'NSS_USE_STATIC_LIBS'
+ ],
},
'variables': {
'module': 'nss',
diff --git a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
index 5d670fa82..39055f641 100644
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -34,7 +34,8 @@ TEST_P(TlsConnectTls13, HelloRetryRequestAbortsZeroRtt) {
ExpectResumption(RESUME_TICKET);
// Send first ClientHello and send 0-RTT data
- auto capture_early_data = new TlsExtensionCapture(ssl_tls13_early_data_xtn);
+ auto capture_early_data =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_early_data_xtn);
client_->SetPacketFilter(capture_early_data);
client_->Handshake();
EXPECT_EQ(k0RttDataLen, PR_Write(client_->ssl_fd(), k0RttData,
@@ -42,8 +43,8 @@ TEST_P(TlsConnectTls13, HelloRetryRequestAbortsZeroRtt) {
EXPECT_TRUE(capture_early_data->captured());
// Send the HelloRetryRequest
- auto hrr_capture =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+ auto hrr_capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeHelloRetryRequest);
server_->SetPacketFilter(hrr_capture);
server_->Handshake();
EXPECT_LT(0U, hrr_capture->buffer().len());
@@ -54,7 +55,8 @@ TEST_P(TlsConnectTls13, HelloRetryRequestAbortsZeroRtt) {
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
// Make a new capture for the early data.
- capture_early_data = new TlsExtensionCapture(ssl_tls13_early_data_xtn);
+ capture_early_data =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_early_data_xtn);
client_->SetPacketFilter(capture_early_data);
// Complete the handshake successfully
@@ -65,6 +67,88 @@ TEST_P(TlsConnectTls13, HelloRetryRequestAbortsZeroRtt) {
EXPECT_FALSE(capture_early_data->captured());
}
+// This filter only works for DTLS 1.3 where there is exactly one handshake
+// packet. If the record is split into two packets, or there are multiple
+// handshake packets, this will break.
+class CorrectMessageSeqAfterHrrFilter : public TlsRecordFilter {
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& record, size_t* offset,
+ DataBuffer* output) {
+ if (filtered_packets() > 0 || header.content_type() != content_handshake) {
+ return KEEP;
+ }
+
+ DataBuffer buffer(record);
+ TlsRecordHeader new_header = {header.version(), header.content_type(),
+ header.sequence_number() + 1};
+
+ // Correct message_seq.
+ buffer.Write(4, 1U, 2);
+
+ *offset = new_header.Write(output, *offset, buffer);
+ return CHANGE;
+ }
+};
+
+TEST_P(TlsConnectTls13, SecondClientHelloRejectEarlyDataXtn) {
+ static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
+ ssl_grp_ec_secp521r1};
+
+ SetupForZeroRtt();
+ ExpectResumption(RESUME_TICKET);
+
+ client_->ConfigNamedGroups(groups);
+ server_->ConfigNamedGroups(groups);
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+
+ // A new client that tries to resume with 0-RTT but doesn't send the
+ // correct key share(s). The server will respond with an HRR.
+ auto orig_client =
+ std::make_shared<TlsAgent>(client_->name(), TlsAgent::CLIENT, variant_);
+ client_.swap(orig_client);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ client_->ConfigureSessionCache(RESUME_BOTH);
+ client_->Set0RttEnabled(true);
+ client_->StartConnect();
+
+ // Swap in the new client.
+ client_->SetPeer(server_);
+ server_->SetPeer(client_);
+
+ // Send the ClientHello.
+ client_->Handshake();
+ // Process the CH, send an HRR.
+ server_->Handshake();
+
+ // Swap the client we created manually with the one that successfully
+ // received a PSK, and try to resume with 0-RTT. The client doesn't know
+ // about the HRR so it will send the early_data xtn as well as 0-RTT data.
+ client_.swap(orig_client);
+ orig_client.reset();
+
+ // Correct the DTLS message sequence number after an HRR.
+ if (variant_ == ssl_variant_datagram) {
+ client_->SetPacketFilter(
+ std::make_shared<CorrectMessageSeqAfterHrrFilter>());
+ }
+
+ server_->SetPeer(client_);
+ client_->Handshake();
+
+ // Send 0-RTT data.
+ const char* k0RttData = "ABCDEF";
+ const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
+ PRInt32 rv = PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen);
+ EXPECT_EQ(k0RttDataLen, rv);
+
+ ExpectAlert(server_, kTlsAlertUnsupportedExtension);
+ Handshake();
+ client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT);
+}
+
class KeyShareReplayer : public TlsExtensionFilter {
public:
KeyShareReplayer() {}
@@ -94,11 +178,11 @@ class KeyShareReplayer : public TlsExtensionFilter {
// server should reject this.
TEST_P(TlsConnectTls13, RetryWithSameKeyShare) {
EnsureTlsSetup();
- client_->SetPacketFilter(new KeyShareReplayer());
+ client_->SetPacketFilter(std::make_shared<KeyShareReplayer>());
static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1};
server_->ConfigNamedGroups(groups);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_BAD_2ND_CLIENT_HELLO, server_->error_code());
EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, client_->error_code());
}
@@ -109,7 +193,7 @@ TEST_F(TlsConnectDatagram13, DropClientSecondFlightWithHelloRetry) {
static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1};
server_->ConfigNamedGroups(groups);
- server_->SetPacketFilter(new SelectiveDropFilter(0x2));
+ server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x2));
Connect();
}
@@ -169,16 +253,13 @@ TEST_F(TlsConnectTest, Select12AfterHelloRetryRequest) {
// Here we replace the TLS server with one that does TLS 1.2 only.
// This will happily send the client a TLS 1.2 ServerHello.
- TlsAgent* replacement_server =
- new TlsAgent(server_->name(), TlsAgent::SERVER, mode_);
- delete server_;
- server_ = replacement_server;
- server_->Init();
+ server_.reset(new TlsAgent(server_->name(), TlsAgent::SERVER, variant_));
client_->SetPeer(server_);
server_->SetPeer(client_);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->StartConnect();
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
Handshake();
EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, server_->error_code());
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
@@ -189,8 +270,6 @@ class HelloRetryRequestAgentTest : public TlsAgentTestClient {
void SetUp() override {
TlsAgentTestClient::SetUp();
EnsureInit();
- agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
- SSL_LIBRARY_VERSION_TLS_1_3);
agent_->StartConnect();
}
@@ -232,6 +311,7 @@ TEST_P(HelloRetryRequestAgentTest, SendSecondHelloRetryRequest) {
MakeGroupHrr(ssl_grp_ec_secp384r1, &hrr, 0);
ProcessMessage(hrr, TlsAgent::STATE_CONNECTING);
MakeGroupHrr(ssl_grp_ec_secp521r1, &hrr, 1);
+ ExpectAlert(kTlsAlertUnexpectedMessage);
ProcessMessage(hrr, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST);
}
@@ -241,6 +321,7 @@ TEST_P(HelloRetryRequestAgentTest, SendSecondHelloRetryRequest) {
TEST_P(HelloRetryRequestAgentTest, HandleBogusHelloRetryRequest) {
DataBuffer hrr;
MakeGroupHrr(ssl_grp_ec_curve25519, &hrr);
+ ExpectAlert(kTlsAlertIllegalParameter);
ProcessMessage(hrr, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
}
@@ -248,6 +329,7 @@ TEST_P(HelloRetryRequestAgentTest, HandleBogusHelloRetryRequest) {
TEST_P(HelloRetryRequestAgentTest, HandleNoopHelloRetryRequest) {
DataBuffer hrr;
MakeCannedHrr(nullptr, 0U, &hrr);
+ ExpectAlert(kTlsAlertDecodeError);
ProcessMessage(hrr, TlsAgent::STATE_ERROR,
SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
}
@@ -265,7 +347,7 @@ TEST_P(HelloRetryRequestAgentTest, HandleHelloRetryRequestCookie) {
0x13};
DataBuffer hrr;
MakeCannedHrr(canned_cookie_hrr, sizeof(canned_cookie_hrr), &hrr);
- TlsExtensionCapture* capture = new TlsExtensionCapture(ssl_tls13_cookie_xtn);
+ auto capture = std::make_shared<TlsExtensionCapture>(ssl_tls13_cookie_xtn);
agent_->SetPacketFilter(capture);
ProcessMessage(hrr, TlsAgent::STATE_CONNECTING);
const size_t cookie_pos = 2 + 2; // cookie_xtn, extension len
@@ -275,10 +357,11 @@ TEST_P(HelloRetryRequestAgentTest, HandleHelloRetryRequestCookie) {
}
INSTANTIATE_TEST_CASE_P(HelloRetryRequestAgentTests, HelloRetryRequestAgentTest,
- TlsConnectTestBase::kTlsModesAll);
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ TlsConnectTestBase::kTlsV13));
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(HelloRetryRequestKeyExchangeTests, TlsKeyExchange13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
#endif
diff --git a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
index 65c0ca1f8..77703dd8e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -39,7 +39,7 @@ TEST_P(TlsConnectGeneric, ConnectEcdsa) {
CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
}
-TEST_P(TlsConnectGenericPre13, CipherSuiteMismatch) {
+TEST_P(TlsConnectGeneric, CipherSuiteMismatch) {
EnsureTlsSetup();
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
@@ -48,11 +48,97 @@ TEST_P(TlsConnectGenericPre13, CipherSuiteMismatch) {
client_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
}
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
+class TlsAlertRecorder : public TlsRecordFilter {
+ public:
+ TlsAlertRecorder() : level_(255), description_(255) {}
+
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) override {
+ if (level_ != 255) { // Already captured.
+ return KEEP;
+ }
+ if (header.content_type() != kTlsAlertType) {
+ return KEEP;
+ }
+
+ std::cerr << "Alert: " << input << std::endl;
+
+ TlsParser parser(input);
+ EXPECT_TRUE(parser.Read(&level_));
+ EXPECT_TRUE(parser.Read(&description_));
+ return KEEP;
+ }
+
+ uint8_t level() const { return level_; }
+ uint8_t description() const { return description_; }
+
+ private:
+ uint8_t level_;
+ uint8_t description_;
+};
+
+class HelloTruncator : public TlsHandshakeFilter {
+ PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) override {
+ if (header.handshake_type() != kTlsHandshakeClientHello &&
+ header.handshake_type() != kTlsHandshakeServerHello) {
+ return KEEP;
+ }
+ output->Assign(input.data(), input.len() - 1);
+ return CHANGE;
+ }
+};
+
+// Verify that when NSS reports that an alert is sent, it is actually sent.
+TEST_P(TlsConnectGeneric, CaptureAlertServer) {
+ client_->SetPacketFilter(std::make_shared<HelloTruncator>());
+ auto alert_recorder = std::make_shared<TlsAlertRecorder>();
+ server_->SetPacketFilter(alert_recorder);
+
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertIllegalParameter, alert_recorder->description());
+}
+
+TEST_P(TlsConnectGenericPre13, CaptureAlertClient) {
+ server_->SetPacketFilter(std::make_shared<HelloTruncator>());
+ auto alert_recorder = std::make_shared<TlsAlertRecorder>();
+ client_->SetPacketFilter(alert_recorder);
+
+ ConnectExpectAlert(client_, kTlsAlertDecodeError);
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertDecodeError, alert_recorder->description());
+}
+
+// In TLS 1.3, the server can't read the client alert.
+TEST_P(TlsConnectTls13, CaptureAlertClient) {
+ server_->SetPacketFilter(std::make_shared<HelloTruncator>());
+ auto alert_recorder = std::make_shared<TlsAlertRecorder>();
+ client_->SetPacketFilter(alert_recorder);
+
+ server_->StartConnect();
+ client_->StartConnect();
+
+ client_->Handshake();
+ client_->ExpectSendAlert(kTlsAlertDecodeError);
+ server_->Handshake();
+ client_->Handshake();
+ if (variant_ == ssl_variant_stream) {
+ // DTLS just drops the alert it can't decrypt.
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ }
+ server_->Handshake();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertDecodeError, alert_recorder->description());
+}
+
TEST_P(TlsConnectGenericPre13, ConnectFalseStart) {
client_->EnableFalseStart();
Connect();
@@ -112,8 +198,10 @@ TEST_P(TlsConnectGeneric, ConnectSendReceive) {
TEST_P(TlsConnectDatagram, ShortRead) {
Connect();
client_->ExpectReadWriteError();
- server_->SendData(1200, 1200);
- client_->WaitForErrorCode(SSL_ERROR_RX_SHORT_DTLS_READ, 2000);
+ server_->SendData(50, 50);
+ client_->ReadBytes(20);
+ EXPECT_EQ(0U, client_->received_bytes());
+ EXPECT_EQ(SSL_ERROR_RX_SHORT_DTLS_READ, PORT_GetError());
// Now send and receive another packet.
server_->ResetSentBytes(); // Reset the counter.
@@ -127,13 +215,13 @@ TEST_P(TlsConnectStream, ShortRead) {
if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) return;
Connect();
- server_->SendData(1200, 1200);
+ server_->SendData(50, 50);
// Read the first tranche.
- WAIT_(client_->received_bytes() == 1024, 2000);
- ASSERT_EQ(1024U, client_->received_bytes());
+ client_->ReadBytes(20);
+ ASSERT_EQ(20U, client_->received_bytes());
// The second tranche should now immediately be available.
client_->ReadBytes();
- ASSERT_EQ(1200U, client_->received_bytes());
+ ASSERT_EQ(50U, client_->received_bytes());
}
TEST_P(TlsConnectGeneric, ConnectWithCompressionMaybe) {
@@ -141,7 +229,8 @@ TEST_P(TlsConnectGeneric, ConnectWithCompressionMaybe) {
client_->EnableCompression();
server_->EnableCompression();
Connect();
- EXPECT_EQ(client_->version() < SSL_LIBRARY_VERSION_TLS_1_3 && mode_ != DGRAM,
+ EXPECT_EQ(client_->version() < SSL_LIBRARY_VERSION_TLS_1_3 &&
+ variant_ != ssl_variant_datagram,
client_->is_compressed());
SendReceive();
}
@@ -161,16 +250,15 @@ TEST_P(TlsConnectDatagram, TestDtlsHolddownExpiry) {
class TlsPreCCSHeaderInjector : public TlsRecordFilter {
public:
TlsPreCCSHeaderInjector() {}
- virtual PacketFilter::Action FilterRecord(const RecordHeader& record_header,
- const DataBuffer& input,
- size_t* offset,
- DataBuffer* output) override {
+ virtual PacketFilter::Action FilterRecord(
+ const TlsRecordHeader& record_header, const DataBuffer& input,
+ size_t* offset, DataBuffer* output) override {
if (record_header.content_type() != kTlsChangeCipherSpecType) return KEEP;
std::cerr << "Injecting Finished header before CCS\n";
const uint8_t hhdr[] = {kTlsHandshakeFinished, 0x00, 0x00, 0x0c};
DataBuffer hhdr_buf(hhdr, sizeof(hhdr));
- RecordHeader nhdr(record_header.version(), kTlsHandshakeType, 0);
+ TlsRecordHeader nhdr(record_header.version(), kTlsHandshakeType, 0);
*offset = nhdr.Write(output, *offset, hhdr_buf);
*offset = record_header.Write(output, *offset, input);
return CHANGE;
@@ -178,24 +266,28 @@ class TlsPreCCSHeaderInjector : public TlsRecordFilter {
};
TEST_P(TlsConnectStreamPre13, ClientFinishedHeaderBeforeCCS) {
- client_->SetPacketFilter(new TlsPreCCSHeaderInjector());
- ConnectExpectFail();
+ client_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
+ ConnectExpectAlert(server_, kTlsAlertUnexpectedMessage);
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
}
TEST_P(TlsConnectStreamPre13, ServerFinishedHeaderBeforeCCS) {
- server_->SetPacketFilter(new TlsPreCCSHeaderInjector());
+ server_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
client_->StartConnect();
server_->StartConnect();
+ ExpectAlert(client_, kTlsAlertUnexpectedMessage);
Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
+ server_->Handshake(); // Make sure alert is consumed.
}
TEST_P(TlsConnectTls13, UnknownAlert) {
Connect();
+ server_->ExpectSendAlert(0xff, kTlsAlertWarning);
+ client_->ExpectReceiveAlert(0xff, kTlsAlertWarning);
SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
0xff); // Unknown value.
client_->ExpectReadWriteError();
@@ -204,20 +296,14 @@ TEST_P(TlsConnectTls13, UnknownAlert) {
TEST_P(TlsConnectTls13, AlertWrongLevel) {
Connect();
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage, kTlsAlertWarning);
+ client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage, kTlsAlertWarning);
SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
kTlsAlertUnexpectedMessage);
client_->ExpectReadWriteError();
client_->WaitForErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, 2000);
}
-TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
- client_->SetShortHeadersEnabled();
- server_->SetShortHeadersEnabled();
- client_->ExpectShortHeaders();
- server_->ExpectShortHeaders();
- Connect();
-}
-
TEST_F(TlsConnectStreamTls13, Tls13FailedWriteSecondFlight) {
EnsureTlsSetup();
client_->StartConnect();
@@ -229,12 +315,21 @@ TEST_F(TlsConnectStreamTls13, Tls13FailedWriteSecondFlight) {
client_->CheckErrorCode(SSL_ERROR_SOCKET_WRITE_FAILURE);
}
-INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsVAll));
+TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
+ client_->SetShortHeadersEnabled();
+ server_->SetShortHeadersEnabled();
+ client_->ExpectShortHeaders();
+ server_->ExpectShortHeaders();
+ Connect();
+}
+
+INSTANTIATE_TEST_CASE_P(
+ GenericStream, TlsConnectGeneric,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGeneric,
- ::testing::Combine(TlsConnectTestBase::kTlsModesDatagram,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus));
INSTANTIATE_TEST_CASE_P(StreamOnly, TlsConnectStream,
@@ -242,33 +337,35 @@ INSTANTIATE_TEST_CASE_P(StreamOnly, TlsConnectStream,
INSTANTIATE_TEST_CASE_P(DatagramOnly, TlsConnectDatagram,
TlsConnectTestBase::kTlsV11Plus);
-INSTANTIATE_TEST_CASE_P(Pre12Stream, TlsConnectPre12,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsV10V11));
+INSTANTIATE_TEST_CASE_P(
+ Pre12Stream, TlsConnectPre12,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10V11));
INSTANTIATE_TEST_CASE_P(
Pre12Datagram, TlsConnectPre12,
- ::testing::Combine(TlsConnectTestBase::kTlsModesDatagram,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11));
INSTANTIATE_TEST_CASE_P(Version12Only, TlsConnectTls12,
- TlsConnectTestBase::kTlsModesAll);
+ TlsConnectTestBase::kTlsVariantsAll);
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(Version13Only, TlsConnectTls13,
- TlsConnectTestBase::kTlsModesAll);
+ TlsConnectTestBase::kTlsVariantsAll);
#endif
-INSTANTIATE_TEST_CASE_P(Pre13Stream, TlsConnectGenericPre13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsV10ToV12));
+INSTANTIATE_TEST_CASE_P(
+ Pre13Stream, TlsConnectGenericPre13,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10ToV12));
INSTANTIATE_TEST_CASE_P(
Pre13Datagram, TlsConnectGenericPre13,
- ::testing::Combine(TlsConnectTestBase::kTlsModesDatagram,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(Pre13StreamOnly, TlsConnectStreamPre13,
TlsConnectTestBase::kTlsV10ToV12);
INSTANTIATE_TEST_CASE_P(Version12Plus, TlsConnectTls12Plus,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus));
} // namespace nspr_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
index cfe42cb9f..ce0e3ca8d 100644
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -21,6 +21,7 @@ extern "C" {
#include "tls_connect.h"
#include "tls_filter.h"
#include "tls_parser.h"
+#include "tls_protect.h"
namespace nss_test {
@@ -200,6 +201,87 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) {
SendReceive();
}
+TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtClient) {
+ SSLInt_SetTicketLifetime(1); // one second
+ // This causes a ticket resumption.
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive();
+
+ WAIT_(false, 1000);
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_NONE);
+
+ // TLS 1.3 uses the pre-shared key extension instead.
+ SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? ssl_tls13_pre_shared_key_xtn
+ : ssl_session_ticket_xtn;
+ auto capture = std::make_shared<TlsExtensionCapture>(xtn);
+ client_->SetPacketFilter(capture);
+ Connect();
+
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ EXPECT_FALSE(capture->captured());
+ } else {
+ EXPECT_TRUE(capture->captured());
+ EXPECT_EQ(0U, capture->extension().len());
+ }
+}
+
+TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
+ SSLInt_SetTicketLifetime(1); // one second
+ // This causes a ticket resumption.
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive();
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ExpectResumption(RESUME_NONE);
+
+ SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? ssl_tls13_pre_shared_key_xtn
+ : ssl_session_ticket_xtn;
+ auto capture = std::make_shared<TlsExtensionCapture>(xtn);
+ client_->SetPacketFilter(capture);
+ client_->StartConnect();
+ server_->StartConnect();
+ client_->Handshake();
+ EXPECT_TRUE(capture->captured());
+ EXPECT_LT(0U, capture->extension().len());
+
+ WAIT_(false, 1000); // Let the ticket expire on the server.
+
+ Handshake();
+ CheckConnected();
+}
+
+TEST_P(TlsConnectGeneric, ConnectResumeCorruptTicket) {
+ // This causes a ticket resumption.
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ Connect();
+ SendReceive();
+
+ Reset();
+ static const uint8_t kHmacKey1Buf[32] = {0};
+ static const DataBuffer kHmacKey1(kHmacKey1Buf, sizeof(kHmacKey1Buf));
+
+ SECItem key_item = {siBuffer, const_cast<uint8_t*>(kHmacKey1Buf),
+ sizeof(kHmacKey1Buf)};
+
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ PK11SymKey* hmac_key =
+ PK11_ImportSymKey(slot.get(), CKM_SHA256_HMAC, PK11_OriginUnwrap,
+ CKA_SIGN, &key_item, nullptr);
+ ASSERT_NE(nullptr, hmac_key);
+ SSLInt_SetSelfEncryptMacKey(hmac_key);
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ConnectExpectAlert(server_, illegal_parameter);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
// This callback switches out the "server" cert used on the server with
// the "client" certificate, which should be the same type.
static int32_t SwitchCertificates(TlsAgent* agent, const SECItem* srvNameArr,
@@ -245,8 +327,8 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
// Prior to TLS 1.3, we were not fully ephemeral; though 1.3 fixes that
TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
- TlsInspectorRecordHandshakeMessage* i1 =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+ auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerKeyExchange);
server_->SetPacketFilter(i1);
Connect();
CheckKeys();
@@ -255,8 +337,8 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
// Restart
Reset();
- TlsInspectorRecordHandshakeMessage* i2 =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+ auto i2 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerKeyExchange);
server_->SetPacketFilter(i2);
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
Connect();
@@ -277,8 +359,8 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) {
SECStatus rv =
SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
- TlsInspectorRecordHandshakeMessage* i1 =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+ auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerKeyExchange);
server_->SetPacketFilter(i1);
Connect();
CheckKeys();
@@ -290,8 +372,8 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) {
server_->EnsureTlsSetup();
rv = SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
- TlsInspectorRecordHandshakeMessage* i2 =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+ auto i2 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerKeyExchange);
server_->SetPacketFilter(i2);
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
Connect();
@@ -356,7 +438,7 @@ TEST_P(TlsConnectGeneric, TestResumeClientDifferentCipher) {
} else {
ticket_extension = ssl_session_ticket_xtn;
}
- auto ticket_capture = new TlsExtensionCapture(ticket_extension);
+ auto ticket_capture = std::make_shared<TlsExtensionCapture>(ticket_extension);
client_->SetPacketFilter(ticket_capture);
Connect();
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
@@ -420,9 +502,15 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
- server_->SetPacketFilter(
- new SelectedCipherSuiteReplacer(ChooseAnotherCipher(version_)));
+ server_->SetPacketFilter(std::make_shared<SelectedCipherSuiteReplacer>(
+ ChooseAnotherCipher(version_)));
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ } else {
+ ExpectAlert(client_, kTlsAlertHandshakeFailure);
+ }
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -459,7 +547,7 @@ class SelectedVersionReplacer : public TlsHandshakeFilter {
// lower version number on resumption.
TEST_P(TlsConnectGenericPre13, TestResumptionOverrideVersion) {
uint16_t override_version = 0;
- if (mode_ == STREAM) {
+ if (variant_ == ssl_variant_stream) {
switch (version_) {
case SSL_LIBRARY_VERSION_TLS_1_0:
return; // Skip the test.
@@ -492,9 +580,10 @@ TEST_P(TlsConnectGenericPre13, TestResumptionOverrideVersion) {
// Enable the lower version on the client.
client_->SetVersionRange(version_ - 1, version_);
server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
- server_->SetPacketFilter(new SelectedVersionReplacer(override_version));
+ server_->SetPacketFilter(
+ std::make_shared<SelectedVersionReplacer>(override_version));
- ConnectExpectFail();
+ ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
}
@@ -515,8 +604,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ExpectResumption(RESUME_TICKET);
- TlsExtensionCapture* c1 =
- new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+ auto c1 = std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
client_->SetPacketFilter(c1);
Connect();
SendReceive();
@@ -533,8 +621,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ClearStats();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
- TlsExtensionCapture* c2 =
- new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+ auto c2 = std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
client_->SetPacketFilter(c2);
ExpectResumption(RESUME_TICKET);
Connect();
@@ -564,7 +651,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNST) {
Connect();
// Clear the session ticket keys to invalidate the old ticket.
- SSLInt_ClearSessionTicketKey();
+ SSLInt_ClearSelfEncryptKey();
SSLInt_SendNewSessionTicket(server_->ssl_fd());
SendReceive(); // Need to read so that we absorb the session tickets.
@@ -579,4 +666,66 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNST) {
SendReceive();
}
+TEST_F(TlsConnectTest, TestTls13ResumptionDowngrade) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ Connect();
+
+ SendReceive(); // Need to read so that we absorb the session tickets.
+ CheckKeys();
+
+ // Try resuming the connection. This will fail resuming the 1.3 session
+ // from before, but will successfully establish a 1.2 connection.
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+ Connect();
+
+ // Renegotiate to ensure we don't carryover any state
+ // from the 1.3 resumption attempt.
+ client_->SetExpectedVersion(SSL_LIBRARY_VERSION_TLS_1_2);
+ client_->PrepareForRenegotiate();
+ server_->StartRenegotiate();
+ Handshake();
+
+ SendReceive();
+ CheckKeys();
+}
+
+TEST_F(TlsConnectTest, TestTls13ResumptionForcedDowngrade) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ Connect();
+
+ SendReceive(); // Need to read so that we absorb the session tickets.
+ CheckKeys();
+
+ // Try resuming the connection.
+ Reset();
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ // Enable the lower version on the client.
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+
+ // Add filters that set downgrade SH.version to 1.2 and the cipher suite
+ // to one that works with 1.2, so that we don't run into early sanity checks.
+ // We will eventually fail the (sid.version == SH.version) check.
+ std::vector<std::shared_ptr<PacketFilter>> filters;
+ filters.push_back(std::make_shared<SelectedCipherSuiteReplacer>(
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256));
+ filters.push_back(
+ std::make_shared<SelectedVersionReplacer>(SSL_LIBRARY_VERSION_TLS_1_2));
+ server_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(filters));
+
+ client_->ExpectSendAlert(kTlsAlertDecodeError);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac); // Server can't read
+ ConnectExpectFail();
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+}
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
index 523a37499..a130ef77f 100644
--- a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
@@ -28,9 +28,9 @@ class TlsHandshakeSkipFilter : public TlsRecordFilter {
protected:
// Takes a record; if it is a handshake record, it removes the first handshake
// message that is of handshake_type_ type.
- virtual PacketFilter::Action FilterRecord(const RecordHeader& record_header,
- const DataBuffer& input,
- DataBuffer* output) {
+ virtual PacketFilter::Action FilterRecord(
+ const TlsRecordHeader& record_header, const DataBuffer& input,
+ DataBuffer* output) {
if (record_header.content_type() != kTlsHandshakeType) {
return KEEP;
}
@@ -78,81 +78,162 @@ class TlsHandshakeSkipFilter : public TlsRecordFilter {
bool skipped_;
};
-class TlsSkipTest
- : public TlsConnectTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsSkipTest : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
protected:
TlsSkipTest()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
- void ServerSkipTest(PacketFilter* filter,
+ void ServerSkipTest(std::shared_ptr<PacketFilter> filter,
uint8_t alert = kTlsAlertUnexpectedMessage) {
- auto alert_recorder = new TlsAlertRecorder();
- client_->SetPacketFilter(alert_recorder);
- if (filter) {
- server_->SetPacketFilter(filter);
+ server_->SetPacketFilter(filter);
+ ConnectExpectAlert(client_, alert);
+ }
+};
+
+class Tls13SkipTest : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<SSLProtocolVariant> {
+ protected:
+ Tls13SkipTest()
+ : TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
+
+ void ServerSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
+ EnsureTlsSetup();
+ server_->SetTlsRecordFilter(filter);
+ filter->EnableDecryption();
+ client_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ if (variant_ == ssl_variant_stream) {
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+ } else {
+ ConnectExpectFailOneSide(TlsAgent::CLIENT);
+ }
+ client_->CheckErrorCode(error);
+ if (variant_ == ssl_variant_stream) {
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+ } else {
+ ASSERT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
}
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(alert, alert_recorder->description());
+ }
+
+ void ClientSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
+ EnsureTlsSetup();
+ client_->SetTlsRecordFilter(filter);
+ filter->EnableDecryption();
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ ConnectExpectFailOneSide(TlsAgent::SERVER);
+
+ server_->CheckErrorCode(error);
+ ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+
+ client_->Handshake(); // Make sure to consume the alert the server sends.
}
};
TEST_P(TlsSkipTest, SkipCertificateRsa) {
EnableOnlyStaticRsaCiphers();
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
}
TEST_P(TlsSkipTest, SkipCertificateDhe) {
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
}
TEST_P(TlsSkipTest, SkipCertificateEcdhe) {
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
}
TEST_P(TlsSkipTest, SkipCertificateEcdsa) {
Reset(TlsAgent::kServerEcdsa256);
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
}
TEST_P(TlsSkipTest, SkipServerKeyExchange) {
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
}
TEST_P(TlsSkipTest, SkipServerKeyExchangeEcdsa) {
Reset(TlsAgent::kServerEcdsa256);
- ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
}
TEST_P(TlsSkipTest, SkipCertAndKeyExch) {
- auto chain = new ChainedPacketFilter();
- chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
- chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+ auto chain = std::make_shared<ChainedPacketFilter>();
+ chain->Add(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
+ chain->Add(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
ServerSkipTest(chain);
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
}
TEST_P(TlsSkipTest, SkipCertAndKeyExchEcdsa) {
Reset(TlsAgent::kServerEcdsa256);
- auto chain = new ChainedPacketFilter();
- chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
- chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+ auto chain = std::make_shared<ChainedPacketFilter>();
+ chain->Add(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
+ chain->Add(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
ServerSkipTest(chain);
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
}
-INSTANTIATE_TEST_CASE_P(SkipTls10, TlsSkipTest,
- ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
- TlsConnectTestBase::kTlsV10));
+TEST_P(Tls13SkipTest, SkipEncryptedExtensions) {
+ ServerSkipTest(std::make_shared<TlsHandshakeSkipFilter>(
+ kTlsHandshakeEncryptedExtensions),
+ SSL_ERROR_RX_UNEXPECTED_CERTIFICATE);
+}
+
+TEST_P(Tls13SkipTest, SkipServerCertificate) {
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate),
+ SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+}
+
+TEST_P(Tls13SkipTest, SkipServerCertificateVerify) {
+ ServerSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
+ SSL_ERROR_RX_UNEXPECTED_FINISHED);
+}
+
+TEST_P(Tls13SkipTest, SkipClientCertificate) {
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+ client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
+ ClientSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate),
+ SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+}
+
+TEST_P(Tls13SkipTest, SkipClientCertificateVerify) {
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+ client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
+ ClientSkipTest(
+ std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
+ SSL_ERROR_RX_UNEXPECTED_FINISHED);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ SkipTls10, TlsSkipTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsV10));
INSTANTIATE_TEST_CASE_P(SkipVariants, TlsSkipTest,
- ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV11V12));
-
+INSTANTIATE_TEST_CASE_P(Skip13Variants, Tls13SkipTest,
+ TlsConnectTestBase::kTlsVariantsAll);
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
index baf24ed9c..8db1f30e1 100644
--- a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -48,28 +48,20 @@ TEST_P(TlsConnectGenericPre13, ConnectStaticRSA) {
// This test is stream so we can catch the bad_record_mac alert.
TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
EnableOnlyStaticRsaCiphers();
- TlsInspectorReplaceHandshakeMessage* i1 =
- new TlsInspectorReplaceHandshakeMessage(
- kTlsHandshakeClientKeyExchange,
- DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
+ auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
+ kTlsHandshakeClientKeyExchange,
+ DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
client_->SetPacketFilter(i1);
- auto alert_recorder = new TlsAlertRecorder();
- server_->SetPacketFilter(alert_recorder);
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+ ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
}
// Test that a PMS with a bogus version number is handled correctly.
// This test is stream so we can catch the bad_record_mac alert.
TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
EnableOnlyStaticRsaCiphers();
- client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
- auto alert_recorder = new TlsAlertRecorder();
- server_->SetPacketFilter(alert_recorder);
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+ client_->SetPacketFilter(
+ std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
+ ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
}
// Test that a PMS with a bogus version number is ignored when
@@ -77,7 +69,8 @@ TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
// ConnectStaticRSABogusPMSVersionDetect.
TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) {
EnableOnlyStaticRsaCiphers();
- client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
+ client_->SetPacketFilter(
+ std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
server_->DisableRollbackDetection();
Connect();
}
@@ -86,16 +79,11 @@ TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) {
TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusCKE) {
EnableOnlyStaticRsaCiphers();
EnableExtendedMasterSecret();
- TlsInspectorReplaceHandshakeMessage* inspect =
- new TlsInspectorReplaceHandshakeMessage(
- kTlsHandshakeClientKeyExchange,
- DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
+ auto inspect = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
+ kTlsHandshakeClientKeyExchange,
+ DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
client_->SetPacketFilter(inspect);
- auto alert_recorder = new TlsAlertRecorder();
- server_->SetPacketFilter(alert_recorder);
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+ ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
}
// This test is stream so we can catch the bad_record_mac alert.
@@ -103,19 +91,17 @@ TEST_P(TlsConnectStreamPre13,
ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
EnableOnlyStaticRsaCiphers();
EnableExtendedMasterSecret();
- client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
- auto alert_recorder = new TlsAlertRecorder();
- server_->SetPacketFilter(alert_recorder);
- ConnectExpectFail();
- EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+ client_->SetPacketFilter(
+ std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
+ ConnectExpectAlert(server_, kTlsAlertBadRecordMac);
}
TEST_P(TlsConnectStreamPre13,
ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
EnableOnlyStaticRsaCiphers();
EnableExtendedMasterSecret();
- client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
+ client_->SetPacketFilter(
+ std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
server_->DisableRollbackDetection();
Connect();
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
index 8b586beae..110e3e0b6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
@@ -23,7 +23,7 @@ namespace nss_test {
// Replaces the client hello with an SSLv2 version once.
class SSLv2ClientHelloFilter : public PacketFilter {
public:
- SSLv2ClientHelloFilter(TlsAgent* client, uint16_t version)
+ SSLv2ClientHelloFilter(std::shared_ptr<TlsAgent>& client, uint16_t version)
: replaced_(false),
client_(client),
version_(version),
@@ -121,7 +121,7 @@ class SSLv2ClientHelloFilter : public PacketFilter {
// Update the client random so that the handshake succeeds.
SECStatus rv = SSLInt_UpdateSSLv2ClientRandom(
- client_->ssl_fd(), challenge.data(), challenge.size(),
+ client_.lock()->ssl_fd(), challenge.data(), challenge.size(),
output->data() + hdr_len, output->len() - hdr_len);
EXPECT_EQ(SECSuccess, rv);
@@ -130,7 +130,7 @@ class SSLv2ClientHelloFilter : public PacketFilter {
private:
bool replaced_;
- TlsAgent* client_;
+ std::weak_ptr<TlsAgent> client_;
uint16_t version_;
uint8_t pad_len_;
uint8_t reported_pad_len_;
@@ -141,14 +141,15 @@ class SSLv2ClientHelloFilter : public PacketFilter {
class SSLv2ClientHelloTestF : public TlsConnectTestBase {
public:
- SSLv2ClientHelloTestF() : TlsConnectTestBase(STREAM, 0), filter_(nullptr) {}
+ SSLv2ClientHelloTestF()
+ : TlsConnectTestBase(ssl_variant_stream, 0), filter_(nullptr) {}
- SSLv2ClientHelloTestF(Mode mode, uint16_t version)
- : TlsConnectTestBase(mode, version), filter_(nullptr) {}
+ SSLv2ClientHelloTestF(SSLProtocolVariant variant, uint16_t version)
+ : TlsConnectTestBase(variant, version), filter_(nullptr) {}
void SetUp() {
TlsConnectTestBase::SetUp();
- filter_ = new SSLv2ClientHelloFilter(client_, version_);
+ filter_ = std::make_shared<SSLv2ClientHelloFilter>(client_, version_);
client_->SetPacketFilter(filter_);
}
@@ -185,7 +186,7 @@ class SSLv2ClientHelloTestF : public TlsConnectTestBase {
void SetSendEscape(bool send_escape) { filter_->SetSendEscape(send_escape); }
private:
- SSLv2ClientHelloFilter* filter_;
+ std::shared_ptr<SSLv2ClientHelloFilter> filter_;
};
// Parameterized version of SSLv2ClientHelloTestF we can
@@ -193,7 +194,8 @@ class SSLv2ClientHelloTestF : public TlsConnectTestBase {
class SSLv2ClientHelloTest : public SSLv2ClientHelloTestF,
public ::testing::WithParamInterface<uint16_t> {
public:
- SSLv2ClientHelloTest() : SSLv2ClientHelloTestF(STREAM, GetParam()) {}
+ SSLv2ClientHelloTest()
+ : SSLv2ClientHelloTestF(ssl_variant_stream, GetParam()) {}
};
// Test negotiating TLS 1.0 - 1.2.
@@ -202,6 +204,28 @@ TEST_P(SSLv2ClientHelloTest, Connect) {
Connect();
}
+// Sending a v2 ClientHello after a no-op v3 record must fail.
+TEST_P(SSLv2ClientHelloTest, ConnectAfterEmptyV3Record) {
+ DataBuffer buffer;
+
+ size_t idx = 0;
+ idx = buffer.Write(idx, 0x16, 1); // handshake
+ idx = buffer.Write(idx, 0x0301, 2); // record_version
+ (void)buffer.Write(idx, 0U, 2); // length=0
+
+ SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
+ EnsureTlsSetup();
+ client_->SendDirect(buffer);
+
+ // Need padding so the connection doesn't just time out. With a v2
+ // ClientHello parsed as a v3 record we will use the record version
+ // as the record length.
+ SetPadding(255);
+
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ EXPECT_EQ(SSL_ERROR_BAD_CLIENT, server_->error_code());
+}
+
// Test negotiating TLS 1.3.
TEST_F(SSLv2ClientHelloTestF, Connect13) {
EnsureTlsSetup();
@@ -211,7 +235,7 @@ TEST_F(SSLv2ClientHelloTestF, Connect13) {
std::vector<uint16_t> cipher_suites = {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256};
SetAvailableCipherSuites(cipher_suites);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
}
@@ -238,7 +262,7 @@ TEST_P(SSLv2ClientHelloTest, SendSecurityEscape) {
// Set a big padding so that the server fails instead of timing out.
SetPadding(255);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
}
// Invalid SSLv2 client hello padding must fail the handshake.
@@ -248,7 +272,7 @@ TEST_P(SSLv2ClientHelloTest, AddErroneousPadding) {
// Append 5 bytes of padding but say it's only 4.
SetPadding(5, 4);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
}
@@ -259,7 +283,7 @@ TEST_P(SSLv2ClientHelloTest, AddErroneousPadding2) {
// Append 5 bytes of padding but say it's 6.
SetPadding(5, 6);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
}
@@ -270,7 +294,7 @@ TEST_P(SSLv2ClientHelloTest, SmallClientRandom) {
// Send a ClientRandom that's too small.
SetClientRandomLength(15);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
}
@@ -288,7 +312,7 @@ TEST_P(SSLv2ClientHelloTest, BigClientRandom) {
// Send a ClientRandom that's too big.
SetClientRandomLength(33);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, server_->error_code());
}
@@ -297,7 +321,7 @@ TEST_P(SSLv2ClientHelloTest, BigClientRandom) {
TEST_P(SSLv2ClientHelloTest, RequireSafeRenegotiation) {
RequireSafeRenegotiation();
SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
EXPECT_EQ(SSL_ERROR_UNSAFE_NEGOTIATION, server_->error_code());
}
@@ -339,7 +363,7 @@ TEST_F(SSLv2ClientHelloTestF, InappropriateFallbackSCSV) {
TLS_FALLBACK_SCSV};
SetAvailableCipherSuites(cipher_suites);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertInappropriateFallback);
EXPECT_EQ(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, server_->error_code());
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
index b3538497e..379a67e35 100644
--- a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
@@ -57,7 +57,8 @@ TEST_P(TlsConnectGeneric, ServerNegotiateTls12) {
// SSL_SetDowngradeCheckVersion() API.
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
client_->SetPacketFilter(
- new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_1));
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ SSL_LIBRARY_VERSION_TLS_1_1));
ConnectExpectFail();
ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
}
@@ -65,7 +66,8 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
/* Attempt to negotiate the bogus DTLS 1.1 version. */
TEST_F(DtlsConnectTest, TestDtlsVersion11) {
client_->SetPacketFilter(
- new TlsInspectorClientHelloVersionSetter(((~0x0101) & 0xffff)));
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ ((~0x0101) & 0xffff)));
ConnectExpectFail();
// It's kind of surprising that SSL_ERROR_NO_CYPHER_OVERLAP is
// what is returned here, but this is deliberate in ssl3_HandleAlert().
@@ -77,7 +79,8 @@ TEST_F(DtlsConnectTest, TestDtlsVersion11) {
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls12) {
EnsureTlsSetup();
client_->SetPacketFilter(
- new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_2));
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ SSL_LIBRARY_VERSION_TLS_1_2));
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
@@ -90,7 +93,8 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls12) {
// instead get a handshake failure alert from the server.
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
client_->SetPacketFilter(
- new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_0));
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ SSL_LIBRARY_VERSION_TLS_1_0));
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_1);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
@@ -123,6 +127,18 @@ TEST_F(TlsConnectTest, TestFallbackFromTls13) {
}
#endif
+TEST_P(TlsConnectGeneric, TestFallbackSCSVVersionMatch) {
+ client_->SetFallbackSCSVEnabled(true);
+ Connect();
+}
+
+TEST_P(TlsConnectGenericPre13, TestFallbackSCSVVersionMismatch) {
+ client_->SetFallbackSCSVEnabled(true);
+ server_->SetVersionRange(version_, version_ + 1);
+ ConnectExpectAlert(server_, kTlsAlertInappropriateFallback);
+ client_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT);
+}
+
// The TLS v1.3 spec section C.4 states that 'Implementations MUST NOT send or
// accept any records with a version less than { 3, 0 }'. Thus we will not
// allow version ranges including both SSL v3 and TLS v1.3.
@@ -161,6 +177,13 @@ TEST_P(TlsConnectStream, ConnectTls10AndServerRenegotiateHigher) {
// doesn't fail.
server_->ResetPreliminaryInfo();
server_->StartRenegotiate();
+
+ if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+ } else {
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
+ }
+
Handshake();
if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
// In TLS 1.3, the server detects this problem.
@@ -194,6 +217,11 @@ TEST_P(TlsConnectStream, ConnectTls10AndClientRenegotiateHigher) {
// doesn't fail.
server_->ResetPreliminaryInfo();
client_->StartRenegotiate();
+ if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ ExpectAlert(server_, kTlsAlertUnexpectedMessage);
+ } else {
+ ExpectAlert(client_, kTlsAlertIllegalParameter);
+ }
Handshake();
if (test_version >= SSL_LIBRARY_VERSION_TLS_1_3) {
// In TLS 1.3, the server detects this problem.
@@ -225,13 +253,14 @@ TEST_F(TlsConnectTest, Tls13RejectsRehandshakeServer) {
TEST_P(TlsConnectGeneric, AlertBeforeServerHello) {
EnsureTlsSetup();
+ client_->ExpectReceiveAlert(kTlsAlertUnrecognizedName, kTlsAlertWarning);
client_->StartConnect();
server_->StartConnect();
client_->Handshake(); // Send ClientHello.
static const uint8_t kWarningAlert[] = {kTlsAlertWarning,
kTlsAlertUnrecognizedName};
DataBuffer alert;
- TlsAgentTestBase::MakeRecord(mode_, kTlsAlertType,
+ TlsAgentTestBase::MakeRecord(variant_, kTlsAlertType,
SSL_LIBRARY_VERSION_TLS_1_0, kWarningAlert,
PR_ARRAY_SIZE(kWarningAlert), &alert);
client_->adapter()->PacketReceived(alert);
@@ -246,11 +275,12 @@ class Tls13NoSupportedVersions : public TlsConnectStreamTls12 {
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, max_server_version);
client_->SetPacketFilter(
- new TlsInspectorClientHelloVersionSetter(overwritten_client_version));
- auto capture =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerHello);
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ overwritten_client_version));
+ auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerHello);
server_->SetPacketFilter(capture);
- ConnectExpectFail();
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
const DataBuffer& server_hello = capture->buffer();
@@ -281,11 +311,14 @@ TEST_F(Tls13NoSupportedVersions,
// Offer 1.3 but with ClientHello.legacy_version == TLS 1.4. This
// causes a bad MAC error when we read EncryptedExtensions.
TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) {
- client_->SetPacketFilter(new TlsInspectorClientHelloVersionSetter(
- SSL_LIBRARY_VERSION_TLS_1_3 + 1));
- auto capture =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerHello);
+ client_->SetPacketFilter(
+ std::make_shared<TlsInspectorClientHelloVersionSetter>(
+ SSL_LIBRARY_VERSION_TLS_1_3 + 1));
+ auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerHello);
server_->SetPacketFilter(capture);
+ client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
diff --git a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
new file mode 100644
index 000000000..eda96831c
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
@@ -0,0 +1,394 @@
+/* -*- 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 "nss.h"
+#include "secerr.h"
+#include "ssl.h"
+#include "ssl3prot.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+#include <iostream>
+
+namespace nss_test {
+
+std::string GetSSLVersionString(uint16_t v) {
+ switch (v) {
+ case SSL_LIBRARY_VERSION_3_0:
+ return "ssl3";
+ case SSL_LIBRARY_VERSION_TLS_1_0:
+ return "tls1.0";
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ return "tls1.1";
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ return "tls1.2";
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ return "tls1.3";
+ case SSL_LIBRARY_VERSION_NONE:
+ return "NONE";
+ }
+ if (v < SSL_LIBRARY_VERSION_3_0) {
+ return "undefined-too-low";
+ }
+ return "undefined-too-high";
+}
+
+inline std::ostream& operator<<(std::ostream& stream,
+ const SSLVersionRange& vr) {
+ return stream << GetSSLVersionString(vr.min) << ","
+ << GetSSLVersionString(vr.max);
+}
+
+class VersionRangeWithLabel {
+ public:
+ VersionRangeWithLabel(const std::string& label, const SSLVersionRange& vr)
+ : label_(label), vr_(vr) {}
+ VersionRangeWithLabel(const std::string& label, uint16_t min, uint16_t max)
+ : label_(label) {
+ vr_.min = min;
+ vr_.max = max;
+ }
+ VersionRangeWithLabel(const std::string& label) : label_(label) {
+ vr_.min = vr_.max = SSL_LIBRARY_VERSION_NONE;
+ }
+
+ void WriteStream(std::ostream& stream) const {
+ stream << " " << label_ << ": " << vr_;
+ }
+
+ uint16_t min() const { return vr_.min; }
+ uint16_t max() const { return vr_.max; }
+ SSLVersionRange range() const { return vr_; }
+
+ private:
+ std::string label_;
+ SSLVersionRange vr_;
+};
+
+inline std::ostream& operator<<(std::ostream& stream,
+ const VersionRangeWithLabel& vrwl) {
+ vrwl.WriteStream(stream);
+ return stream;
+}
+
+typedef std::tuple<SSLProtocolVariant, // variant
+ uint16_t, // policy min
+ uint16_t, // policy max
+ uint16_t, // input min
+ uint16_t> // input max
+ PolicyVersionRangeInput;
+
+class TestPolicyVersionRange
+ : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<PolicyVersionRangeInput> {
+ public:
+ TestPolicyVersionRange()
+ : TlsConnectTestBase(std::get<0>(GetParam()), 0),
+ variant_(std::get<0>(GetParam())),
+ policy_("policy", std::get<1>(GetParam()), std::get<2>(GetParam())),
+ input_("input", std::get<3>(GetParam()), std::get<4>(GetParam())),
+ library_("supported-by-library",
+ ((variant_ == ssl_variant_stream)
+ ? SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM
+ : SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM),
+ SSL_LIBRARY_VERSION_MAX_SUPPORTED) {
+ TlsConnectTestBase::SkipVersionChecks();
+ }
+
+ void SetPolicy(const SSLVersionRange& policy) {
+ NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0);
+
+ SECStatus rv;
+ rv = NSS_OptionSet(NSS_TLS_VERSION_MIN_POLICY, policy.min);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_TLS_VERSION_MAX_POLICY, policy.max);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_DTLS_VERSION_MIN_POLICY, policy.min);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_DTLS_VERSION_MAX_POLICY, policy.max);
+ ASSERT_EQ(SECSuccess, rv);
+ }
+
+ void CreateDummySocket(std::shared_ptr<DummyPrSocket>* dummy_socket,
+ ScopedPRFileDesc* ssl_fd) {
+ (*dummy_socket).reset(new DummyPrSocket("dummy", variant_));
+ *ssl_fd = (*dummy_socket)->CreateFD();
+ if (variant_ == ssl_variant_stream) {
+ SSL_ImportFD(nullptr, ssl_fd->get());
+ } else {
+ DTLS_ImportFD(nullptr, ssl_fd->get());
+ }
+ }
+
+ bool GetOverlap(const SSLVersionRange& r1, const SSLVersionRange& r2,
+ SSLVersionRange* overlap) {
+ if (r1.min == SSL_LIBRARY_VERSION_NONE ||
+ r1.max == SSL_LIBRARY_VERSION_NONE ||
+ r2.min == SSL_LIBRARY_VERSION_NONE ||
+ r2.max == SSL_LIBRARY_VERSION_NONE) {
+ return false;
+ }
+
+ SSLVersionRange temp;
+ temp.min = PR_MAX(r1.min, r2.min);
+ temp.max = PR_MIN(r1.max, r2.max);
+
+ if (temp.min > temp.max) {
+ return false;
+ }
+
+ *overlap = temp;
+ return true;
+ }
+
+ bool IsValidInputForVersionRangeSet(SSLVersionRange* expectedEffectiveRange) {
+ if (input_.min() <= SSL_LIBRARY_VERSION_3_0 &&
+ input_.max() >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ // This is always invalid input, independent of policy
+ return false;
+ }
+
+ if (input_.min() < library_.min() || input_.max() > library_.max() ||
+ input_.min() > input_.max()) {
+ // Asking for unsupported ranges is invalid input for VersionRangeSet
+ // APIs, regardless of overlap.
+ return false;
+ }
+
+ SSLVersionRange overlap_with_library;
+ if (!GetOverlap(input_.range(), library_.range(), &overlap_with_library)) {
+ return false;
+ }
+
+ SSLVersionRange overlap_with_library_and_policy;
+ if (!GetOverlap(overlap_with_library, policy_.range(),
+ &overlap_with_library_and_policy)) {
+ return false;
+ }
+
+ RemoveConflictingVersions(variant_, &overlap_with_library_and_policy);
+ *expectedEffectiveRange = overlap_with_library_and_policy;
+ return true;
+ }
+
+ void RemoveConflictingVersions(SSLProtocolVariant variant,
+ SSLVersionRange* r) {
+ ASSERT_TRUE(r != nullptr);
+ if (r->max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ r->min < SSL_LIBRARY_VERSION_TLS_1_0) {
+ r->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ }
+ }
+
+ void SetUp() {
+ SetPolicy(policy_.range());
+ TlsConnectTestBase::SetUp();
+ }
+
+ void TearDown() {
+ TlsConnectTestBase::TearDown();
+ saved_version_policy_.RestoreOriginalPolicy();
+ }
+
+ protected:
+ class VersionPolicy {
+ public:
+ VersionPolicy() { SaveOriginalPolicy(); }
+
+ void RestoreOriginalPolicy() {
+ SECStatus rv;
+ rv = NSS_OptionSet(NSS_TLS_VERSION_MIN_POLICY, saved_min_tls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_TLS_VERSION_MAX_POLICY, saved_max_tls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_DTLS_VERSION_MIN_POLICY, saved_min_dtls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionSet(NSS_DTLS_VERSION_MAX_POLICY, saved_max_dtls_);
+ ASSERT_EQ(SECSuccess, rv);
+ // If it wasn't set initially, clear the bit that we set.
+ if (!(saved_algorithm_policy_ & NSS_USE_POLICY_IN_SSL)) {
+ rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, 0,
+ NSS_USE_POLICY_IN_SSL);
+ ASSERT_EQ(SECSuccess, rv);
+ }
+ }
+
+ private:
+ void SaveOriginalPolicy() {
+ SECStatus rv;
+ rv = NSS_OptionGet(NSS_TLS_VERSION_MIN_POLICY, &saved_min_tls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionGet(NSS_TLS_VERSION_MAX_POLICY, &saved_max_tls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionGet(NSS_DTLS_VERSION_MIN_POLICY, &saved_min_dtls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_OptionGet(NSS_DTLS_VERSION_MAX_POLICY, &saved_max_dtls_);
+ ASSERT_EQ(SECSuccess, rv);
+ rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY,
+ &saved_algorithm_policy_);
+ ASSERT_EQ(SECSuccess, rv);
+ }
+
+ int32_t saved_min_tls_;
+ int32_t saved_max_tls_;
+ int32_t saved_min_dtls_;
+ int32_t saved_max_dtls_;
+ uint32_t saved_algorithm_policy_;
+ };
+
+ VersionPolicy saved_version_policy_;
+
+ SSLProtocolVariant variant_;
+ const VersionRangeWithLabel policy_;
+ const VersionRangeWithLabel input_;
+ const VersionRangeWithLabel library_;
+};
+
+static const uint16_t kExpandedVersionsArr[] = {
+ /* clang-format off */
+ SSL_LIBRARY_VERSION_3_0 - 1,
+ SSL_LIBRARY_VERSION_3_0,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+#ifndef NSS_DISABLE_TLS_1_3
+ SSL_LIBRARY_VERSION_TLS_1_3,
+#endif
+ SSL_LIBRARY_VERSION_MAX_SUPPORTED + 1
+ /* clang-format on */
+};
+static ::testing::internal::ParamGenerator<uint16_t> kExpandedVersions =
+ ::testing::ValuesIn(kExpandedVersionsArr);
+
+TEST_P(TestPolicyVersionRange, TestAllTLSVersionsAndPolicyCombinations) {
+ ASSERT_TRUE(variant_ == ssl_variant_stream ||
+ variant_ == ssl_variant_datagram)
+ << "testing unsupported ssl variant";
+
+ std::cerr << "testing: " << variant_ << policy_ << input_ << library_
+ << std::endl;
+
+ SSLVersionRange supported_range;
+ SECStatus rv = SSL_VersionRangeGetSupported(variant_, &supported_range);
+ VersionRangeWithLabel supported("SSL_VersionRangeGetSupported",
+ supported_range);
+
+ std::cerr << supported << std::endl;
+
+ std::shared_ptr<DummyPrSocket> dummy_socket;
+ ScopedPRFileDesc ssl_fd;
+ CreateDummySocket(&dummy_socket, &ssl_fd);
+
+ SECStatus rv_socket;
+ SSLVersionRange overlap_policy_and_lib;
+ if (!GetOverlap(policy_.range(), library_.range(), &overlap_policy_and_lib)) {
+ EXPECT_EQ(SECFailure, rv)
+ << "expected SSL_VersionRangeGetSupported to fail with invalid policy";
+
+ SSLVersionRange enabled_range;
+ rv = SSL_VersionRangeGetDefault(variant_, &enabled_range);
+ EXPECT_EQ(SECFailure, rv)
+ << "expected SSL_VersionRangeGetDefault to fail with invalid policy";
+
+ SSLVersionRange enabled_range_on_socket;
+ rv_socket = SSL_VersionRangeGet(ssl_fd.get(), &enabled_range_on_socket);
+ EXPECT_EQ(SECFailure, rv_socket)
+ << "expected SSL_VersionRangeGet to fail with invalid policy";
+
+ ConnectExpectFail();
+ return;
+ }
+
+ EXPECT_EQ(SECSuccess, rv)
+ << "expected SSL_VersionRangeGetSupported to succeed with valid policy";
+
+ EXPECT_TRUE(supported_range.min != SSL_LIBRARY_VERSION_NONE &&
+ supported_range.max != SSL_LIBRARY_VERSION_NONE)
+ << "expected SSL_VersionRangeGetSupported to return real values with "
+ "valid policy";
+
+ RemoveConflictingVersions(variant_, &overlap_policy_and_lib);
+ VersionRangeWithLabel overlap_info("overlap", overlap_policy_and_lib);
+
+ EXPECT_TRUE(supported_range == overlap_policy_and_lib)
+ << "expected range from GetSupported to be identical with calculated "
+ "overlap "
+ << overlap_info;
+
+ // We don't know which versions are "enabled by default" by the library,
+ // therefore we don't know if there's overlap between the default
+ // and the policy, and therefore, we don't if TLS connections should
+ // be successful or fail in this combination.
+ // Therefore we don't test if we can connect, without having configured a
+ // version range explicitly.
+
+ // Now start testing with supplied input.
+
+ SSLVersionRange expected_effective_range;
+ bool is_valid_input =
+ IsValidInputForVersionRangeSet(&expected_effective_range);
+
+ SSLVersionRange temp_input = input_.range();
+ rv = SSL_VersionRangeSetDefault(variant_, &temp_input);
+ rv_socket = SSL_VersionRangeSet(ssl_fd.get(), &temp_input);
+
+ if (!is_valid_input) {
+ EXPECT_EQ(SECFailure, rv)
+ << "expected failure return from SSL_VersionRangeSetDefault";
+
+ EXPECT_EQ(SECFailure, rv_socket)
+ << "expected failure return from SSL_VersionRangeSet";
+ return;
+ }
+
+ EXPECT_EQ(SECSuccess, rv)
+ << "expected successful return from SSL_VersionRangeSetDefault";
+
+ EXPECT_EQ(SECSuccess, rv_socket)
+ << "expected successful return from SSL_VersionRangeSet";
+
+ SSLVersionRange effective;
+ SSLVersionRange effective_socket;
+
+ rv = SSL_VersionRangeGetDefault(variant_, &effective);
+ EXPECT_EQ(SECSuccess, rv)
+ << "expected successful return from SSL_VersionRangeGetDefault";
+
+ rv_socket = SSL_VersionRangeGet(ssl_fd.get(), &effective_socket);
+ EXPECT_EQ(SECSuccess, rv_socket)
+ << "expected successful return from SSL_VersionRangeGet";
+
+ VersionRangeWithLabel expected_info("expectation", expected_effective_range);
+ VersionRangeWithLabel effective_info("effectively-enabled", effective);
+
+ EXPECT_TRUE(expected_effective_range == effective)
+ << "range returned by SSL_VersionRangeGetDefault doesn't match "
+ "expectation: "
+ << expected_info << effective_info;
+
+ EXPECT_TRUE(expected_effective_range == effective_socket)
+ << "range returned by SSL_VersionRangeGet doesn't match "
+ "expectation: "
+ << expected_info << effective_info;
+
+ // Because we found overlap between policy and supported versions,
+ // and because we have used SetDefault to enable at least one version,
+ // it should be possible to execute an SSL/TLS connection.
+ Connect();
+}
+
+INSTANTIATE_TEST_CASE_P(TLSVersionRanges, TestPolicyVersionRange,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ kExpandedVersions, kExpandedVersions,
+ kExpandedVersions,
+ kExpandedVersions));
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/test_io.cc b/security/nss/gtests/ssl_gtest/test_io.cc
index f3fd0b24c..b9f0c672e 100644
--- a/security/nss/gtests/ssl_gtest/test_io.cc
+++ b/security/nss/gtests/ssl_gtest/test_io.cc
@@ -15,314 +15,33 @@
#include "prlog.h"
#include "prthread.h"
-#include "databuffer.h"
-
extern bool g_ssl_gtest_verbose;
namespace nss_test {
-static PRDescIdentity test_fd_identity = PR_INVALID_IO_LAYER;
-
-#define UNIMPLEMENTED() \
- std::cerr << "Call to unimplemented function " << __FUNCTION__ << std::endl; \
- PR_ASSERT(PR_FALSE); \
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0)
-
#define LOG(a) std::cerr << name_ << ": " << a << std::endl
#define LOGV(a) \
do { \
if (g_ssl_gtest_verbose) LOG(a); \
} while (false)
-class Packet : public DataBuffer {
- public:
- Packet(const DataBuffer &buf) : DataBuffer(buf), offset_(0) {}
-
- void Advance(size_t delta) {
- PR_ASSERT(offset_ + delta <= len());
- offset_ = std::min(len(), offset_ + delta);
- }
-
- size_t offset() const { return offset_; }
- size_t remaining() const { return len() - offset_; }
-
- private:
- size_t offset_;
-};
-
-// Implementation of NSPR methods
-static PRStatus DummyClose(PRFileDesc *f) {
- DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
- f->secret = nullptr;
- f->dtor(f);
- delete io;
- return PR_SUCCESS;
-}
-
-static int32_t DummyRead(PRFileDesc *f, void *buf, int32_t length) {
- DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
- return io->Read(buf, length);
-}
-
-static int32_t DummyWrite(PRFileDesc *f, const void *buf, int32_t length) {
- DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
- return io->Write(buf, length);
-}
-
-static int32_t DummyAvailable(PRFileDesc *f) {
- UNIMPLEMENTED();
- return -1;
-}
-
-int64_t DummyAvailable64(PRFileDesc *f) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static PRStatus DummySync(PRFileDesc *f) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static int32_t DummySeek(PRFileDesc *f, int32_t offset, PRSeekWhence how) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static int64_t DummySeek64(PRFileDesc *f, int64_t offset, PRSeekWhence how) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static PRStatus DummyFileInfo(PRFileDesc *f, PRFileInfo *info) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static PRStatus DummyFileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static int32_t DummyWritev(PRFileDesc *f, const PRIOVec *iov, int32_t iov_size,
- PRIntervalTime to) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static PRStatus DummyConnect(PRFileDesc *f, const PRNetAddr *addr,
- PRIntervalTime to) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static PRFileDesc *DummyAccept(PRFileDesc *sd, PRNetAddr *addr,
- PRIntervalTime to) {
- UNIMPLEMENTED();
- return nullptr;
-}
-
-static PRStatus DummyBind(PRFileDesc *f, const PRNetAddr *addr) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static PRStatus DummyListen(PRFileDesc *f, int32_t depth) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) {
- DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
- io->Reset();
- return PR_SUCCESS;
-}
-
-// This function does not support peek.
-static int32_t DummyRecv(PRFileDesc *f, void *buf, int32_t buflen,
- int32_t flags, PRIntervalTime to) {
- PR_ASSERT(flags == 0);
- if (flags != 0) {
- PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
- return -1;
- }
-
- DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
-
- if (io->mode() == DGRAM) {
- return io->Recv(buf, buflen);
- } else {
- return io->Read(buf, buflen);
- }
-}
-
-// Note: this is always nonblocking and assumes a zero timeout.
-static int32_t DummySend(PRFileDesc *f, const void *buf, int32_t amount,
- int32_t flags, PRIntervalTime to) {
- int32_t written = DummyWrite(f, buf, amount);
- return written;
-}
-
-static int32_t DummyRecvfrom(PRFileDesc *f, void *buf, int32_t amount,
- int32_t flags, PRNetAddr *addr,
- PRIntervalTime to) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static int32_t DummySendto(PRFileDesc *f, const void *buf, int32_t amount,
- int32_t flags, const PRNetAddr *addr,
- PRIntervalTime to) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static int16_t DummyPoll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static int32_t DummyAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
- PRNetAddr **raddr, void *buf, int32_t amount,
- PRIntervalTime t) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static int32_t DummyTransmitFile(PRFileDesc *sd, PRFileDesc *f,
- const void *headers, int32_t hlen,
- PRTransmitFileFlags flags, PRIntervalTime t) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static PRStatus DummyGetpeername(PRFileDesc *f, PRNetAddr *addr) {
- // TODO: Modify to return unique names for each channel
- // somehow, as opposed to always the same static address. The current
- // implementation messes up the session cache, which is why it's off
- // elsewhere
- addr->inet.family = PR_AF_INET;
- addr->inet.port = 0;
- addr->inet.ip = 0;
-
- return PR_SUCCESS;
-}
-
-static PRStatus DummyGetsockname(PRFileDesc *f, PRNetAddr *addr) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static PRStatus DummyGetsockoption(PRFileDesc *f, PRSocketOptionData *opt) {
- switch (opt->option) {
- case PR_SockOpt_Nonblocking:
- opt->value.non_blocking = PR_TRUE;
- return PR_SUCCESS;
- default:
- UNIMPLEMENTED();
- break;
- }
-
- return PR_FAILURE;
-}
-
-// Imitate setting socket options. These are mostly noops.
-static PRStatus DummySetsockoption(PRFileDesc *f,
- const PRSocketOptionData *opt) {
- switch (opt->option) {
- case PR_SockOpt_Nonblocking:
- return PR_SUCCESS;
- case PR_SockOpt_NoDelay:
- return PR_SUCCESS;
- default:
- UNIMPLEMENTED();
- break;
- }
-
- return PR_FAILURE;
-}
-
-static int32_t DummySendfile(PRFileDesc *out, PRSendFileData *in,
- PRTransmitFileFlags flags, PRIntervalTime to) {
- UNIMPLEMENTED();
- return -1;
-}
-
-static PRStatus DummyConnectContinue(PRFileDesc *f, int16_t flags) {
- UNIMPLEMENTED();
- return PR_FAILURE;
-}
-
-static int32_t DummyReserved(PRFileDesc *f) {
- UNIMPLEMENTED();
- return -1;
-}
-
-DummyPrSocket::~DummyPrSocket() { Reset(); }
-
-void DummyPrSocket::SetPacketFilter(PacketFilter *filter) {
- if (filter_) {
- delete filter_;
- }
+void DummyPrSocket::SetPacketFilter(std::shared_ptr<PacketFilter> filter) {
filter_ = filter;
}
-void DummyPrSocket::Reset() {
- delete filter_;
- if (peer_) {
- peer_->SetPeer(nullptr);
- peer_ = nullptr;
- }
- while (!input_.empty()) {
- Packet *front = input_.front();
- input_.pop();
- delete front;
- }
-}
-
-static const struct PRIOMethods DummyMethods = {
- PR_DESC_LAYERED, DummyClose,
- DummyRead, DummyWrite,
- DummyAvailable, DummyAvailable64,
- DummySync, DummySeek,
- DummySeek64, DummyFileInfo,
- DummyFileInfo64, DummyWritev,
- DummyConnect, DummyAccept,
- DummyBind, DummyListen,
- DummyShutdown, DummyRecv,
- DummySend, DummyRecvfrom,
- DummySendto, DummyPoll,
- DummyAcceptRead, DummyTransmitFile,
- DummyGetsockname, DummyGetpeername,
- DummyReserved, DummyReserved,
- DummyGetsockoption, DummySetsockoption,
- DummySendfile, DummyConnectContinue,
- DummyReserved, DummyReserved,
- DummyReserved, DummyReserved};
-
-PRFileDesc *DummyPrSocket::CreateFD(const std::string &name, Mode mode) {
- if (test_fd_identity == PR_INVALID_IO_LAYER) {
- test_fd_identity = PR_GetUniqueIdentity("testtransportadapter");
- }
-
- PRFileDesc *fd = (PR_CreateIOLayerStub(test_fd_identity, &DummyMethods));
- fd->secret = reinterpret_cast<PRFilePrivate *>(new DummyPrSocket(name, mode));
-
- return fd;
-}
-
-DummyPrSocket *DummyPrSocket::GetAdapter(PRFileDesc *fd) {
- return reinterpret_cast<DummyPrSocket *>(fd->secret);
+ScopedPRFileDesc DummyPrSocket::CreateFD() {
+ static PRDescIdentity test_fd_identity =
+ PR_GetUniqueIdentity("testtransportadapter");
+ return DummyIOLayerMethods::CreateFD(test_fd_identity, this);
}
void DummyPrSocket::PacketReceived(const DataBuffer &packet) {
- input_.push(new Packet(packet));
+ input_.push(Packet(packet));
}
-int32_t DummyPrSocket::Read(void *data, int32_t len) {
- PR_ASSERT(mode_ == STREAM);
-
- if (mode_ != STREAM) {
+int32_t DummyPrSocket::Read(PRFileDesc *f, void *data, int32_t len) {
+ PR_ASSERT(variant_ == ssl_variant_stream);
+ if (variant_ != ssl_variant_stream) {
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return -1;
}
@@ -333,45 +52,54 @@ int32_t DummyPrSocket::Read(void *data, int32_t len) {
return -1;
}
- Packet *front = input_.front();
+ auto &front = input_.front();
size_t to_read =
- std::min(static_cast<size_t>(len), front->len() - front->offset());
- memcpy(data, static_cast<const void *>(front->data() + front->offset()),
+ std::min(static_cast<size_t>(len), front.len() - front.offset());
+ memcpy(data, static_cast<const void *>(front.data() + front.offset()),
to_read);
- front->Advance(to_read);
+ front.Advance(to_read);
- if (!front->remaining()) {
+ if (!front.remaining()) {
input_.pop();
- delete front;
}
return static_cast<int32_t>(to_read);
}
-int32_t DummyPrSocket::Recv(void *buf, int32_t buflen) {
+int32_t DummyPrSocket::Recv(PRFileDesc *f, void *buf, int32_t buflen,
+ int32_t flags, PRIntervalTime to) {
+ PR_ASSERT(flags == 0);
+ if (flags != 0) {
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return -1;
+ }
+
+ if (variant() != ssl_variant_datagram) {
+ return Read(f, buf, buflen);
+ }
+
if (input_.empty()) {
PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
return -1;
}
- Packet *front = input_.front();
- if (static_cast<size_t>(buflen) < front->len()) {
+ auto &front = input_.front();
+ if (static_cast<size_t>(buflen) < front.len()) {
PR_ASSERT(false);
PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
return -1;
}
- size_t count = front->len();
- memcpy(buf, front->data(), count);
+ size_t count = front.len();
+ memcpy(buf, front.data(), count);
input_.pop();
- delete front;
-
return static_cast<int32_t>(count);
}
-int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
- if (!peer_ || !writeable_) {
+int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
+ auto peer = peer_.lock();
+ if (!peer || !writeable_) {
PR_SetError(PR_IO_ERROR, 0);
return -1;
}
@@ -387,14 +115,14 @@ int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
case PacketFilter::CHANGE:
LOG("Original packet: " << packet);
LOG("Filtered packet: " << filtered);
- peer_->PacketReceived(filtered);
+ peer->PacketReceived(filtered);
break;
case PacketFilter::DROP:
LOG("Droppped packet: " << packet);
break;
case PacketFilter::KEEP:
LOGV("Packet: " << packet);
- peer_->PacketReceived(packet);
+ peer->PacketReceived(packet);
break;
}
// libssl can't handle it if this reports something other than the length
@@ -415,43 +143,31 @@ void Poller::Shutdown() {
instance = nullptr;
}
-Poller::~Poller() {
- while (!timers_.empty()) {
- Timer *timer = timers_.top();
- timers_.pop();
- delete timer;
- }
-}
+void Poller::Wait(Event event, std::shared_ptr<DummyPrSocket> &adapter,
+ PollTarget *target, PollCallback cb) {
+ assert(event < TIMER_EVENT);
+ if (event >= TIMER_EVENT) return;
-void Poller::Wait(Event event, DummyPrSocket *adapter, PollTarget *target,
- PollCallback cb) {
+ std::unique_ptr<Waiter> waiter;
auto it = waiters_.find(adapter);
- Waiter *waiter;
-
if (it == waiters_.end()) {
- waiter = new Waiter(adapter);
+ waiter.reset(new Waiter(adapter));
} else {
- waiter = it->second;
+ waiter = std::move(it->second);
}
- assert(event < TIMER_EVENT);
- if (event >= TIMER_EVENT) return;
-
waiter->targets_[event] = target;
waiter->callbacks_[event] = cb;
- waiters_[adapter] = waiter;
+ waiters_[adapter] = std::move(waiter);
}
-void Poller::Cancel(Event event, DummyPrSocket *adapter) {
+void Poller::Cancel(Event event, std::shared_ptr<DummyPrSocket> &adapter) {
auto it = waiters_.find(adapter);
- Waiter *waiter;
-
if (it == waiters_.end()) {
return;
}
- waiter = it->second;
-
+ auto &waiter = it->second;
waiter->targets_[event] = nullptr;
waiter->callbacks_[event] = nullptr;
@@ -460,13 +176,12 @@ void Poller::Cancel(Event event, DummyPrSocket *adapter) {
if (waiter->callbacks_[i]) return;
}
- delete waiter;
waiters_.erase(adapter);
}
void Poller::SetTimer(uint32_t timer_ms, PollTarget *target, PollCallback cb,
- Timer **timer) {
- Timer *t = new Timer(PR_Now() + timer_ms * 1000, target, cb);
+ std::shared_ptr<Timer> *timer) {
+ auto t = std::make_shared<Timer>(PR_Now() + timer_ms * 1000, target, cb);
timers_.push(t);
if (timer) *timer = t;
}
@@ -482,7 +197,7 @@ bool Poller::Poll() {
// Figure out the timer for the select.
if (!timers_.empty()) {
- Timer *first_timer = timers_.top();
+ auto first_timer = timers_.top();
if (now >= first_timer->deadline_) {
// Timer expired.
timeout = PR_INTERVAL_NO_WAIT;
@@ -493,7 +208,7 @@ bool Poller::Poll() {
}
for (auto it = waiters_.begin(); it != waiters_.end(); ++it) {
- Waiter *waiter = it->second;
+ auto &waiter = it->second;
if (waiter->callbacks_[READABLE_EVENT]) {
if (waiter->io_->readable()) {
@@ -522,12 +237,11 @@ bool Poller::Poll() {
while (!timers_.empty()) {
if (now < timers_.top()->deadline_) break;
- Timer *timer = timers_.top();
+ auto timer = timers_.top();
timers_.pop();
if (timer->callback_) {
timer->callback_(timer->target_, TIMER_EVENT);
}
- delete timer;
}
return true;
diff --git a/security/nss/gtests/ssl_gtest/test_io.h b/security/nss/gtests/ssl_gtest/test_io.h
index b78db0dc6..ac2497222 100644
--- a/security/nss/gtests/ssl_gtest/test_io.h
+++ b/security/nss/gtests/ssl_gtest/test_io.h
@@ -14,12 +14,15 @@
#include <queue>
#include <string>
+#include "databuffer.h"
+#include "dummy_io.h"
#include "prio.h"
+#include "scoped_ptrs.h"
+#include "sslt.h"
namespace nss_test {
class DataBuffer;
-class Packet;
class DummyPrSocket; // Fwd decl.
// Allow us to inspect a packet before it is written.
@@ -42,49 +45,59 @@ class PacketFilter {
virtual Action Filter(const DataBuffer& input, DataBuffer* output) = 0;
};
-enum Mode { STREAM, DGRAM };
-
-inline std::ostream& operator<<(std::ostream& os, Mode m) {
- return os << ((m == STREAM) ? "TLS" : "DTLS");
-}
-
-class DummyPrSocket {
+class DummyPrSocket : public DummyIOLayerMethods {
public:
- ~DummyPrSocket();
+ DummyPrSocket(const std::string& name, SSLProtocolVariant variant)
+ : name_(name),
+ variant_(variant),
+ peer_(),
+ input_(),
+ filter_(nullptr),
+ writeable_(true) {}
+ virtual ~DummyPrSocket() {}
- static PRFileDesc* CreateFD(const std::string& name,
- Mode mode); // Returns an FD.
- static DummyPrSocket* GetAdapter(PRFileDesc* fd);
+ // Create a file descriptor that will reference this object. The fd must not
+ // live longer than this adapter; call PR_Close() before.
+ ScopedPRFileDesc CreateFD();
- DummyPrSocket* peer() const { return peer_; }
- void SetPeer(DummyPrSocket* peer) { peer_ = peer; }
- void SetPacketFilter(PacketFilter* filter);
+ std::weak_ptr<DummyPrSocket>& peer() { return peer_; }
+ void SetPeer(const std::shared_ptr<DummyPrSocket>& peer) { peer_ = peer; }
+ void SetPacketFilter(std::shared_ptr<PacketFilter> filter);
// Drops peer, packet filter and any outstanding packets.
void Reset();
void PacketReceived(const DataBuffer& data);
- 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 Read(PRFileDesc* f, void* data, int32_t len) override;
+ int32_t Recv(PRFileDesc* f, void* buf, int32_t buflen, int32_t flags,
+ PRIntervalTime to) override;
+ int32_t Write(PRFileDesc* f, const void* buf, int32_t length) override;
void CloseWrites() { writeable_ = false; }
- Mode mode() const { return mode_; }
+ SSLProtocolVariant variant() const { return variant_; }
bool readable() const { return !input_.empty(); }
private:
- DummyPrSocket(const std::string& name, Mode mode)
- : name_(name),
- mode_(mode),
- peer_(nullptr),
- input_(),
- filter_(nullptr),
- writeable_(true) {}
+ class Packet : public DataBuffer {
+ public:
+ Packet(const DataBuffer& buf) : DataBuffer(buf), offset_(0) {}
+
+ void Advance(size_t delta) {
+ PR_ASSERT(offset_ + delta <= len());
+ offset_ = std::min(len(), offset_ + delta);
+ }
+
+ size_t offset() const { return offset_; }
+ size_t remaining() const { return len() - offset_; }
+
+ private:
+ size_t offset_;
+ };
const std::string name_;
- Mode mode_;
- DummyPrSocket* peer_;
- std::queue<Packet*> input_;
- PacketFilter* filter_;
+ SSLProtocolVariant variant_;
+ std::weak_ptr<DummyPrSocket> peer_;
+ std::queue<Packet> input_;
+ std::shared_ptr<PacketFilter> filter_;
bool writeable_;
};
@@ -111,40 +124,44 @@ class Poller {
PollCallback callback_;
};
- void Wait(Event event, DummyPrSocket* adapter, PollTarget* target,
- PollCallback cb);
- void Cancel(Event event, DummyPrSocket* adapter);
+ void Wait(Event event, std::shared_ptr<DummyPrSocket>& adapter,
+ PollTarget* target, PollCallback cb);
+ void Cancel(Event event, std::shared_ptr<DummyPrSocket>& adapter);
void SetTimer(uint32_t timer_ms, PollTarget* target, PollCallback cb,
- Timer** handle);
+ std::shared_ptr<Timer>* handle);
bool Poll();
private:
Poller() : waiters_(), timers_() {}
- ~Poller();
+ ~Poller() {}
class Waiter {
public:
- Waiter(DummyPrSocket* io) : io_(io) {
+ Waiter(std::shared_ptr<DummyPrSocket> io) : io_(io) {
+ memset(&targets_[0], 0, sizeof(targets_));
memset(&callbacks_[0], 0, sizeof(callbacks_));
}
void WaitFor(Event event, PollCallback callback);
- DummyPrSocket* io_;
+ std::shared_ptr<DummyPrSocket> io_;
PollTarget* targets_[TIMER_EVENT];
PollCallback callbacks_[TIMER_EVENT];
};
class TimerComparator {
public:
- bool operator()(const Timer* lhs, const Timer* rhs) {
+ bool operator()(const std::shared_ptr<Timer> lhs,
+ const std::shared_ptr<Timer> rhs) {
return lhs->deadline_ > rhs->deadline_;
}
};
static Poller* instance;
- std::map<DummyPrSocket*, Waiter*> waiters_;
- std::priority_queue<Timer*, std::vector<Timer*>, TimerComparator> timers_;
+ std::map<std::shared_ptr<DummyPrSocket>, std::unique_ptr<Waiter>> waiters_;
+ std::priority_queue<std::shared_ptr<Timer>,
+ std::vector<std::shared_ptr<Timer>>, TimerComparator>
+ timers_;
};
} // end of namespace
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.cc b/security/nss/gtests/ssl_gtest/tls_agent.cc
index b75bba567..d6d91f7f7 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -43,14 +43,14 @@ const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
const std::string TlsAgent::kServerDsa = "dsa";
-TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode)
+TlsAgent::TlsAgent(const std::string& name, Role role,
+ SSLProtocolVariant variant)
: name_(name),
- mode_(mode),
+ variant_(variant),
+ role_(role),
server_key_bits_(0),
- pr_fd_(nullptr),
- adapter_(nullptr),
+ adapter_(new DummyPrSocket(role_str(), variant)),
ssl_fd_(nullptr),
- role_(role),
state_(STATE_INIT),
timer_handle_(nullptr),
falsestart_enabled_(false),
@@ -61,6 +61,10 @@ TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode)
can_falsestart_hook_called_(false),
sni_hook_called_(false),
auth_certificate_hook_called_(false),
+ expected_received_alert_(kTlsAlertCloseNotify),
+ expected_received_alert_level_(kTlsAlertWarning),
+ expected_sent_alert_(kTlsAlertCloseNotify),
+ expected_sent_alert_level_(kTlsAlertWarning),
handshake_callback_called_(false),
error_code_(0),
send_ctr_(0),
@@ -69,29 +73,31 @@ TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode)
handshake_callback_(),
auth_certificate_callback_(),
sni_callback_(),
- expect_short_headers_(false) {
+ expect_short_headers_(false),
+ skip_version_checks_(false) {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
- SECStatus rv = SSL_VersionRangeGetDefault(
- mode_ == STREAM ? ssl_variant_stream : ssl_variant_datagram, &vrange_);
+ SECStatus rv = SSL_VersionRangeGetDefault(variant_, &vrange_);
EXPECT_EQ(SECSuccess, rv);
}
TlsAgent::~TlsAgent() {
- if (adapter_) {
- Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
- // The adapter is closed when the FD closes.
- }
if (timer_handle_) {
timer_handle_->Cancel();
}
- if (pr_fd_) {
- PR_Close(pr_fd_);
+ if (adapter_) {
+ Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
}
- if (ssl_fd_) {
- PR_Close(ssl_fd_);
+ // Add failures manually, if any, so we don't throw in a destructor.
+ if (expected_received_alert_ != kTlsAlertCloseNotify ||
+ expected_received_alert_level_ != kTlsAlertWarning) {
+ ADD_FAILURE() << "Wrong expected_received_alert status";
+ }
+ if (expected_sent_alert_ != kTlsAlertCloseNotify ||
+ expected_sent_alert_level_ != kTlsAlertWarning) {
+ ADD_FAILURE() << "Wrong expected_sent_alert status";
}
}
@@ -102,27 +108,39 @@ void TlsAgent::SetState(State state) {
state_ = state;
}
+/*static*/ bool TlsAgent::LoadCertificate(const std::string& name,
+ ScopedCERTCertificate* cert,
+ ScopedSECKEYPrivateKey* priv) {
+ cert->reset(PK11_FindCertFromNickname(name.c_str(), nullptr));
+ EXPECT_NE(nullptr, cert->get());
+ if (!cert->get()) return false;
+
+ priv->reset(PK11_FindKeyByAnyCert(cert->get(), nullptr));
+ EXPECT_NE(nullptr, priv->get());
+ if (!priv->get()) return false;
+
+ return true;
+}
+
bool TlsAgent::ConfigServerCert(const std::string& name, bool updateKeyBits,
const SSLExtraServerCertData* serverCertData) {
- ScopedCERTCertificate cert(PK11_FindCertFromNickname(name.c_str(), nullptr));
- EXPECT_NE(nullptr, cert.get());
- if (!cert.get()) return false;
+ ScopedCERTCertificate cert;
+ ScopedSECKEYPrivateKey priv;
+ if (!TlsAgent::LoadCertificate(name, &cert, &priv)) {
+ return false;
+ }
- ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get()));
- EXPECT_NE(nullptr, pub.get());
- if (!pub.get()) return false;
if (updateKeyBits) {
+ ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get()));
+ EXPECT_NE(nullptr, pub.get());
+ if (!pub.get()) return false;
server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub.get());
}
- ScopedSECKEYPrivateKey priv(PK11_FindKeyByAnyCert(cert.get(), nullptr));
- EXPECT_NE(nullptr, priv.get());
- if (!priv.get()) return false;
-
SECStatus rv =
- SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, ssl_kea_null);
+ SSL_ConfigSecureServer(ssl_fd(), nullptr, nullptr, ssl_kea_null);
EXPECT_EQ(SECFailure, rv);
- rv = SSL_ConfigServerCert(ssl_fd_, cert.get(), priv.get(), serverCertData,
+ rv = SSL_ConfigServerCert(ssl_fd(), cert.get(), priv.get(), serverCertData,
serverCertData ? sizeof(*serverCertData) : 0);
return rv == SECSuccess;
}
@@ -131,41 +149,59 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
// Don't set up twice
if (ssl_fd_) return true;
- if (adapter_->mode() == STREAM) {
- ssl_fd_ = SSL_ImportFD(modelSocket, pr_fd_);
+ ScopedPRFileDesc dummy_fd(adapter_->CreateFD());
+ EXPECT_NE(nullptr, dummy_fd);
+ if (!dummy_fd) {
+ return false;
+ }
+ if (adapter_->variant() == ssl_variant_stream) {
+ ssl_fd_.reset(SSL_ImportFD(modelSocket, dummy_fd.get()));
} else {
- ssl_fd_ = DTLS_ImportFD(modelSocket, pr_fd_);
+ ssl_fd_.reset(DTLS_ImportFD(modelSocket, dummy_fd.get()));
}
EXPECT_NE(nullptr, ssl_fd_);
- if (!ssl_fd_) return false;
- pr_fd_ = nullptr;
+ if (!ssl_fd_) {
+ return false;
+ }
+ dummy_fd.release(); // Now subsumed by ssl_fd_.
- SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
- EXPECT_EQ(SECSuccess, rv);
- if (rv != SECSuccess) return false;
+ SECStatus rv;
+ if (!skip_version_checks_) {
+ rv = SSL_VersionRangeSet(ssl_fd(), &vrange_);
+ EXPECT_EQ(SECSuccess, rv);
+ if (rv != SECSuccess) return false;
+ }
if (role_ == SERVER) {
EXPECT_TRUE(ConfigServerCert(name_, true));
- rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook, this);
+ rv = SSL_SNISocketConfigHook(ssl_fd(), SniHook, this);
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
ScopedCERTCertList anchors(CERT_NewCertList());
- rv = SSL_SetTrustAnchors(ssl_fd_, anchors.get());
+ rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get());
if (rv != SECSuccess) return false;
} else {
- rv = SSL_SetURL(ssl_fd_, "server");
+ rv = SSL_SetURL(ssl_fd(), "server");
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
}
- rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this);
+ rv = SSL_AuthCertificateHook(ssl_fd(), AuthCertificateHook, this);
+ EXPECT_EQ(SECSuccess, rv);
+ if (rv != SECSuccess) return false;
+
+ rv = SSL_AlertReceivedCallback(ssl_fd(), AlertReceivedCallback, this);
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
- rv = SSL_HandshakeCallback(ssl_fd_, HandshakeCallback, this);
+ rv = SSL_AlertSentCallback(ssl_fd(), AlertSentCallback, this);
+ EXPECT_EQ(SECSuccess, rv);
+ if (rv != SECSuccess) return false;
+
+ rv = SSL_HandshakeCallback(ssl_fd(), HandshakeCallback, this);
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
@@ -177,38 +213,31 @@ void TlsAgent::SetupClientAuth() {
ASSERT_EQ(CLIENT, role_);
EXPECT_EQ(SECSuccess,
- SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook,
+ SSL_GetClientAuthDataHook(ssl_fd(), GetClientAuthDataHook,
reinterpret_cast<void*>(this)));
}
-bool TlsAgent::GetClientAuthCredentials(CERTCertificate** cert,
- SECKEYPrivateKey** priv) const {
- *cert = PK11_FindCertFromNickname(name_.c_str(), nullptr);
- EXPECT_NE(nullptr, *cert);
- if (!*cert) return false;
-
- *priv = PK11_FindKeyByAnyCert(*cert, nullptr);
- EXPECT_NE(nullptr, *priv);
- if (!*priv) return false; // Leak cert.
-
- return true;
-}
-
SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
CERTDistNames* caNames,
- CERTCertificate** cert,
- SECKEYPrivateKey** privKey) {
+ CERTCertificate** clientCert,
+ SECKEYPrivateKey** clientKey) {
TlsAgent* agent = reinterpret_cast<TlsAgent*>(self);
ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
- if (agent->GetClientAuthCredentials(cert, privKey)) {
- return SECSuccess;
+
+ ScopedCERTCertificate cert;
+ ScopedSECKEYPrivateKey priv;
+ if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) {
+ return SECFailure;
}
- return SECFailure;
+
+ *clientCert = cert.release();
+ *clientKey = priv.release();
+ return SECSuccess;
}
bool TlsAgent::GetPeerChainLength(size_t* count) {
- CERTCertList* chain = SSL_PeerCertificateChain(ssl_fd_);
+ CERTCertList* chain = SSL_PeerCertificateChain(ssl_fd());
if (!chain) return false;
*count = 0;
@@ -224,17 +253,21 @@ bool TlsAgent::GetPeerChainLength(size_t* count) {
return true;
}
+void TlsAgent::CheckCipherSuite(uint16_t cipher_suite) {
+ EXPECT_EQ(csinfo_.cipherSuite, cipher_suite);
+}
+
void TlsAgent::RequestClientAuth(bool requireAuth) {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(SERVER, role_);
EXPECT_EQ(SECSuccess,
- SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE));
- EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_REQUIRE_CERTIFICATE,
+ SSL_OptionSet(ssl_fd(), SSL_REQUEST_CERTIFICATE, PR_TRUE));
+ EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd(), SSL_REQUIRE_CERTIFICATE,
requireAuth ? PR_TRUE : PR_FALSE));
EXPECT_EQ(SECSuccess, SSL_AuthCertificateHook(
- ssl_fd_, &TlsAgent::ClientAuthenticated, this));
+ ssl_fd(), &TlsAgent::ClientAuthenticated, this));
expect_client_auth_ = true;
}
@@ -242,7 +275,7 @@ void TlsAgent::StartConnect(PRFileDesc* model) {
EXPECT_TRUE(EnsureTlsSetup(model));
SECStatus rv;
- rv = SSL_ResetHandshake(ssl_fd_, role_ == SERVER ? PR_TRUE : PR_FALSE);
+ rv = SSL_ResetHandshake(ssl_fd(), role_ == SERVER ? PR_TRUE : PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
SetState(STATE_CONNECTING);
}
@@ -250,7 +283,7 @@ void TlsAgent::StartConnect(PRFileDesc* model) {
void TlsAgent::DisableAllCiphers() {
for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
SECStatus rv =
- SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_FALSE);
+ SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
}
}
@@ -287,7 +320,7 @@ void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) {
EXPECT_EQ(sizeof(csinfo), csinfo.length);
if ((csinfo.keaType == kea) || (csinfo.keaType == ssl_kea_tls13_any)) {
- rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
+ rv = SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
}
@@ -325,7 +358,7 @@ void TlsAgent::EnableCiphersByAuthType(SSLAuthType authType) {
if ((csinfo.authType == authType) ||
(csinfo.keaType == ssl_kea_tls13_any)) {
- rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
+ rv = SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
}
@@ -333,20 +366,20 @@ void TlsAgent::EnableCiphersByAuthType(SSLAuthType authType) {
void TlsAgent::EnableSingleCipher(uint16_t cipher) {
DisableAllCiphers();
- SECStatus rv = SSL_CipherPrefSet(ssl_fd_, cipher, PR_TRUE);
+ SECStatus rv = SSL_CipherPrefSet(ssl_fd(), cipher, PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups) {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_NamedGroupConfig(ssl_fd_, &groups[0], groups.size());
+ SECStatus rv = SSL_NamedGroupConfig(ssl_fd(), &groups[0], groups.size());
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SetSessionTicketsEnabled(bool en) {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_SESSION_TICKETS,
en ? PR_TRUE : PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
}
@@ -354,7 +387,7 @@ void TlsAgent::SetSessionTicketsEnabled(bool en) {
void TlsAgent::SetSessionCacheEnabled(bool en) {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE, en ? PR_FALSE : PR_TRUE);
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_NO_CACHE, en ? PR_FALSE : PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
@@ -362,14 +395,22 @@ void TlsAgent::Set0RttEnabled(bool en) {
EXPECT_TRUE(EnsureTlsSetup());
SECStatus rv =
- SSL_OptionSet(ssl_fd_, SSL_ENABLE_0RTT_DATA, en ? PR_TRUE : PR_FALSE);
+ SSL_OptionSet(ssl_fd(), SSL_ENABLE_0RTT_DATA, en ? PR_TRUE : PR_FALSE);
+ EXPECT_EQ(SECSuccess, rv);
+}
+
+void TlsAgent::SetFallbackSCSVEnabled(bool en) {
+ EXPECT_TRUE(role_ == CLIENT && EnsureTlsSetup());
+
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_FALLBACK_SCSV,
+ en ? PR_TRUE : PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SetShortHeadersEnabled() {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd_);
+ SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd());
EXPECT_EQ(SECSuccess, rv);
}
@@ -377,8 +418,8 @@ void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
vrange_.min = minver;
vrange_.max = maxver;
- if (ssl_fd_) {
- SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
+ if (ssl_fd()) {
+ SECStatus rv = SSL_VersionRangeSet(ssl_fd(), &vrange_);
EXPECT_EQ(SECSuccess, rv);
}
}
@@ -398,32 +439,34 @@ void TlsAgent::ExpectReadWriteError() { expect_readwrite_error_ = true; }
void TlsAgent::ExpectShortHeaders() { expect_short_headers_ = true; }
+void TlsAgent::SkipVersionChecks() { skip_version_checks_ = true; }
+
void TlsAgent::SetSignatureSchemes(const SSLSignatureScheme* schemes,
size_t count) {
EXPECT_TRUE(EnsureTlsSetup());
EXPECT_LE(count, SSL_SignatureMaxCount());
EXPECT_EQ(SECSuccess,
- SSL_SignatureSchemePrefSet(ssl_fd_, schemes,
+ SSL_SignatureSchemePrefSet(ssl_fd(), schemes,
static_cast<unsigned int>(count)));
- EXPECT_EQ(SECFailure, SSL_SignatureSchemePrefSet(ssl_fd_, schemes, 0))
+ EXPECT_EQ(SECFailure, SSL_SignatureSchemePrefSet(ssl_fd(), schemes, 0))
<< "setting no schemes should fail and do nothing";
std::vector<SSLSignatureScheme> configuredSchemes(count);
unsigned int configuredCount;
EXPECT_EQ(SECFailure,
- SSL_SignatureSchemePrefGet(ssl_fd_, nullptr, &configuredCount, 1))
+ SSL_SignatureSchemePrefGet(ssl_fd(), nullptr, &configuredCount, 1))
<< "get schemes, schemes is nullptr";
EXPECT_EQ(SECFailure,
- SSL_SignatureSchemePrefGet(ssl_fd_, &configuredSchemes[0],
+ SSL_SignatureSchemePrefGet(ssl_fd(), &configuredSchemes[0],
&configuredCount, 0))
<< "get schemes, too little space";
EXPECT_EQ(SECFailure,
- SSL_SignatureSchemePrefGet(ssl_fd_, &configuredSchemes[0], nullptr,
+ SSL_SignatureSchemePrefGet(ssl_fd(), &configuredSchemes[0], nullptr,
configuredSchemes.size()))
<< "get schemes, countOut is nullptr";
EXPECT_EQ(SECSuccess, SSL_SignatureSchemePrefGet(
- ssl_fd_, &configuredSchemes[0], &configuredCount,
+ ssl_fd(), &configuredSchemes[0], &configuredCount,
configuredSchemes.size()));
// SignatureSchemePrefSet drops unsupported algorithms silently, so the
// number that are configured might be fewer.
@@ -524,10 +567,10 @@ void TlsAgent::EnableFalseStart() {
EXPECT_TRUE(EnsureTlsSetup());
falsestart_enabled_ = true;
+ EXPECT_EQ(SECSuccess, SSL_SetCanFalseStartCallback(
+ ssl_fd(), CanFalseStartCallback, this));
EXPECT_EQ(SECSuccess,
- SSL_SetCanFalseStartCallback(ssl_fd_, CanFalseStartCallback, this));
- EXPECT_EQ(SECSuccess,
- SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALSE_START, PR_TRUE));
+ SSL_OptionSet(ssl_fd(), SSL_ENABLE_FALSE_START, PR_TRUE));
}
void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
@@ -535,8 +578,8 @@ void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
EXPECT_TRUE(EnsureTlsSetup());
- EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE));
- EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd_, val, len));
+ EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd(), SSL_ENABLE_ALPN, PR_TRUE));
+ EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd(), val, len));
}
void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
@@ -544,7 +587,7 @@ void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
SSLNextProtoState state;
char chosen[10];
unsigned int chosen_len;
- SECStatus rv = SSL_GetNextProto(ssl_fd_, &state,
+ SECStatus rv = SSL_GetNextProto(ssl_fd(), &state,
reinterpret_cast<unsigned char*>(chosen),
&chosen_len, sizeof(chosen));
EXPECT_EQ(SECSuccess, rv);
@@ -562,12 +605,12 @@ void TlsAgent::EnableSrtp() {
const uint16_t ciphers[] = {SRTP_AES128_CM_HMAC_SHA1_80,
SRTP_AES128_CM_HMAC_SHA1_32};
EXPECT_EQ(SECSuccess,
- SSL_SetSRTPCiphers(ssl_fd_, ciphers, PR_ARRAY_SIZE(ciphers)));
+ SSL_SetSRTPCiphers(ssl_fd(), ciphers, PR_ARRAY_SIZE(ciphers)));
}
void TlsAgent::CheckSrtp() const {
uint16_t actual;
- EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd_, &actual));
+ EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd(), &actual));
EXPECT_EQ(SRTP_AES128_CM_HMAC_SHA1_80, actual);
}
@@ -578,6 +621,55 @@ void TlsAgent::CheckErrorCode(int32_t expected) const {
<< PORT_ErrorToName(expected) << std::endl;
}
+static uint8_t GetExpectedAlertLevel(uint8_t alert) {
+ switch (alert) {
+ case kTlsAlertCloseNotify:
+ case kTlsAlertEndOfEarlyData:
+ return kTlsAlertWarning;
+ default:
+ break;
+ }
+ return kTlsAlertFatal;
+}
+
+void TlsAgent::ExpectReceiveAlert(uint8_t alert, uint8_t level) {
+ expected_received_alert_ = alert;
+ if (level == 0) {
+ expected_received_alert_level_ = GetExpectedAlertLevel(alert);
+ } else {
+ expected_received_alert_level_ = level;
+ }
+}
+
+void TlsAgent::ExpectSendAlert(uint8_t alert, uint8_t level) {
+ expected_sent_alert_ = alert;
+ if (level == 0) {
+ expected_sent_alert_level_ = GetExpectedAlertLevel(alert);
+ } else {
+ expected_sent_alert_level_ = level;
+ }
+}
+
+void TlsAgent::CheckAlert(bool sent, const SSLAlert* alert) {
+ LOG(((alert->level == kTlsAlertWarning) ? "Warning" : "Fatal")
+ << " alert " << (sent ? "sent" : "received") << ": "
+ << static_cast<int>(alert->description));
+
+ auto& expected = sent ? expected_sent_alert_ : expected_received_alert_;
+ auto& expected_level =
+ sent ? expected_sent_alert_level_ : expected_received_alert_level_;
+ /* Silently pass close_notify in case the test has already ended. */
+ if (expected == kTlsAlertCloseNotify && expected_level == kTlsAlertWarning &&
+ alert->description == expected && alert->level == expected_level) {
+ return;
+ }
+
+ EXPECT_EQ(expected, alert->description);
+ EXPECT_EQ(expected_level, alert->level);
+ expected = kTlsAlertCloseNotify;
+ expected_level = kTlsAlertWarning;
+}
+
void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
ASSERT_EQ(0, error_code_);
WAIT_(error_code_ != 0, delay);
@@ -589,7 +681,7 @@ void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
void TlsAgent::CheckPreliminaryInfo() {
SSLPreliminaryChannelInfo info;
EXPECT_EQ(SECSuccess,
- SSL_GetPreliminaryChannelInfo(ssl_fd_, &info, sizeof(info)));
+ SSL_GetPreliminaryChannelInfo(ssl_fd(), &info, sizeof(info)));
EXPECT_EQ(sizeof(info), info.length);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_version);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_cipher_suite);
@@ -619,7 +711,7 @@ void TlsAgent::CheckCallbacks() const {
// These callbacks shouldn't fire if we are resuming, except on TLS 1.3.
if (role_ == SERVER) {
- PRBool have_sni = SSLInt_ExtensionNegotiated(ssl_fd_, ssl_server_name_xtn);
+ PRBool have_sni = SSLInt_ExtensionNegotiated(ssl_fd(), ssl_server_name_xtn);
EXPECT_EQ(((!expect_resumption_ && have_sni) ||
expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3),
sni_hook_called_);
@@ -639,11 +731,15 @@ void TlsAgent::ResetPreliminaryInfo() {
}
void TlsAgent::Connected() {
+ if (state_ == STATE_CONNECTED) {
+ return;
+ }
+
LOG("Handshake success");
CheckPreliminaryInfo();
CheckCallbacks();
- SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info_, sizeof(info_));
+ SECStatus rv = SSL_GetChannelInfo(ssl_fd(), &info_, sizeof(info_));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(sizeof(info_), info_.length);
@@ -658,18 +754,19 @@ void TlsAgent::Connected() {
EXPECT_EQ(sizeof(csinfo_), csinfo_.length);
if (expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
- PRInt32 cipherSuites = SSLInt_CountTls13CipherSpecs(ssl_fd_);
+ PRInt32 cipherSuites = SSLInt_CountTls13CipherSpecs(ssl_fd());
// We use one ciphersuite in each direction, plus one that's kept around
// by DTLS for retransmission.
- PRInt32 expected = ((mode_ == DGRAM) && (role_ == CLIENT)) ? 3 : 2;
+ PRInt32 expected =
+ ((variant_ == ssl_variant_datagram) && (role_ == CLIENT)) ? 3 : 2;
EXPECT_EQ(expected, cipherSuites);
if (expected != cipherSuites) {
- SSLInt_PrintTls13CipherSpecs(ssl_fd_);
+ SSLInt_PrintTls13CipherSpecs(ssl_fd());
}
}
PRBool short_headers;
- rv = SSLInt_UsingShortHeaders(ssl_fd_, &short_headers);
+ rv = SSLInt_UsingShortHeaders(ssl_fd(), &short_headers);
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ((PRBool)expect_short_headers_, short_headers);
SetState(STATE_CONNECTED);
@@ -679,7 +776,7 @@ void TlsAgent::EnableExtendedMasterSecret() {
ASSERT_TRUE(EnsureTlsSetup());
SECStatus rv =
- SSL_OptionSet(ssl_fd_, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+ SSL_OptionSet(ssl_fd(), SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
ASSERT_EQ(SECSuccess, rv);
}
@@ -701,13 +798,13 @@ void TlsAgent::CheckEarlyDataAccepted(bool expected) {
}
void TlsAgent::CheckSecretsDestroyed() {
- ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd_));
+ ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd()));
}
void TlsAgent::DisableRollbackDetection() {
ASSERT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ROLLBACK_DETECTION, PR_FALSE);
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ROLLBACK_DETECTION, PR_FALSE);
ASSERT_EQ(SECSuccess, rv);
}
@@ -715,23 +812,22 @@ void TlsAgent::DisableRollbackDetection() {
void TlsAgent::EnableCompression() {
ASSERT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_DEFLATE, PR_TRUE);
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_DEFLATE, PR_TRUE);
ASSERT_EQ(SECSuccess, rv);
}
void TlsAgent::SetDowngradeCheckVersion(uint16_t version) {
ASSERT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd_, version);
+ SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd(), version);
ASSERT_EQ(SECSuccess, rv);
}
void TlsAgent::Handshake() {
LOGV("Handshake");
- SECStatus rv = SSL_ForceHandshake(ssl_fd_);
+ SECStatus rv = SSL_ForceHandshake(ssl_fd());
if (rv == SECSuccess) {
Connected();
-
Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
&TlsAgent::ReadableCallback);
return;
@@ -740,14 +836,14 @@ void TlsAgent::Handshake() {
int32_t err = PR_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
LOGV("Would have blocked");
- if (mode_ == DGRAM) {
+ if (variant_ == ssl_variant_datagram) {
if (timer_handle_) {
timer_handle_->Cancel();
timer_handle_ = nullptr;
}
PRIntervalTime timeout;
- rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
+ rv = DTLS_GetHandshakeTimeout(ssl_fd(), &timeout);
if (rv == SECSuccess) {
Poller::Instance()->SetTimer(
timeout + 1, this, &TlsAgent::ReadableCallback, &timer_handle_);
@@ -773,13 +869,18 @@ void TlsAgent::PrepareForRenegotiate() {
void TlsAgent::StartRenegotiate() {
PrepareForRenegotiate();
- SECStatus rv = SSL_ReHandshake(ssl_fd_, PR_TRUE);
+ SECStatus rv = SSL_ReHandshake(ssl_fd(), PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SendDirect(const DataBuffer& buf) {
LOG("Send Direct " << buf);
- adapter_->peer()->PacketReceived(buf);
+ auto peer = adapter_->peer().lock();
+ if (peer) {
+ peer->PacketReceived(buf);
+ } else {
+ LOG("Send Direct peer absent");
+ }
}
static bool ErrorIsNonFatal(PRErrorCode code) {
@@ -806,7 +907,7 @@ void TlsAgent::SendData(size_t bytes, size_t blocksize) {
void TlsAgent::SendBuffer(const DataBuffer& buf) {
LOGV("Writing " << buf.len() << " bytes");
- int32_t rv = PR_Write(ssl_fd_, buf.data(), buf.len());
+ int32_t rv = PR_Write(ssl_fd(), buf.data(), buf.len());
if (expect_readwrite_error_) {
EXPECT_GT(0, rv);
EXPECT_NE(PR_WOULD_BLOCK_ERROR, error_code_);
@@ -817,10 +918,10 @@ void TlsAgent::SendBuffer(const DataBuffer& buf) {
}
}
-void TlsAgent::ReadBytes() {
- uint8_t block[1024];
+void TlsAgent::ReadBytes(size_t amount) {
+ uint8_t block[16384];
- int32_t rv = PR_Read(ssl_fd_, block, sizeof(block));
+ int32_t rv = PR_Read(ssl_fd(), block, (std::min)(amount, sizeof(block)));
LOGV("ReadBytes " << rv);
int32_t err;
@@ -853,18 +954,19 @@ void TlsAgent::ResetSentBytes() { send_ctr_ = 0; }
void TlsAgent::ConfigureSessionCache(SessionResumptionMode mode) {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE,
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_NO_CACHE,
mode & RESUME_SESSIONID ? PR_FALSE : PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
- rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
+ rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_SESSION_TICKETS,
mode & RESUME_TICKET ? PR_TRUE : PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::DisableECDHEServerKeyReuse() {
+ ASSERT_TRUE(EnsureTlsSetup());
ASSERT_EQ(TlsAgent::SERVER, role_);
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
+ SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
EXPECT_EQ(SECSuccess, rv);
}
@@ -877,29 +979,25 @@ void TlsAgentTestBase::SetUp() {
}
void TlsAgentTestBase::TearDown() {
- delete agent_;
+ agent_ = nullptr;
SSL_ClearSessionCache();
SSL_ShutdownServerSessionIDCache();
}
void TlsAgentTestBase::Reset(const std::string& server_name) {
- delete agent_;
- Init(server_name);
-}
-
-void TlsAgentTestBase::Init(const std::string& server_name) {
- agent_ =
+ agent_.reset(
new TlsAgent(role_ == TlsAgent::CLIENT ? TlsAgent::kClient : server_name,
- role_, mode_);
- agent_->Init();
- fd_ = DummyPrSocket::CreateFD(agent_->role_str(), mode_);
- agent_->adapter()->SetPeer(DummyPrSocket::GetAdapter(fd_));
+ role_, variant_));
+ if (version_) {
+ agent_->SetVersionRange(version_, version_);
+ }
+ agent_->adapter()->SetPeer(sink_adapter_);
agent_->StartConnect();
}
void TlsAgentTestBase::EnsureInit() {
if (!agent_) {
- Init();
+ Reset();
}
const std::vector<SSLNamedGroup> groups = {
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
@@ -907,6 +1005,11 @@ void TlsAgentTestBase::EnsureInit() {
agent_->ConfigNamedGroups(groups);
}
+void TlsAgentTestBase::ExpectAlert(uint8_t alert) {
+ EnsureInit();
+ agent_->ExpectSendAlert(alert);
+}
+
void TlsAgentTestBase::ProcessMessage(const DataBuffer& buffer,
TlsAgent::State expected_state,
int32_t error_code) {
@@ -922,14 +1025,16 @@ void TlsAgentTestBase::ProcessMessage(const DataBuffer& buffer,
}
}
-void TlsAgentTestBase::MakeRecord(Mode mode, uint8_t type, uint16_t version,
- const uint8_t* buf, size_t len,
- DataBuffer* out, uint64_t seq_num) {
+void TlsAgentTestBase::MakeRecord(SSLProtocolVariant variant, uint8_t type,
+ uint16_t version, const uint8_t* buf,
+ size_t len, DataBuffer* out,
+ uint64_t seq_num) {
size_t index = 0;
index = out->Write(index, type, 1);
- index = out->Write(
- index, mode == STREAM ? version : TlsVersionToDtlsVersion(version), 2);
- if (mode == DGRAM) {
+ if (variant == ssl_variant_stream) {
+ index = out->Write(index, version, 2);
+ } else {
+ index = out->Write(index, TlsVersionToDtlsVersion(version), 2);
index = out->Write(index, seq_num >> 32, 4);
index = out->Write(index, seq_num & PR_UINT32_MAX, 4);
}
@@ -940,7 +1045,7 @@ void TlsAgentTestBase::MakeRecord(Mode mode, uint8_t type, uint16_t version,
void TlsAgentTestBase::MakeRecord(uint8_t type, uint16_t version,
const uint8_t* buf, size_t len,
DataBuffer* out, uint64_t seq_num) const {
- MakeRecord(mode_, type, version, buf, len, out, seq_num);
+ MakeRecord(variant_, type, version, buf, len, out, seq_num);
}
void TlsAgentTestBase::MakeHandshakeMessage(uint8_t hs_type,
@@ -959,7 +1064,7 @@ void TlsAgentTestBase::MakeHandshakeMessageFragment(
if (!fragment_length) fragment_length = hs_len;
index = out->Write(index, hs_type, 1); // Handshake record type.
index = out->Write(index, hs_len, 3); // Handshake length
- if (mode_ == DGRAM) {
+ if (variant_ == ssl_variant_datagram) {
index = out->Write(index, seq_num, 2);
index = out->Write(index, fragment_offset, 3);
index = out->Write(index, fragment_length, 3);
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.h b/security/nss/gtests/ssl_gtest/tls_agent.h
index 78923c930..4bccb9a84 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -14,9 +14,11 @@
#include <iostream>
#include "test_io.h"
+#include "tls_filter.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
+#include "scoped_ptrs.h"
extern bool g_ssl_gtest_verbose;
@@ -42,6 +44,8 @@ const extern std::vector<SSLNamedGroup> kECDHEGroups;
const extern std::vector<SSLNamedGroup> kFFDHEGroups;
const extern std::vector<SSLNamedGroup> kFasterDHEGroups;
+// These functions are called from callbacks. They use bare pointers because
+// TlsAgent sets up the callback and it doesn't know who owns it.
typedef std::function<SECStatus(TlsAgent* agent, bool checksig, bool isServer)>
AuthCertificateCallbackFunction;
@@ -70,25 +74,24 @@ class TlsAgent : public PollTarget {
static const std::string kServerEcdhRsa;
static const std::string kServerDsa;
- TlsAgent(const std::string& name, Role role, Mode mode);
+ TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
virtual ~TlsAgent();
- bool Init() {
- pr_fd_ = DummyPrSocket::CreateFD(role_str(), mode_);
- if (!pr_fd_) return false;
-
- adapter_ = DummyPrSocket::GetAdapter(pr_fd_);
- if (!adapter_) return false;
-
- return true;
+ void SetPeer(std::shared_ptr<TlsAgent>& peer) {
+ adapter_->SetPeer(peer->adapter_);
}
- void SetPeer(TlsAgent* peer) { adapter_->SetPeer(peer->adapter_); }
+ void SetTlsRecordFilter(std::shared_ptr<TlsRecordFilter> filter) {
+ filter->SetAgent(this);
+ adapter_->SetPacketFilter(filter);
+ }
- void SetPacketFilter(PacketFilter* filter) {
+ void SetPacketFilter(std::shared_ptr<PacketFilter> filter) {
adapter_->SetPacketFilter(filter);
}
+ void DeletePacketFilter() { adapter_->SetPacketFilter(nullptr); }
+
void StartConnect(PRFileDesc* model = nullptr);
void CheckKEA(SSLKEAType kea_type, SSLNamedGroup group,
size_t kea_size = 0) const;
@@ -107,6 +110,9 @@ class TlsAgent : public PollTarget {
void PrepareForRenegotiate();
// Prepares for renegotiation, then actually triggers it.
void StartRenegotiate();
+ static bool LoadCertificate(const std::string& name,
+ ScopedCERTCertificate* cert,
+ ScopedSECKEYPrivateKey* priv);
bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
const SSLExtraServerCertData* serverCertData = nullptr);
bool ConfigServerCertWithChain(const std::string& name);
@@ -114,13 +120,12 @@ class TlsAgent : public PollTarget {
void SetupClientAuth();
void RequestClientAuth(bool requireAuth);
- bool GetClientAuthCredentials(CERTCertificate** cert,
- SECKEYPrivateKey** priv) const;
void ConfigureSessionCache(SessionResumptionMode mode);
void SetSessionTicketsEnabled(bool en);
void SetSessionCacheEnabled(bool en);
void Set0RttEnabled(bool en);
+ void SetFallbackSCSVEnabled(bool en);
void SetShortHeadersEnabled();
void SetVersionRange(uint16_t minver, uint16_t maxver);
void GetVersionRange(uint16_t* minver, uint16_t* maxver);
@@ -132,6 +137,7 @@ class TlsAgent : public PollTarget {
void EnableFalseStart();
void ExpectResumption();
void ExpectShortHeaders();
+ void SkipVersionChecks();
void SetSignatureSchemes(const SSLSignatureScheme* schemes, size_t count);
void EnableAlpn(const uint8_t* val, size_t len);
void CheckAlpn(SSLNextProtoState expected_state,
@@ -145,7 +151,7 @@ class TlsAgent : public PollTarget {
void SendBuffer(const DataBuffer& buf);
// Send data directly to the underlying socket, skipping the TLS layer.
void SendDirect(const DataBuffer& buf);
- void ReadBytes();
+ void ReadBytes(size_t max = 16384U);
void ResetSentBytes(); // Hack to test drops.
void EnableExtendedMasterSecret();
void CheckExtendedMasterSecret(bool expected);
@@ -157,6 +163,7 @@ class TlsAgent : public PollTarget {
void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
void DisableECDHEServerKeyReuse();
bool GetPeerChainLength(size_t* count);
+ void CheckCipherSuite(uint16_t cipher_suite);
const std::string& name() const { return name_; }
@@ -166,15 +173,15 @@ class TlsAgent : public PollTarget {
State state() const { return state_; }
const CERTCertificate* peer_cert() const {
- return SSL_PeerCertificate(ssl_fd_);
+ return SSL_PeerCertificate(ssl_fd_.get());
}
const char* state_str() const { return state_str(state()); }
static const char* state_str(State state) { return states[state]; }
- PRFileDesc* ssl_fd() { return ssl_fd_; }
- DummyPrSocket* adapter() { return adapter_; }
+ PRFileDesc* ssl_fd() const { return ssl_fd_.get(); }
+ std::shared_ptr<DummyPrSocket>& adapter() { return adapter_; }
bool is_compressed() const {
return info_.compressionMethod != ssl_compression_null;
@@ -239,6 +246,9 @@ class TlsAgent : public PollTarget {
sni_callback_ = sni_callback;
}
+ void ExpectReceiveAlert(uint8_t alert, uint8_t level = 0);
+ void ExpectSendAlert(uint8_t alert, uint8_t level = 0);
+
private:
const static char* states[];
@@ -320,6 +330,18 @@ class TlsAgent : public PollTarget {
return SECSuccess;
}
+ void CheckAlert(bool sent, const SSLAlert* alert);
+
+ static void AlertReceivedCallback(const PRFileDesc* fd, void* arg,
+ const SSLAlert* alert) {
+ reinterpret_cast<TlsAgent*>(arg)->CheckAlert(false, alert);
+ }
+
+ static void AlertSentCallback(const PRFileDesc* fd, void* arg,
+ const SSLAlert* alert) {
+ reinterpret_cast<TlsAgent*>(arg)->CheckAlert(true, alert);
+ }
+
static void HandshakeCallback(PRFileDesc* fd, void* arg) {
TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
agent->handshake_callback_called_ = true;
@@ -336,14 +358,13 @@ class TlsAgent : public PollTarget {
void Connected();
const std::string name_;
- Mode mode_;
- uint16_t server_key_bits_;
- PRFileDesc* pr_fd_;
- DummyPrSocket* adapter_;
- PRFileDesc* ssl_fd_;
+ SSLProtocolVariant variant_;
Role role_;
+ uint16_t server_key_bits_;
+ std::shared_ptr<DummyPrSocket> adapter_;
+ ScopedPRFileDesc ssl_fd_;
State state_;
- Poller::Timer* timer_handle_;
+ std::shared_ptr<Poller::Timer> timer_handle_;
bool falsestart_enabled_;
uint16_t expected_version_;
uint16_t expected_cipher_suite_;
@@ -352,6 +373,10 @@ class TlsAgent : public PollTarget {
bool can_falsestart_hook_called_;
bool sni_hook_called_;
bool auth_certificate_hook_called_;
+ uint8_t expected_received_alert_;
+ uint8_t expected_received_alert_level_;
+ uint8_t expected_sent_alert_;
+ uint8_t expected_sent_alert_level_;
bool handshake_callback_called_;
SSLChannelInfo info_;
SSLCipherSuiteInfo csinfo_;
@@ -364,6 +389,7 @@ class TlsAgent : public PollTarget {
AuthCertificateCallbackFunction auth_certificate_callback_;
SniCallbackFunction sni_callback_;
bool expect_short_headers_;
+ bool skip_version_checks_;
};
inline std::ostream& operator<<(std::ostream& stream,
@@ -375,20 +401,23 @@ class TlsAgentTestBase : public ::testing::Test {
public:
static ::testing::internal::ParamGenerator<std::string> kTlsRolesAll;
- TlsAgentTestBase(TlsAgent::Role role, Mode mode)
- : agent_(nullptr), fd_(nullptr), role_(role), mode_(mode) {}
- ~TlsAgentTestBase() {
- if (fd_) {
- PR_Close(fd_);
- }
- }
+ TlsAgentTestBase(TlsAgent::Role role, SSLProtocolVariant variant,
+ uint16_t version = 0)
+ : agent_(nullptr),
+ role_(role),
+ variant_(variant),
+ version_(version),
+ sink_adapter_(new DummyPrSocket("sink", variant)) {}
+ virtual ~TlsAgentTestBase() {}
void SetUp();
void TearDown();
- static void MakeRecord(Mode mode, uint8_t type, uint16_t version,
- const uint8_t* buf, size_t len, DataBuffer* out,
- uint64_t seq_num = 0);
+ void ExpectAlert(uint8_t alert);
+
+ static void MakeRecord(SSLProtocolVariant variant, uint8_t type,
+ uint16_t version, const uint8_t* buf, size_t len,
+ DataBuffer* out, uint64_t seq_num = 0);
void MakeRecord(uint8_t type, uint16_t version, const uint8_t* buf,
size_t len, DataBuffer* out, uint64_t seq_num = 0) const;
void MakeHandshakeMessage(uint8_t hs_type, const uint8_t* data, size_t hs_len,
@@ -403,10 +432,6 @@ class TlsAgentTestBase : public ::testing::Test {
return str == "CLIENT" ? TlsAgent::CLIENT : TlsAgent::SERVER;
}
- static inline Mode ToMode(const std::string& str) {
- return str == "TLS" ? STREAM : DGRAM;
- }
-
void Init(const std::string& server_name = TlsAgent::kServerRsa);
void Reset(const std::string& server_name = TlsAgent::kServerRsa);
@@ -415,43 +440,57 @@ class TlsAgentTestBase : public ::testing::Test {
void ProcessMessage(const DataBuffer& buffer, TlsAgent::State expected_state,
int32_t error_code = 0);
- TlsAgent* agent_;
- PRFileDesc* fd_;
+ std::unique_ptr<TlsAgent> agent_;
TlsAgent::Role role_;
- Mode mode_;
+ SSLProtocolVariant variant_;
+ uint16_t version_;
+ // This adapter is here just to accept packets from this agent.
+ std::shared_ptr<DummyPrSocket> sink_adapter_;
};
-class TlsAgentTest : public TlsAgentTestBase,
- public ::testing::WithParamInterface<
- std::tuple<std::string, std::string>> {
+class TlsAgentTest
+ : public TlsAgentTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<std::string, SSLProtocolVariant, uint16_t>> {
public:
TlsAgentTest()
: TlsAgentTestBase(ToRole(std::get<0>(GetParam())),
- ToMode(std::get<1>(GetParam()))) {}
+ std::get<1>(GetParam()), std::get<2>(GetParam())) {}
};
class TlsAgentTestClient : public TlsAgentTestBase,
- public ::testing::WithParamInterface<std::string> {
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsAgentTestClient()
- : TlsAgentTestBase(TlsAgent::CLIENT, ToMode(GetParam())) {}
+ : TlsAgentTestBase(TlsAgent::CLIENT, std::get<0>(GetParam()),
+ std::get<1>(GetParam())) {}
};
+class TlsAgentTestClient13 : public TlsAgentTestClient {};
+
class TlsAgentStreamTestClient : public TlsAgentTestBase {
public:
- TlsAgentStreamTestClient() : TlsAgentTestBase(TlsAgent::CLIENT, STREAM) {}
+ TlsAgentStreamTestClient()
+ : TlsAgentTestBase(TlsAgent::CLIENT, ssl_variant_stream) {}
};
class TlsAgentStreamTestServer : public TlsAgentTestBase {
public:
- TlsAgentStreamTestServer() : TlsAgentTestBase(TlsAgent::SERVER, STREAM) {}
+ TlsAgentStreamTestServer()
+ : TlsAgentTestBase(TlsAgent::SERVER, ssl_variant_stream) {}
};
class TlsAgentDgramTestClient : public TlsAgentTestBase {
public:
- TlsAgentDgramTestClient() : TlsAgentTestBase(TlsAgent::CLIENT, DGRAM) {}
+ TlsAgentDgramTestClient()
+ : TlsAgentTestBase(TlsAgent::CLIENT, ssl_variant_datagram) {}
};
+inline bool operator==(const SSLVersionRange& vr1, const SSLVersionRange& vr2) {
+ return vr1.min == vr2.min && vr1.max == vr2.max;
+}
+
} // namespace nss_test
#endif
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.cc b/security/nss/gtests/ssl_gtest/tls_connect.cc
index d02549954..c8de5a1fe 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -13,23 +13,27 @@ extern "C" {
#include "databuffer.h"
#include "gtest_utils.h"
+#include "scoped_ptrs.h"
#include "sslproto.h"
extern std::string g_working_dir_path;
namespace nss_test {
-static const std::string kTlsModesStreamArr[] = {"TLS"};
-::testing::internal::ParamGenerator<std::string>
- TlsConnectTestBase::kTlsModesStream =
- ::testing::ValuesIn(kTlsModesStreamArr);
-static const std::string kTlsModesDatagramArr[] = {"DTLS"};
-::testing::internal::ParamGenerator<std::string>
- TlsConnectTestBase::kTlsModesDatagram =
- ::testing::ValuesIn(kTlsModesDatagramArr);
-static const std::string kTlsModesAllArr[] = {"TLS", "DTLS"};
-::testing::internal::ParamGenerator<std::string>
- TlsConnectTestBase::kTlsModesAll = ::testing::ValuesIn(kTlsModesAllArr);
+static const SSLProtocolVariant kTlsVariantsStreamArr[] = {ssl_variant_stream};
+::testing::internal::ParamGenerator<SSLProtocolVariant>
+ TlsConnectTestBase::kTlsVariantsStream =
+ ::testing::ValuesIn(kTlsVariantsStreamArr);
+static const SSLProtocolVariant kTlsVariantsDatagramArr[] = {
+ ssl_variant_datagram};
+::testing::internal::ParamGenerator<SSLProtocolVariant>
+ TlsConnectTestBase::kTlsVariantsDatagram =
+ ::testing::ValuesIn(kTlsVariantsDatagramArr);
+static const SSLProtocolVariant kTlsVariantsAllArr[] = {ssl_variant_stream,
+ ssl_variant_datagram};
+::testing::internal::ParamGenerator<SSLProtocolVariant>
+ TlsConnectTestBase::kTlsVariantsAll =
+ ::testing::ValuesIn(kTlsVariantsAllArr);
static const uint16_t kTlsV10Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0};
::testing::internal::ParamGenerator<uint16_t> TlsConnectTestBase::kTlsV10 =
@@ -99,30 +103,29 @@ std::string VersionString(uint16_t version) {
}
}
-TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
- : mode_(mode),
- client_(new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_)),
- server_(new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_)),
+TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
+ uint16_t version)
+ : variant_(variant),
+ client_(new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, variant_)),
+ server_(new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, variant_)),
client_model_(nullptr),
server_model_(nullptr),
version_(version),
expected_resumption_mode_(RESUME_NONE),
session_ids_(),
expect_extended_master_secret_(false),
- expect_early_data_accepted_(false) {
+ expect_early_data_accepted_(false),
+ skip_version_checks_(false) {
std::string v;
- if (mode_ == DGRAM && version_ == SSL_LIBRARY_VERSION_TLS_1_1) {
+ if (variant_ == ssl_variant_datagram &&
+ version_ == SSL_LIBRARY_VERSION_TLS_1_1) {
v = "1.0";
} else {
v = VersionString(version_);
}
- std::cerr << "Version: " << mode_ << " " << v << std::endl;
+ std::cerr << "Version: " << variant_ << " " << v << std::endl;
}
-TlsConnectTestBase::TlsConnectTestBase(const std::string& mode,
- uint16_t version)
- : TlsConnectTestBase(TlsConnectTestBase::ToMode(mode), version) {}
-
TlsConnectTestBase::~TlsConnectTestBase() {}
// Check the group of each of the supported groups
@@ -166,35 +169,29 @@ void TlsConnectTestBase::ClearStats() {
void TlsConnectTestBase::ClearServerCache() {
SSL_ShutdownServerSessionIDCache();
- SSLInt_ClearSessionTicketKey();
+ SSLInt_ClearSelfEncryptKey();
SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
}
void TlsConnectTestBase::SetUp() {
SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
- SSLInt_ClearSessionTicketKey();
+ SSLInt_ClearSelfEncryptKey();
+ SSLInt_SetTicketLifetime(30);
+ SSLInt_SetMaxEarlyDataSize(1024);
ClearStats();
Init();
}
void TlsConnectTestBase::TearDown() {
- delete client_;
- delete server_;
- if (client_model_) {
- ASSERT_NE(server_model_, nullptr);
- delete client_model_;
- delete server_model_;
- }
+ client_ = nullptr;
+ server_ = nullptr;
SSL_ClearSessionCache();
- SSLInt_ClearSessionTicketKey();
+ SSLInt_ClearSelfEncryptKey();
SSL_ShutdownServerSessionIDCache();
}
void TlsConnectTestBase::Init() {
- EXPECT_TRUE(client_->Init());
- EXPECT_TRUE(server_->Init());
-
client_->SetPeer(server_);
server_->SetPeer(client_);
@@ -212,11 +209,12 @@ void TlsConnectTestBase::Reset() {
void TlsConnectTestBase::Reset(const std::string& server_name,
const std::string& client_name) {
- delete client_;
- delete server_;
-
- client_ = new TlsAgent(client_name, TlsAgent::CLIENT, mode_);
- server_ = new TlsAgent(server_name, TlsAgent::SERVER, mode_);
+ client_.reset(new TlsAgent(client_name, TlsAgent::CLIENT, variant_));
+ server_.reset(new TlsAgent(server_name, TlsAgent::SERVER, variant_));
+ if (skip_version_checks_) {
+ client_->SkipVersionChecks();
+ server_->SkipVersionChecks();
+ }
Init();
}
@@ -276,10 +274,12 @@ void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite) {
}
void TlsConnectTestBase::CheckConnected() {
- // Check the version is as expected
EXPECT_EQ(client_->version(), server_->version());
- EXPECT_EQ(std::min(client_->max_version(), server_->max_version()),
- client_->version());
+ if (!skip_version_checks_) {
+ // Check the version is as expected
+ EXPECT_EQ(std::min(client_->max_version(), server_->max_version()),
+ client_->version());
+ }
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
@@ -345,6 +345,13 @@ void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
scheme = ssl_sig_none;
break;
case ssl_auth_rsa_sign:
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ scheme = ssl_sig_rsa_pss_sha256;
+ } else {
+ scheme = ssl_sig_rsa_pkcs1_sha256;
+ }
+ break;
+ case ssl_auth_rsa_pss:
scheme = ssl_sig_rsa_pss_sha256;
break;
case ssl_auth_ecdsa:
@@ -373,7 +380,36 @@ void TlsConnectTestBase::ConnectExpectFail() {
ASSERT_EQ(TlsAgent::STATE_ERROR, server_->state());
}
+void TlsConnectTestBase::ExpectAlert(std::shared_ptr<TlsAgent>& sender,
+ uint8_t alert) {
+ EnsureTlsSetup();
+ auto receiver = (sender == client_) ? server_ : client_;
+ sender->ExpectSendAlert(alert);
+ receiver->ExpectReceiveAlert(alert);
+}
+
+void TlsConnectTestBase::ConnectExpectAlert(std::shared_ptr<TlsAgent>& sender,
+ uint8_t alert) {
+ ExpectAlert(sender, alert);
+ ConnectExpectFail();
+}
+
+void TlsConnectTestBase::ConnectExpectFailOneSide(TlsAgent::Role failing_side) {
+ server_->StartConnect();
+ client_->StartConnect();
+ client_->SetServerKeyBits(server_->server_key_bits());
+ client_->Handshake();
+ server_->Handshake();
+
+ auto failing_agent = server_;
+ if (failing_side == TlsAgent::CLIENT) {
+ failing_agent = client_;
+ }
+ ASSERT_TRUE_WAIT(failing_agent->state() == TlsAgent::STATE_ERROR, 5000);
+}
+
void TlsConnectTestBase::ConfigureVersion(uint16_t version) {
+ version_ = version;
client_->SetVersionRange(version, version);
server_->SetVersionRange(version, version);
}
@@ -424,10 +460,16 @@ void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
client_->ConfigureSessionCache(client);
server_->ConfigureSessionCache(server);
if ((server & RESUME_TICKET) != 0) {
- // This is an abomination. NSS encrypts session tickets with the server's
- // RSA public key. That means we need the server to have an RSA certificate
- // even if it won't be used for the connection.
- server_->ConfigServerCert(TlsAgent::kServerRsaDecrypt);
+ ScopedCERTCertificate cert;
+ ScopedSECKEYPrivateKey privKey;
+ ASSERT_TRUE(TlsAgent::LoadCertificate(TlsAgent::kServerRsaDecrypt, &cert,
+ &privKey));
+
+ ScopedSECKEYPublicKey pubKey(CERT_ExtractPublicKey(cert.get()));
+ ASSERT_TRUE(pubKey);
+
+ EXPECT_EQ(SECSuccess,
+ SSL_SetSessionTicketKeyPair(pubKey.get(), privKey.get()));
}
}
@@ -472,13 +514,15 @@ void TlsConnectTestBase::EnsureModelSockets() {
// Make sure models agents are available.
if (!client_model_) {
ASSERT_EQ(server_model_, nullptr);
- client_model_ = new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_);
- server_model_ = new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_);
+ client_model_.reset(
+ new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, variant_));
+ server_model_.reset(
+ new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, variant_));
+ if (skip_version_checks_) {
+ client_model_->SkipVersionChecks();
+ server_model_->SkipVersionChecks();
+ }
}
-
- // Initialise agents.
- ASSERT_TRUE(client_model_->Init());
- ASSERT_TRUE(server_model_->Init());
}
void TlsConnectTestBase::CheckAlpn(const std::string& val) {
@@ -540,6 +584,10 @@ void TlsConnectTestBase::ZeroRttSendReceive(
const char* k0RttData = "ABCDEF";
const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
+ if (expect_writable && expect_readable) {
+ ExpectAlert(client_, kTlsAlertEndOfEarlyData);
+ }
+
client_->Handshake(); // Send ClientHello.
if (post_clienthello_check) {
if (!post_clienthello_check()) return;
@@ -599,6 +647,12 @@ void TlsConnectTestBase::DisableECDHEServerKeyReuse() {
server_->DisableECDHEServerKeyReuse();
}
+void TlsConnectTestBase::SkipVersionChecks() {
+ skip_version_checks_ = true;
+ client_->SkipVersionChecks();
+ server_->SkipVersionChecks();
+}
+
TlsConnectGeneric::TlsConnectGeneric()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
@@ -616,16 +670,17 @@ TlsConnectTls13::TlsConnectTls13()
void TlsKeyExchangeTest::EnsureKeyShareSetup() {
EnsureTlsSetup();
- groups_capture_ = new TlsExtensionCapture(ssl_supported_groups_xtn);
- shares_capture_ = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
- shares_capture2_ = new TlsExtensionCapture(ssl_tls13_key_share_xtn, true);
- std::vector<PacketFilter*> captures;
- captures.push_back(groups_capture_);
- captures.push_back(shares_capture_);
- captures.push_back(shares_capture2_);
- client_->SetPacketFilter(new ChainedPacketFilter(captures));
- capture_hrr_ =
- new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+ groups_capture_ =
+ std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+ shares_capture_ =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+ shares_capture2_ =
+ std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn, true);
+ std::vector<std::shared_ptr<PacketFilter>> captures = {
+ groups_capture_, shares_capture_, shares_capture2_};
+ client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
+ capture_hrr_ = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeHelloRetryRequest);
server_->SetPacketFilter(capture_hrr_);
}
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.h b/security/nss/gtests/ssl_gtest/tls_connect.h
index aa4a32d96..73e8dc81a 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -25,9 +25,12 @@ extern std::string VersionString(uint16_t version);
// A generic TLS connection test base.
class TlsConnectTestBase : public ::testing::Test {
public:
- static ::testing::internal::ParamGenerator<std::string> kTlsModesStream;
- static ::testing::internal::ParamGenerator<std::string> kTlsModesDatagram;
- static ::testing::internal::ParamGenerator<std::string> kTlsModesAll;
+ static ::testing::internal::ParamGenerator<SSLProtocolVariant>
+ kTlsVariantsStream;
+ static ::testing::internal::ParamGenerator<SSLProtocolVariant>
+ kTlsVariantsDatagram;
+ static ::testing::internal::ParamGenerator<SSLProtocolVariant>
+ kTlsVariantsAll;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV10;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV11;
static ::testing::internal::ParamGenerator<uint16_t> kTlsV12;
@@ -39,8 +42,7 @@ class TlsConnectTestBase : public ::testing::Test {
static ::testing::internal::ParamGenerator<uint16_t> kTlsV12Plus;
static ::testing::internal::ParamGenerator<uint16_t> kTlsVAll;
- TlsConnectTestBase(Mode mode, uint16_t version);
- TlsConnectTestBase(const std::string& mode, uint16_t version);
+ TlsConnectTestBase(SSLProtocolVariant variant, uint16_t version);
virtual ~TlsConnectTestBase();
void SetUp();
@@ -68,6 +70,9 @@ class TlsConnectTestBase : public ::testing::Test {
void CheckConnected();
// Connect and expect it to fail.
void ConnectExpectFail();
+ void ExpectAlert(std::shared_ptr<TlsAgent>& sender, uint8_t alert);
+ void ConnectExpectAlert(std::shared_ptr<TlsAgent>& sender, uint8_t alert);
+ void ConnectExpectFailOneSide(TlsAgent::Role failingSide);
void ConnectWithCipherSuite(uint16_t cipher_suite);
// Check that the keys used in the handshake match expectations.
void CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
@@ -108,13 +113,14 @@ class TlsConnectTestBase : public ::testing::Test {
void ExpectExtendedMasterSecret(bool expected);
void ExpectEarlyDataAccepted(bool expected);
void DisableECDHEServerKeyReuse();
+ void SkipVersionChecks();
protected:
- Mode mode_;
- TlsAgent* client_;
- TlsAgent* server_;
- TlsAgent* client_model_;
- TlsAgent* server_model_;
+ SSLProtocolVariant variant_;
+ std::shared_ptr<TlsAgent> client_;
+ std::shared_ptr<TlsAgent> server_;
+ std::unique_ptr<TlsAgent> client_model_;
+ std::unique_ptr<TlsAgent> server_model_;
uint16_t version_;
SessionResumptionMode expected_resumption_mode_;
std::vector<std::vector<uint8_t>> session_ids_;
@@ -126,16 +132,13 @@ class TlsConnectTestBase : public ::testing::Test {
const uint8_t alpn_dummy_val_[4] = {0x01, 0x62, 0x01, 0x61};
private:
- static inline Mode ToMode(const std::string& str) {
- return str == "TLS" ? STREAM : DGRAM;
- }
-
void CheckResumption(SessionResumptionMode expected);
void CheckExtendedMasterSecret();
void CheckEarlyDataAccepted();
bool expect_extended_master_secret_;
bool expect_early_data_accepted_;
+ bool skip_version_checks_;
// Track groups and make sure that there are no duplicates.
class DuplicateGroupChecker {
@@ -154,20 +157,20 @@ class TlsConnectTestBase : public ::testing::Test {
// A non-parametrized TLS test base.
class TlsConnectTest : public TlsConnectTestBase {
public:
- TlsConnectTest() : TlsConnectTestBase(STREAM, 0) {}
+ TlsConnectTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
};
// A non-parametrized DTLS-only test base.
class DtlsConnectTest : public TlsConnectTestBase {
public:
- DtlsConnectTest() : TlsConnectTestBase(DGRAM, 0) {}
+ DtlsConnectTest() : TlsConnectTestBase(ssl_variant_datagram, 0) {}
};
// A TLS-only test base.
class TlsConnectStream : public TlsConnectTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
- TlsConnectStream() : TlsConnectTestBase(STREAM, GetParam()) {}
+ TlsConnectStream() : TlsConnectTestBase(ssl_variant_stream, GetParam()) {}
};
// A TLS-only test base for tests before 1.3
@@ -177,30 +180,30 @@ class TlsConnectStreamPre13 : public TlsConnectStream {};
class TlsConnectDatagram : public TlsConnectTestBase,
public ::testing::WithParamInterface<uint16_t> {
public:
- TlsConnectDatagram() : TlsConnectTestBase(DGRAM, GetParam()) {}
+ TlsConnectDatagram() : TlsConnectTestBase(ssl_variant_datagram, GetParam()) {}
};
-// 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>> {
+// A generic test class that can be either stream or datagram and a single
+// version of TLS. This is configured in ssl_loopback_unittest.cc.
+class TlsConnectGeneric : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsConnectGeneric();
};
// A Pre TLS 1.2 generic test.
-class TlsConnectPre12
- : public TlsConnectTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsConnectPre12 : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsConnectPre12();
};
// A TLS 1.2 only generic test.
-class TlsConnectTls12 : public TlsConnectTestBase,
- public ::testing::WithParamInterface<std::string> {
+class TlsConnectTls12
+ : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<SSLProtocolVariant> {
public:
TlsConnectTls12();
};
@@ -209,20 +212,21 @@ class TlsConnectTls12 : public TlsConnectTestBase,
class TlsConnectStreamTls12 : public TlsConnectTestBase {
public:
TlsConnectStreamTls12()
- : TlsConnectTestBase(STREAM, SSL_LIBRARY_VERSION_TLS_1_2) {}
+ : TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_2) {}
};
// A TLS 1.2+ generic test.
-class TlsConnectTls12Plus
- : public TlsConnectTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+class TlsConnectTls12Plus : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<
+ std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsConnectTls12Plus();
};
// A TLS 1.3 only generic test.
-class TlsConnectTls13 : public TlsConnectTestBase,
- public ::testing::WithParamInterface<std::string> {
+class TlsConnectTls13
+ : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<SSLProtocolVariant> {
public:
TlsConnectTls13();
};
@@ -231,13 +235,13 @@ class TlsConnectTls13 : public TlsConnectTestBase,
class TlsConnectStreamTls13 : public TlsConnectTestBase {
public:
TlsConnectStreamTls13()
- : TlsConnectTestBase(STREAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
+ : TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
};
class TlsConnectDatagram13 : public TlsConnectTestBase {
public:
TlsConnectDatagram13()
- : TlsConnectTestBase(DGRAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
+ : TlsConnectTestBase(ssl_variant_datagram, SSL_LIBRARY_VERSION_TLS_1_3) {}
};
// A variant that is used only with Pre13.
@@ -245,10 +249,10 @@ class TlsConnectGenericPre13 : public TlsConnectGeneric {};
class TlsKeyExchangeTest : public TlsConnectGeneric {
protected:
- TlsExtensionCapture* groups_capture_;
- TlsExtensionCapture* shares_capture_;
- TlsExtensionCapture* shares_capture2_;
- TlsInspectorRecordHandshakeMessage* capture_hrr_;
+ std::shared_ptr<TlsExtensionCapture> groups_capture_;
+ std::shared_ptr<TlsExtensionCapture> shares_capture_;
+ std::shared_ptr<TlsExtensionCapture> shares_capture2_;
+ std::shared_ptr<TlsInspectorRecordHandshakeMessage> capture_hrr_;
void EnsureKeyShareSetup();
void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.cc b/security/nss/gtests/ssl_gtest/tls_filter.cc
index 4f7d195d0..76d9aaaff 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -15,9 +15,62 @@ extern "C" {
#include <iostream>
#include "gtest_utils.h"
#include "tls_agent.h"
+#include "tls_filter.h"
+#include "tls_protect.h"
namespace nss_test {
+void TlsVersioned::WriteStream(std::ostream& stream) const {
+ stream << (is_dtls() ? "DTLS " : "TLS ");
+ switch (version()) {
+ case 0:
+ stream << "(no version)";
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_0:
+ stream << "1.0";
+ break;
+ case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ stream << (is_dtls() ? "1.0" : "1.1");
+ break;
+ case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ stream << "1.2";
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ stream << "1.3";
+ break;
+ default:
+ stream << "Invalid version: " << version();
+ break;
+ }
+}
+
+void TlsRecordFilter::EnableDecryption() {
+ SSLInt_SetCipherSpecChangeFunc(agent()->ssl_fd(), CipherSpecChanged,
+ (void*)this);
+}
+
+void TlsRecordFilter::CipherSpecChanged(void* arg, PRBool sending,
+ ssl3CipherSpec* newSpec) {
+ TlsRecordFilter* self = static_cast<TlsRecordFilter*>(arg);
+ PRBool isServer = self->agent()->role() == TlsAgent::SERVER;
+
+ if (g_ssl_gtest_verbose) {
+ std::cerr << "Cipher spec changed. Role="
+ << (isServer ? "server" : "client")
+ << " direction=" << (sending ? "send" : "receive") << std::endl;
+ }
+ if (!sending) return;
+
+ self->cipher_spec_.reset(new TlsCipherSpec());
+ bool ret =
+ self->cipher_spec_->Init(SSLInt_CipherSpecToAlgorithm(isServer, newSpec),
+ SSLInt_CipherSpecToKey(isServer, newSpec),
+ SSLInt_CipherSpecToIv(isServer, newSpec));
+ EXPECT_EQ(true, ret);
+}
+
PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
DataBuffer* output) {
bool changed = false;
@@ -25,10 +78,13 @@ PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
output->Allocate(input.len());
TlsParser parser(input);
+
while (parser.remaining()) {
- RecordHeader header;
+ TlsRecordHeader header;
DataBuffer record;
+
if (!header.Parse(&parser, &record)) {
+ ADD_FAILURE() << "not a valid record";
return KEEP;
}
@@ -49,12 +105,21 @@ PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
return KEEP;
}
-PacketFilter::Action TlsRecordFilter::FilterRecord(const RecordHeader& header,
- const DataBuffer& record,
- size_t* offset,
- DataBuffer* output) {
+PacketFilter::Action TlsRecordFilter::FilterRecord(
+ const TlsRecordHeader& header, const DataBuffer& record, size_t* offset,
+ DataBuffer* output) {
DataBuffer filtered;
- PacketFilter::Action action = FilterRecord(header, record, &filtered);
+ uint8_t inner_content_type;
+ DataBuffer plaintext;
+
+ if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
+ return KEEP;
+ }
+
+ TlsRecordHeader real_header = {header.version(), inner_content_type,
+ header.sequence_number()};
+
+ PacketFilter::Action action = FilterRecord(real_header, plaintext, &filtered);
if (action == KEEP) {
return KEEP;
}
@@ -64,19 +129,21 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(const RecordHeader& header,
return DROP;
}
- const DataBuffer* source = &record;
- if (action == CHANGE) {
- EXPECT_GT(0x10000U, filtered.len());
- std::cerr << "record old: " << record << std::endl;
- std::cerr << "record new: " << filtered << std::endl;
- source = &filtered;
- }
+ EXPECT_GT(0x10000U, filtered.len());
+ std::cerr << "record old: " << plaintext << std::endl;
+ std::cerr << "record new: " << filtered << std::endl;
- *offset = header.Write(output, *offset, *source);
+ DataBuffer ciphertext;
+ bool rv = Protect(header, inner_content_type, filtered, &ciphertext);
+ EXPECT_TRUE(rv);
+ if (!rv) {
+ return KEEP;
+ }
+ *offset = header.Write(output, *offset, ciphertext);
return CHANGE;
}
-bool TlsRecordFilter::RecordHeader::Parse(TlsParser* parser, DataBuffer* body) {
+bool TlsRecordHeader::Parse(TlsParser* parser, DataBuffer* body) {
if (!parser->Read(&content_type_)) {
return false;
}
@@ -102,8 +169,8 @@ bool TlsRecordFilter::RecordHeader::Parse(TlsParser* parser, DataBuffer* body) {
return parser->ReadVariable(body, 2);
}
-size_t TlsRecordFilter::RecordHeader::Write(DataBuffer* buffer, size_t offset,
- const DataBuffer& body) const {
+size_t TlsRecordHeader::Write(DataBuffer* buffer, size_t offset,
+ const DataBuffer& body) const {
offset = buffer->Write(offset, content_type_, 1);
offset = buffer->Write(offset, version_, 2);
if (is_dtls()) {
@@ -116,8 +183,48 @@ size_t TlsRecordFilter::RecordHeader::Write(DataBuffer* buffer, size_t offset,
return offset;
}
+bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
+ const DataBuffer& ciphertext,
+ uint8_t* inner_content_type,
+ DataBuffer* plaintext) {
+ if (!cipher_spec_ || header.content_type() != kTlsApplicationDataType) {
+ *inner_content_type = header.content_type();
+ *plaintext = ciphertext;
+ return true;
+ }
+
+ if (!cipher_spec_->Unprotect(header, ciphertext, plaintext)) return false;
+
+ size_t len = plaintext->len();
+ while (len > 0 && !plaintext->data()[len - 1]) {
+ --len;
+ }
+ if (!len) {
+ // Bogus padding.
+ return false;
+ }
+
+ *inner_content_type = plaintext->data()[len - 1];
+ plaintext->Truncate(len - 1);
+
+ return true;
+}
+
+bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
+ uint8_t inner_content_type,
+ const DataBuffer& plaintext,
+ DataBuffer* ciphertext) {
+ if (!cipher_spec_ || header.content_type() != kTlsApplicationDataType) {
+ *ciphertext = plaintext;
+ return true;
+ }
+ DataBuffer padded = plaintext;
+ padded.Write(padded.len(), inner_content_type, 1);
+ return cipher_spec_->Protect(header, padded, ciphertext);
+}
+
PacketFilter::Action TlsHandshakeFilter::FilterRecord(
- const RecordHeader& record_header, const DataBuffer& input,
+ const TlsRecordHeader& record_header, const DataBuffer& input,
DataBuffer* output) {
// Check that the first byte is as requested.
if (record_header.content_type() != kTlsHandshakeType) {
@@ -159,9 +266,8 @@ PacketFilter::Action TlsHandshakeFilter::FilterRecord(
return changed ? (offset ? CHANGE : DROP) : KEEP;
}
-bool TlsHandshakeFilter::HandshakeHeader::ReadLength(TlsParser* parser,
- const RecordHeader& header,
- uint32_t* length) {
+bool TlsHandshakeFilter::HandshakeHeader::ReadLength(
+ TlsParser* parser, const TlsRecordHeader& header, uint32_t* length) {
if (!parser->Read(length, 3)) {
return false; // malformed
}
@@ -192,7 +298,7 @@ bool TlsHandshakeFilter::HandshakeHeader::ReadLength(TlsParser* parser,
}
bool TlsHandshakeFilter::HandshakeHeader::Parse(
- TlsParser* parser, const RecordHeader& record_header, DataBuffer* body) {
+ TlsParser* parser, const TlsRecordHeader& record_header, DataBuffer* body) {
version_ = record_header.version();
if (!parser->Read(&handshake_type_)) {
return false; // malformed
@@ -205,15 +311,28 @@ bool TlsHandshakeFilter::HandshakeHeader::Parse(
return parser->Read(body, length);
}
-size_t TlsHandshakeFilter::HandshakeHeader::Write(
- DataBuffer* buffer, size_t offset, const DataBuffer& body) const {
+size_t TlsHandshakeFilter::HandshakeHeader::WriteFragment(
+ DataBuffer* buffer, size_t offset, const DataBuffer& body,
+ size_t fragment_offset, size_t fragment_length) const {
+ EXPECT_TRUE(is_dtls());
+ EXPECT_GE(body.len(), fragment_offset + fragment_length);
offset = buffer->Write(offset, handshake_type(), 1);
offset = buffer->Write(offset, body.len(), 3);
+ offset = buffer->Write(offset, message_seq_, 2);
+ offset = buffer->Write(offset, fragment_offset, 3);
+ offset = buffer->Write(offset, fragment_length, 3);
+ offset =
+ buffer->Write(offset, body.data() + fragment_offset, fragment_length);
+ return offset;
+}
+
+size_t TlsHandshakeFilter::HandshakeHeader::Write(
+ DataBuffer* buffer, size_t offset, const DataBuffer& body) const {
if (is_dtls()) {
- offset = buffer->Write(offset, message_seq_, 2);
- offset = buffer->Write(offset, 0U, 3); // fragment_offset
- offset = buffer->Write(offset, body.len(), 3);
+ return WriteFragment(buffer, offset, body, 0U, body.len());
}
+ offset = buffer->Write(offset, handshake_type(), 1);
+ offset = buffer->Write(offset, body.len(), 3);
offset = buffer->Write(offset, body);
return offset;
}
@@ -244,42 +363,12 @@ PacketFilter::Action TlsInspectorReplaceHandshakeMessage::FilterHandshake(
}
PacketFilter::Action TlsConversationRecorder::FilterRecord(
- const RecordHeader& header, const DataBuffer& input, DataBuffer* output) {
+ const TlsRecordHeader& header, const DataBuffer& input,
+ DataBuffer* output) {
buffer_.Append(input);
return KEEP;
}
-PacketFilter::Action TlsAlertRecorder::FilterRecord(const RecordHeader& header,
- const DataBuffer& input,
- DataBuffer* output) {
- if (level_ == kTlsAlertFatal) { // already fatal
- return KEEP;
- }
- if (header.content_type() != kTlsAlertType) {
- return KEEP;
- }
-
- std::cerr << "Alert: " << input << std::endl;
-
- TlsParser parser(input);
- uint8_t lvl;
- if (!parser.Read(&lvl)) {
- return KEEP;
- }
- if (lvl == kTlsAlertWarning) { // not strong enough
- return KEEP;
- }
- level_ = lvl;
- (void)parser.Read(&description_);
- return KEEP;
-}
-
-ChainedPacketFilter::~ChainedPacketFilter() {
- for (auto it = filters_.begin(); it != filters_.end(); ++it) {
- delete *it;
- }
-}
-
PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
DataBuffer* output) {
DataBuffer in(input);
@@ -297,28 +386,7 @@ PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
return changed ? CHANGE : KEEP;
}
-PacketFilter::Action TlsExtensionFilter::FilterHandshake(
- const HandshakeHeader& header, const DataBuffer& input,
- DataBuffer* output) {
- if (header.handshake_type() == kTlsHandshakeClientHello) {
- TlsParser parser(input);
- if (!FindClientHelloExtensions(&parser, header)) {
- return KEEP;
- }
- return FilterExtensions(&parser, input, output);
- }
- if (header.handshake_type() == kTlsHandshakeServerHello) {
- TlsParser parser(input);
- if (!FindServerHelloExtensions(&parser)) {
- return KEEP;
- }
- return FilterExtensions(&parser, input, output);
- }
- return KEEP;
-}
-
-bool TlsExtensionFilter::FindClientHelloExtensions(TlsParser* parser,
- const Versioned& header) {
+bool FindClientHelloExtensions(TlsParser* parser, const TlsVersioned& header) {
if (!parser->Skip(2 + 32)) { // version + random
return false;
}
@@ -337,7 +405,7 @@ bool TlsExtensionFilter::FindClientHelloExtensions(TlsParser* parser,
return true;
}
-bool TlsExtensionFilter::FindServerHelloExtensions(TlsParser* parser) {
+bool FindServerHelloExtensions(TlsParser* parser, const TlsVersioned& header) {
uint32_t vtmp;
if (!parser->Read(&vtmp, 2)) {
return false;
@@ -362,6 +430,92 @@ bool TlsExtensionFilter::FindServerHelloExtensions(TlsParser* parser) {
return true;
}
+static bool FindHelloRetryExtensions(TlsParser* parser,
+ const TlsVersioned& header) {
+ // TODO for -19 add cipher suite
+ if (!parser->Skip(2)) { // version
+ return false;
+ }
+ return true;
+}
+
+bool FindEncryptedExtensions(TlsParser* parser, const TlsVersioned& header) {
+ return true;
+}
+
+static bool FindCertReqExtensions(TlsParser* parser,
+ const TlsVersioned& header) {
+ if (!parser->SkipVariable(1)) { // request context
+ return false;
+ }
+ // TODO remove the next two for -19
+ if (!parser->SkipVariable(2)) { // signature_algorithms
+ return false;
+ }
+ if (!parser->SkipVariable(2)) { // certificate_authorities
+ return false;
+ }
+ return true;
+}
+
+// Only look at the EE cert for this one.
+static bool FindCertificateExtensions(TlsParser* parser,
+ const TlsVersioned& header) {
+ if (!parser->SkipVariable(1)) { // request context
+ return false;
+ }
+ if (!parser->Skip(3)) { // length of certificate list
+ return false;
+ }
+ if (!parser->SkipVariable(3)) { // ASN1Cert
+ return false;
+ }
+ return true;
+}
+
+static bool FindNewSessionTicketExtensions(TlsParser* parser,
+ const TlsVersioned& header) {
+ if (!parser->Skip(8)) { // lifetime, age add
+ return false;
+ }
+ if (!parser->SkipVariable(2)) { // ticket
+ return false;
+ }
+ return true;
+}
+
+static const std::map<uint16_t, TlsExtensionFinder> kExtensionFinders = {
+ {kTlsHandshakeClientHello, FindClientHelloExtensions},
+ {kTlsHandshakeServerHello, FindServerHelloExtensions},
+ {kTlsHandshakeHelloRetryRequest, FindHelloRetryExtensions},
+ {kTlsHandshakeEncryptedExtensions, FindEncryptedExtensions},
+ {kTlsHandshakeCertificateRequest, FindCertReqExtensions},
+ {kTlsHandshakeCertificate, FindCertificateExtensions},
+ {kTlsHandshakeNewSessionTicket, FindNewSessionTicketExtensions}};
+
+bool TlsExtensionFilter::FindExtensions(TlsParser* parser,
+ const HandshakeHeader& header) {
+ auto it = kExtensionFinders.find(header.handshake_type());
+ if (it == kExtensionFinders.end()) {
+ return false;
+ }
+ return (it->second)(parser, header);
+}
+
+PacketFilter::Action TlsExtensionFilter::FilterHandshake(
+ const HandshakeHeader& header, const DataBuffer& input,
+ DataBuffer* output) {
+ if (handshake_types_.count(header.handshake_type()) == 0) {
+ return KEEP;
+ }
+
+ TlsParser parser(input);
+ if (!FindExtensions(&parser, header)) {
+ return KEEP;
+ }
+ return FilterExtensions(&parser, input, output);
+}
+
PacketFilter::Action TlsExtensionFilter::FilterExtensions(
TlsParser* parser, const DataBuffer& input, DataBuffer* output) {
size_t length_offset = parser->consumed();
@@ -456,14 +610,14 @@ PacketFilter::Action TlsExtensionDropper::FilterExtension(
return KEEP;
}
-PacketFilter::Action AfterRecordN::FilterRecord(const RecordHeader& header,
+PacketFilter::Action AfterRecordN::FilterRecord(const TlsRecordHeader& header,
const DataBuffer& body,
DataBuffer* out) {
if (counter_++ == record_) {
DataBuffer buf;
header.Write(&buf, 0, body);
- src_->SendDirect(buf);
- dest_->Handshake();
+ src_.lock()->SendDirect(buf);
+ dest_.lock()->Handshake();
func_();
return DROP;
}
@@ -476,7 +630,7 @@ PacketFilter::Action TlsInspectorClientHelloVersionChanger::FilterHandshake(
DataBuffer* output) {
if (header.handshake_type() == kTlsHandshakeClientKeyExchange) {
EXPECT_EQ(SECSuccess,
- SSLInt_IncrementClientHandshakeVersion(server_->ssl_fd()));
+ SSLInt_IncrementClientHandshakeVersion(server_.lock()->ssl_fd()));
}
return KEEP;
}
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.h b/security/nss/gtests/ssl_gtest/tls_filter.h
index fa2e38785..e4030e23f 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -9,17 +9,67 @@
#include <functional>
#include <memory>
+#include <set>
#include <vector>
#include "test_io.h"
#include "tls_parser.h"
+#include "tls_protect.h"
+
+extern "C" {
+#include "libssl_internals.h"
+}
namespace nss_test {
+class TlsCipherSpec;
+class TlsAgent;
+
+class TlsVersioned {
+ public:
+ TlsVersioned() : version_(0) {}
+ explicit TlsVersioned(uint16_t version) : version_(version) {}
+
+ bool is_dtls() const { return IsDtls(version_); }
+ uint16_t version() const { return version_; }
+
+ void WriteStream(std::ostream& stream) const;
+
+ protected:
+ uint16_t version_;
+};
+
+class TlsRecordHeader : public TlsVersioned {
+ public:
+ TlsRecordHeader() : TlsVersioned(), content_type_(0), sequence_number_(0) {}
+ TlsRecordHeader(uint16_t version, uint8_t content_type,
+ uint64_t sequence_number)
+ : TlsVersioned(version),
+ content_type_(content_type),
+ sequence_number_(sequence_number) {}
+
+ uint8_t content_type() const { return content_type_; }
+ uint64_t sequence_number() const { return sequence_number_; }
+ size_t header_length() const { return is_dtls() ? 11 : 3; }
+
+ // Parse the header; return true if successful; body in an outparam if OK.
+ bool Parse(TlsParser* parser, DataBuffer* body);
+ // Write the header and body to a buffer at the given offset.
+ // Return the offset of the end of the write.
+ size_t Write(DataBuffer* buffer, size_t offset, const DataBuffer& body) const;
+
+ private:
+ uint8_t content_type_;
+ uint64_t sequence_number_;
+};
+
// Abstract filter that operates on entire (D)TLS records.
class TlsRecordFilter : public PacketFilter {
public:
- TlsRecordFilter() : count_(0) {}
+ TlsRecordFilter() : agent_(nullptr), count_(0), cipher_spec_() {}
+
+ void SetAgent(const TlsAgent* agent) { agent_ = agent; }
+ const TlsAgent* agent() const { return agent_; }
// External interface. Overrides PacketFilter.
PacketFilter::Action Filter(const DataBuffer& input, DataBuffer* output);
@@ -27,42 +77,14 @@ class TlsRecordFilter : public PacketFilter {
// Report how many packets were altered by the filter.
size_t filtered_packets() const { return count_; }
- class Versioned {
- public:
- Versioned() : version_(0) {}
- explicit Versioned(uint16_t version) : version_(version) {}
-
- bool is_dtls() const { return IsDtls(version_); }
- uint16_t version() const { return version_; }
-
- protected:
- uint16_t version_;
- };
-
- class RecordHeader : public Versioned {
- public:
- RecordHeader() : Versioned(), content_type_(0), sequence_number_(0) {}
- RecordHeader(uint16_t version, uint8_t content_type,
- uint64_t sequence_number)
- : Versioned(version),
- content_type_(content_type),
- sequence_number_(sequence_number) {}
-
- uint8_t content_type() const { return content_type_; }
- uint64_t sequence_number() const { return sequence_number_; }
- size_t header_length() const { return is_dtls() ? 11 : 3; }
-
- // Parse the header; return true if successful; body in an outparam if OK.
- bool Parse(TlsParser* parser, DataBuffer* body);
- // Write the header and body to a buffer at the given offset.
- // Return the offset of the end of the write.
- size_t Write(DataBuffer* buffer, size_t offset,
- const DataBuffer& body) const;
-
- private:
- uint8_t content_type_;
- uint64_t sequence_number_;
- };
+ // Enable decryption. This only works properly for TLS 1.3 and above.
+ // Enabling it for lower version tests will cause undefined
+ // behavior.
+ void EnableDecryption();
+ bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
+ uint8_t* inner_content_type, DataBuffer* plaintext);
+ bool Protect(const TlsRecordHeader& header, uint8_t inner_content_type,
+ const DataBuffer& plaintext, DataBuffer* ciphertext);
protected:
// There are two filter functions which can be overriden. Both are
@@ -72,7 +94,7 @@ class TlsRecordFilter : public PacketFilter {
// just lets you change the record contents. By default, the
// outer one calls the inner one, so if you override the outer
// one, the inner one is never called unless you call it yourself.
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record,
size_t* offset, DataBuffer* output);
@@ -80,16 +102,49 @@ class TlsRecordFilter : public PacketFilter {
// sequence number (which is zero for TLS), plus the existing record payload.
// It returns an action (KEEP, CHANGE, DROP). It writes to the `changed`
// outparam with the new record contents if it chooses to CHANGE the record.
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& data,
DataBuffer* changed) {
return KEEP;
}
private:
+ static void CipherSpecChanged(void* arg, PRBool sending,
+ ssl3CipherSpec* newSpec);
+
+ const TlsAgent* agent_;
size_t count_;
+ std::unique_ptr<TlsCipherSpec> cipher_spec_;
};
+inline std::ostream& operator<<(std::ostream& stream, TlsVersioned v) {
+ v.WriteStream(stream);
+ return stream;
+}
+
+inline std::ostream& operator<<(std::ostream& stream, TlsRecordHeader& hdr) {
+ hdr.WriteStream(stream);
+ stream << ' ';
+ switch (hdr.content_type()) {
+ case kTlsChangeCipherSpecType:
+ stream << "CCS";
+ break;
+ case kTlsAlertType:
+ stream << "Alert";
+ break;
+ case kTlsHandshakeType:
+ stream << "Handshake";
+ break;
+ case kTlsApplicationDataType:
+ stream << "Data";
+ break;
+ default:
+ stream << '<' << hdr.content_type() << '>';
+ break;
+ }
+ return stream << ' ' << std::hex << hdr.sequence_number() << std::dec;
+}
+
// Abstract filter that operates on handshake messages rather than records.
// This assumes that the handshake messages are written in a block as entire
// records and that they don't span records or anything crazy like that.
@@ -97,20 +152,23 @@ class TlsHandshakeFilter : public TlsRecordFilter {
public:
TlsHandshakeFilter() {}
- class HandshakeHeader : public Versioned {
+ class HandshakeHeader : public TlsVersioned {
public:
- HandshakeHeader() : Versioned(), handshake_type_(0), message_seq_(0) {}
+ HandshakeHeader() : TlsVersioned(), handshake_type_(0), message_seq_(0) {}
uint8_t handshake_type() const { return handshake_type_; }
- bool Parse(TlsParser* parser, const RecordHeader& record_header,
+ bool Parse(TlsParser* parser, const TlsRecordHeader& record_header,
DataBuffer* body);
size_t Write(DataBuffer* buffer, size_t offset,
const DataBuffer& body) const;
+ size_t WriteFragment(DataBuffer* buffer, size_t offset,
+ const DataBuffer& body, size_t fragment_offset,
+ size_t fragment_length) const;
private:
// Reads the length from the record header.
// This also reads the DTLS fragment information and checks it.
- bool ReadLength(TlsParser* parser, const RecordHeader& header,
+ bool ReadLength(TlsParser* parser, const TlsRecordHeader& header,
uint32_t* length);
uint8_t handshake_type_;
@@ -119,7 +177,7 @@ class TlsHandshakeFilter : public TlsRecordFilter {
};
protected:
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output);
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
@@ -167,7 +225,7 @@ class TlsConversationRecorder : public TlsRecordFilter {
public:
TlsConversationRecorder(DataBuffer& buffer) : buffer_(buffer) {}
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output);
@@ -175,43 +233,39 @@ class TlsConversationRecorder : public TlsRecordFilter {
DataBuffer& buffer_;
};
-// Records an alert. If an alert has already been recorded, it won't save the
-// new alert unless the old alert is a warning and the new one is fatal.
-class TlsAlertRecorder : public TlsRecordFilter {
- public:
- TlsAlertRecorder() : level_(255), description_(255) {}
-
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
- const DataBuffer& input,
- DataBuffer* output);
-
- uint8_t level() const { return level_; }
- uint8_t description() const { return description_; }
-
- private:
- uint8_t level_;
- uint8_t description_;
-};
-
// Runs multiple packet filters in series.
class ChainedPacketFilter : public PacketFilter {
public:
ChainedPacketFilter() {}
- ChainedPacketFilter(const std::vector<PacketFilter*> filters)
+ ChainedPacketFilter(const std::vector<std::shared_ptr<PacketFilter>> filters)
: filters_(filters.begin(), filters.end()) {}
- virtual ~ChainedPacketFilter();
+ virtual ~ChainedPacketFilter() {}
virtual PacketFilter::Action Filter(const DataBuffer& input,
DataBuffer* output);
// Takes ownership of the filter.
- void Add(PacketFilter* filter) { filters_.push_back(filter); }
+ void Add(std::shared_ptr<PacketFilter> filter) { filters_.push_back(filter); }
private:
- std::vector<PacketFilter*> filters_;
+ std::vector<std::shared_ptr<PacketFilter>> filters_;
};
+typedef std::function<bool(TlsParser* parser, const TlsVersioned& header)>
+ TlsExtensionFinder;
+
class TlsExtensionFilter : public TlsHandshakeFilter {
+ public:
+ TlsExtensionFilter() : handshake_types_() {
+ handshake_types_.insert(kTlsHandshakeClientHello);
+ handshake_types_.insert(kTlsHandshakeServerHello);
+ }
+
+ TlsExtensionFilter(const std::set<uint8_t>& types)
+ : handshake_types_(types) {}
+
+ static bool FindExtensions(TlsParser* parser, const HandshakeHeader& header);
+
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
@@ -221,15 +275,12 @@ class TlsExtensionFilter : public TlsHandshakeFilter {
const DataBuffer& input,
DataBuffer* output) = 0;
- public:
- static bool FindClientHelloExtensions(TlsParser* parser,
- const Versioned& header);
- static bool FindServerHelloExtensions(TlsParser* parser);
-
private:
PacketFilter::Action FilterExtensions(TlsParser* parser,
const DataBuffer& input,
DataBuffer* output);
+
+ std::set<uint8_t> handshake_types_;
};
class TlsExtensionCapture : public TlsExtensionFilter {
@@ -280,17 +331,17 @@ typedef std::function<void(void)> VoidFunction;
class AfterRecordN : public TlsRecordFilter {
public:
- AfterRecordN(TlsAgent* src, TlsAgent* dest, unsigned int record,
- VoidFunction func)
+ AfterRecordN(std::shared_ptr<TlsAgent>& src, std::shared_ptr<TlsAgent>& dest,
+ unsigned int record, VoidFunction func)
: src_(src), dest_(dest), record_(record), func_(func), counter_(0) {}
- virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& body,
DataBuffer* out) override;
private:
- TlsAgent* src_;
- TlsAgent* dest_;
+ std::weak_ptr<TlsAgent> src_;
+ std::weak_ptr<TlsAgent> dest_;
unsigned int record_;
VoidFunction func_;
unsigned int counter_;
@@ -300,14 +351,15 @@ class AfterRecordN : public TlsRecordFilter {
// ClientHelloVersion on |server|.
class TlsInspectorClientHelloVersionChanger : public TlsHandshakeFilter {
public:
- TlsInspectorClientHelloVersionChanger(TlsAgent* server) : server_(server) {}
+ TlsInspectorClientHelloVersionChanger(std::shared_ptr<TlsAgent>& server)
+ : server_(server) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output);
private:
- TlsAgent* server_;
+ std::weak_ptr<TlsAgent> server_;
};
// This class selectively drops complete writes. This relies on the fact that
@@ -338,6 +390,27 @@ class TlsInspectorClientHelloVersionSetter : public TlsHandshakeFilter {
uint16_t version_;
};
+// Damages the last byte of a handshake message.
+class TlsLastByteDamager : public TlsHandshakeFilter {
+ public:
+ TlsLastByteDamager(uint8_t type) : type_(type) {}
+ PacketFilter::Action FilterHandshake(
+ const TlsHandshakeFilter::HandshakeHeader& header,
+ const DataBuffer& input, DataBuffer* output) override {
+ if (header.handshake_type() != type_) {
+ return KEEP;
+ }
+
+ *output = input;
+
+ output->data()[output->len() - 1]++;
+ return CHANGE;
+ }
+
+ private:
+ uint8_t type_;
+};
+
} // namespace nss_test
#endif
diff --git a/security/nss/gtests/ssl_gtest/tls_parser.cc b/security/nss/gtests/ssl_gtest/tls_parser.cc
deleted file mode 100644
index e4c06aa91..000000000
--- a/security/nss/gtests/ssl_gtest/tls_parser.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- 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 "tls_parser.h"
-
-namespace nss_test {
-
-bool TlsParser::Read(uint8_t* val) {
- if (remaining() < 1) {
- return false;
- }
- *val = *ptr();
- consume(1);
- return true;
-}
-
-bool TlsParser::Read(uint32_t* val, size_t size) {
- if (size > sizeof(uint32_t)) {
- return false;
- }
-
- uint32_t v = 0;
- for (size_t i = 0; i < size; ++i) {
- uint8_t tmp;
- if (!Read(&tmp)) {
- return false;
- }
-
- v = (v << 8) | tmp;
- }
-
- *val = v;
- return true;
-}
-
-bool TlsParser::Read(DataBuffer* val, size_t len) {
- if (remaining() < len) {
- return false;
- }
-
- val->Assign(ptr(), len);
- consume(len);
- return true;
-}
-
-bool TlsParser::ReadVariable(DataBuffer* val, size_t len_size) {
- uint32_t len;
- if (!Read(&len, len_size)) {
- return false;
- }
- return Read(val, len);
-}
-
-bool TlsParser::Skip(size_t len) {
- if (len > remaining()) {
- return false;
- }
- consume(len);
- return true;
-}
-
-bool TlsParser::SkipVariable(size_t len_size) {
- uint32_t len;
- if (!Read(&len, len_size)) {
- return false;
- }
- return Skip(len);
-}
-
-} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/tls_parser.h b/security/nss/gtests/ssl_gtest/tls_parser.h
deleted file mode 100644
index c79d45a7e..000000000
--- a/security/nss/gtests/ssl_gtest/tls_parser.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- 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/. */
-
-#ifndef tls_parser_h_
-#define tls_parser_h_
-
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#if defined(WIN32) || defined(WIN64)
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
-#include "databuffer.h"
-
-namespace nss_test {
-
-const uint8_t kTlsChangeCipherSpecType = 20;
-const uint8_t kTlsAlertType = 21;
-const uint8_t kTlsHandshakeType = 22;
-const uint8_t kTlsApplicationDataType = 23;
-
-const uint8_t kTlsHandshakeClientHello = 1;
-const uint8_t kTlsHandshakeServerHello = 2;
-const uint8_t kTlsHandshakeHelloRetryRequest = 6;
-const uint8_t kTlsHandshakeEncryptedExtensions = 8;
-const uint8_t kTlsHandshakeCertificate = 11;
-const uint8_t kTlsHandshakeServerKeyExchange = 12;
-const uint8_t kTlsHandshakeCertificateVerify = 15;
-const uint8_t kTlsHandshakeClientKeyExchange = 16;
-const uint8_t kTlsHandshakeFinished = 20;
-
-const uint8_t kTlsAlertWarning = 1;
-const uint8_t kTlsAlertFatal = 2;
-
-const uint8_t kTlsAlertUnexpectedMessage = 10;
-const uint8_t kTlsAlertBadRecordMac = 20;
-const uint8_t kTlsAlertHandshakeFailure = 40;
-const uint8_t kTlsAlertIllegalParameter = 47;
-const uint8_t kTlsAlertDecodeError = 50;
-const uint8_t kTlsAlertDecryptError = 51;
-const uint8_t kTlsAlertMissingExtension = 109;
-const uint8_t kTlsAlertUnsupportedExtension = 110;
-const uint8_t kTlsAlertUnrecognizedName = 112;
-const uint8_t kTlsAlertNoApplicationProtocol = 120;
-
-const uint8_t kTlsFakeChangeCipherSpec[] = {
- kTlsChangeCipherSpecType, // Type
- 0xfe,
- 0xff, // Version
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x10, // Fictitious sequence #
- 0x00,
- 0x01, // Length
- 0x01 // Value
-};
-
-static const uint8_t kTls13PskKe = 0;
-static const uint8_t kTls13PskDhKe = 1;
-static const uint8_t kTls13PskAuth = 0;
-static const uint8_t kTls13PskSignAuth = 1;
-
-inline bool IsDtls(uint16_t version) { return (version & 0x8000) == 0x8000; }
-
-inline uint16_t NormalizeTlsVersion(uint16_t version) {
- if (version == 0xfeff) {
- return 0x0302; // special: DTLS 1.0 == TLS 1.1
- }
- if (IsDtls(version)) {
- return (version ^ 0xffff) + 0x0201;
- }
- return version;
-}
-
-inline uint16_t TlsVersionToDtlsVersion(uint16_t version) {
- if (version == 0x0302) {
- return 0xfeff;
- }
- if (version == 0x0304) {
- return version;
- }
- return 0xffff - version + 0x0201;
-}
-
-inline size_t WriteVariable(DataBuffer* target, size_t index,
- const DataBuffer& buf, size_t len_size) {
- index = target->Write(index, static_cast<uint32_t>(buf.len()), len_size);
- return target->Write(index, buf.data(), buf.len());
-}
-
-class TlsParser {
- public:
- TlsParser(const uint8_t* data, size_t len) : buffer_(data, len), offset_(0) {}
- explicit TlsParser(const DataBuffer& buf) : buffer_(buf), offset_(0) {}
-
- bool Read(uint8_t* val);
- // Read an integral type of specified width.
- bool Read(uint32_t* val, size_t size);
- // Reads len bytes into dest buffer, overwriting it.
- bool Read(DataBuffer* dest, size_t len);
- // Reads bytes into dest buffer, overwriting it. The number of bytes is
- // determined by reading from len_size bytes from the stream first.
- bool ReadVariable(DataBuffer* dest, size_t len_size);
-
- bool Skip(size_t len);
- bool SkipVariable(size_t len_size);
-
- size_t consumed() const { return offset_; }
- size_t remaining() const { return buffer_.len() - offset_; }
-
- private:
- void consume(size_t len) { offset_ += len; }
- const uint8_t* ptr() const { return buffer_.data() + offset_; }
-
- DataBuffer buffer_;
- size_t offset_;
-};
-
-} // namespace nss_test
-
-#endif
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.cc b/security/nss/gtests/ssl_gtest/tls_protect.cc
new file mode 100644
index 000000000..efcd89e14
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/tls_protect.cc
@@ -0,0 +1,145 @@
+/* -*- 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 "tls_protect.h"
+#include "tls_filter.h"
+
+namespace nss_test {
+
+AeadCipher::~AeadCipher() {
+ if (key_) {
+ PK11_FreeSymKey(key_);
+ }
+}
+
+bool AeadCipher::Init(PK11SymKey *key, const uint8_t *iv) {
+ key_ = PK11_ReferenceSymKey(key);
+ if (!key_) return false;
+
+ memcpy(iv_, iv, sizeof(iv_));
+ return true;
+}
+
+void AeadCipher::FormatNonce(uint64_t seq, uint8_t *nonce) {
+ memcpy(nonce, iv_, 12);
+
+ for (size_t i = 0; i < 8; ++i) {
+ nonce[12 - (i + 1)] ^= seq & 0xff;
+ seq >>= 8;
+ }
+
+ DataBuffer d(nonce, 12);
+ std::cerr << "Nonce " << d << std::endl;
+}
+
+bool AeadCipher::AeadInner(bool decrypt, void *params, size_t param_length,
+ const uint8_t *in, size_t inlen, uint8_t *out,
+ size_t *outlen, size_t maxlen) {
+ SECStatus rv;
+ unsigned int uoutlen = 0;
+ SECItem param = {
+ siBuffer, static_cast<unsigned char *>(params),
+ static_cast<unsigned int>(param_length),
+ };
+
+ if (decrypt) {
+ rv = PK11_Decrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
+ } else {
+ rv = PK11_Encrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
+ }
+ *outlen = (int)uoutlen;
+
+ return rv == SECSuccess;
+}
+
+bool AeadCipherAesGcm::Aead(bool decrypt, uint64_t seq, const uint8_t *in,
+ size_t inlen, uint8_t *out, size_t *outlen,
+ size_t maxlen) {
+ CK_GCM_PARAMS aeadParams;
+ unsigned char nonce[12];
+
+ memset(&aeadParams, 0, sizeof(aeadParams));
+ aeadParams.pIv = nonce;
+ aeadParams.ulIvLen = sizeof(nonce);
+ aeadParams.pAAD = NULL;
+ aeadParams.ulAADLen = 0;
+ aeadParams.ulTagBits = 128;
+
+ FormatNonce(seq, nonce);
+ return AeadInner(decrypt, (unsigned char *)&aeadParams, sizeof(aeadParams),
+ in, inlen, out, outlen, maxlen);
+}
+
+bool AeadCipherChacha20Poly1305::Aead(bool decrypt, uint64_t seq,
+ const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t *outlen,
+ size_t maxlen) {
+ CK_NSS_AEAD_PARAMS aeadParams;
+ unsigned char nonce[12];
+
+ memset(&aeadParams, 0, sizeof(aeadParams));
+ aeadParams.pNonce = nonce;
+ aeadParams.ulNonceLen = sizeof(nonce);
+ aeadParams.pAAD = NULL;
+ aeadParams.ulAADLen = 0;
+ aeadParams.ulTagLen = 16;
+
+ FormatNonce(seq, nonce);
+ return AeadInner(decrypt, (unsigned char *)&aeadParams, sizeof(aeadParams),
+ in, inlen, out, outlen, maxlen);
+}
+
+bool TlsCipherSpec::Init(SSLCipherAlgorithm cipher, PK11SymKey *key,
+ const uint8_t *iv) {
+ switch (cipher) {
+ case ssl_calg_aes_gcm:
+ aead_.reset(new AeadCipherAesGcm());
+ break;
+ case ssl_calg_chacha20:
+ aead_.reset(new AeadCipherChacha20Poly1305());
+ break;
+ default:
+ return false;
+ }
+
+ return aead_->Init(key, iv);
+}
+
+bool TlsCipherSpec::Unprotect(const TlsRecordHeader &header,
+ const DataBuffer &ciphertext,
+ DataBuffer *plaintext) {
+ // Make space.
+ plaintext->Allocate(ciphertext.len());
+
+ size_t len;
+ bool ret =
+ aead_->Aead(true, header.sequence_number(), ciphertext.data(),
+ ciphertext.len(), plaintext->data(), &len, plaintext->len());
+ if (!ret) return false;
+
+ plaintext->Truncate(len);
+
+ return true;
+}
+
+bool TlsCipherSpec::Protect(const TlsRecordHeader &header,
+ const DataBuffer &plaintext,
+ DataBuffer *ciphertext) {
+ // Make a padded buffer.
+
+ ciphertext->Allocate(plaintext.len() +
+ 32); // Room for any plausible auth tag
+ size_t len;
+ bool ret =
+ aead_->Aead(false, header.sequence_number(), plaintext.data(),
+ plaintext.len(), ciphertext->data(), &len, ciphertext->len());
+ if (!ret) return false;
+ ciphertext->Truncate(len);
+
+ return true;
+}
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.h b/security/nss/gtests/ssl_gtest/tls_protect.h
new file mode 100644
index 000000000..4efbd6e6b
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/tls_protect.h
@@ -0,0 +1,76 @@
+/* -*- 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/. */
+
+#ifndef tls_protection_h_
+#define tls_protection_h_
+
+#include <cstdint>
+#include <memory>
+
+#include "databuffer.h"
+#include "pk11pub.h"
+#include "sslt.h"
+
+namespace nss_test {
+class TlsRecordHeader;
+
+class AeadCipher {
+ public:
+ AeadCipher(CK_MECHANISM_TYPE mech) : mech_(mech), key_(nullptr) {}
+ ~AeadCipher();
+
+ bool Init(PK11SymKey *key, const uint8_t *iv);
+ virtual bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t *outlen, size_t maxlen) = 0;
+
+ protected:
+ void FormatNonce(uint64_t seq, uint8_t *nonce);
+ bool AeadInner(bool decrypt, void *params, size_t param_length,
+ const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
+ size_t maxlen);
+
+ CK_MECHANISM_TYPE mech_;
+ PK11SymKey *key_;
+ uint8_t iv_[12];
+};
+
+class AeadCipherChacha20Poly1305 : public AeadCipher {
+ public:
+ AeadCipherChacha20Poly1305() : AeadCipher(CKM_NSS_CHACHA20_POLY1305) {}
+
+ protected:
+ bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t *outlen, size_t maxlen);
+};
+
+class AeadCipherAesGcm : public AeadCipher {
+ public:
+ AeadCipherAesGcm() : AeadCipher(CKM_AES_GCM) {}
+
+ protected:
+ bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t *outlen, size_t maxlen);
+};
+
+// Our analog of ssl3CipherSpec
+class TlsCipherSpec {
+ public:
+ TlsCipherSpec() : aead_() {}
+
+ bool Init(SSLCipherAlgorithm cipher, PK11SymKey *key, const uint8_t *iv);
+
+ bool Protect(const TlsRecordHeader &header, const DataBuffer &plaintext,
+ DataBuffer *ciphertext);
+ bool Unprotect(const TlsRecordHeader &header, const DataBuffer &ciphertext,
+ DataBuffer *plaintext);
+
+ private:
+ std::unique_ptr<AeadCipher> aead_;
+};
+
+} // namespace nss_test
+
+#endif