mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 15:27:32 +09:00
Update NSS to 3.32.1-RTM
This commit is contained in:
parent
f29876f120
commit
c91ef9012b
512 changed files with 83203 additions and 16839 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
281
security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
Normal file
281
security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
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 (header.handshake_type() != handshake_type_) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
TlsParser parser(input);
|
||||
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) {}
|
||||
TlsExtensionTestBase(SSLProtocolVariant variant, uint16_t version)
|
||||
: TlsConnectTestBase(variant, 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());
|
||||
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);
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
|
||||
} // namespace nspr_test
|
||||
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
|
||||
|
|
|
|||
157
security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
Normal file
157
security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
Normal file
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
143
security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
Normal file
143
security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
Normal file
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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,66 +37,61 @@
|
|||
'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': [
|
||||
[ 'test_build==1', {
|
||||
'dependencies': [
|
||||
'<(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_dbm==0', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/dbm/src/src.gyp:dbm',
|
||||
],
|
||||
}],
|
||||
[ 'disable_libpkix==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',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
],
|
||||
'target_defaults': {
|
||||
'include_dirs': [
|
||||
'../../gtests/google_test/gtest/include',
|
||||
'../../gtests/common',
|
||||
'../../lib/ssl'
|
||||
],
|
||||
'defines': [
|
||||
'NSS_USE_STATIC_LIBS'
|
||||
],
|
||||
},
|
||||
'variables': {
|
||||
'module': 'nss',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
ConnectExpectFail();
|
||||
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
|
||||
EXPECT_EQ(alert, alert_recorder->description());
|
||||
client_->CheckErrorCode(error);
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
||||
} else {
|
||||
ASSERT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
INSTANTIATE_TEST_CASE_P(SkipVariants, TlsSkipTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsModesAll,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
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::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(Skip13Variants, Tls13SkipTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
394
security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
Normal file
394
security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
Normal file
|
|
@ -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
|
||||
|
|
@ -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, DummyPrSocket *adapter, PollTarget *target,
|
||||
PollCallback cb) {
|
||||
auto it = waiters_.find(adapter);
|
||||
Waiter *waiter;
|
||||
|
||||
if (it == waiters_.end()) {
|
||||
waiter = new Waiter(adapter);
|
||||
} else {
|
||||
waiter = it->second;
|
||||
}
|
||||
|
||||
void Poller::Wait(Event event, std::shared_ptr<DummyPrSocket> &adapter,
|
||||
PollTarget *target, PollCallback cb) {
|
||||
assert(event < TIMER_EVENT);
|
||||
if (event >= TIMER_EVENT) return;
|
||||
|
||||
std::unique_ptr<Waiter> waiter;
|
||||
auto it = waiters_.find(adapter);
|
||||
if (it == waiters_.end()) {
|
||||
waiter.reset(new Waiter(adapter));
|
||||
} else {
|
||||
waiter = std::move(it->second);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
server_key_bits_(0),
|
||||
pr_fd_(nullptr),
|
||||
adapter_(nullptr),
|
||||
ssl_fd_(nullptr),
|
||||
variant_(variant),
|
||||
role_(role),
|
||||
server_key_bits_(0),
|
||||
adapter_(new DummyPrSocket(role_str(), variant)),
|
||||
ssl_fd_(nullptr),
|
||||
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_HandshakeCallback(ssl_fd_, HandshakeCallback, this);
|
||||
rv = SSL_AlertReceivedCallback(ssl_fd(), AlertReceivedCallback, this);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
if (rv != SECSuccess) return false;
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 SetPacketFilter(PacketFilter* filter) {
|
||||
void SetTlsRecordFilter(std::shared_ptr<TlsRecordFilter> filter) {
|
||||
filter->SetAgent(this);
|
||||
adapter_->SetPacketFilter(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
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
145
security/nss/gtests/ssl_gtest/tls_protect.cc
Normal file
145
security/nss/gtests/ssl_gtest/tls_protect.cc
Normal file
|
|
@ -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_, ¶m, out, &uoutlen, maxlen, in, inlen);
|
||||
} else {
|
||||
rv = PK11_Encrypt(key_, mech_, ¶m, 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
|
||||
76
security/nss/gtests/ssl_gtest/tls_protect.h
Normal file
76
security/nss/gtests/ssl_gtest/tls_protect.h
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue