mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 15:27:32 +09:00
Replace NSS with Pale Moon's
This commit is contained in:
parent
ff1e5e48bf
commit
8c2e376f94
2870 changed files with 1762232 additions and 1374220 deletions
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -101,7 +102,7 @@ static const BloomFilterConfig kBloomFilterConfigurations[] = {
|
|||
{16, 9}, // This also uses all of the bits from the hashes.
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BloomFilterConfigurations, BloomFilterTest,
|
||||
::testing::ValuesIn(kBloomFilterConfigurations));
|
||||
INSTANTIATE_TEST_SUITE_P(BloomFilterConfigurations, BloomFilterTest,
|
||||
::testing::ValuesIn(kBloomFilterConfigurations));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -7,9 +8,59 @@
|
|||
#include "libssl_internals.h"
|
||||
|
||||
#include "nss.h"
|
||||
#include "pk11hpke.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pk11priv.h"
|
||||
#include "tls13ech.h"
|
||||
#include "seccomon.h"
|
||||
#include "selfencrypt.h"
|
||||
#include "secmodti.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
SECStatus SSLInt_RemoveServerCertificates(PRFileDesc *fd) {
|
||||
if (!fd) {
|
||||
return SECFailure;
|
||||
}
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PRCList *cursor;
|
||||
while (!PR_CLIST_IS_EMPTY(&ss->serverCerts)) {
|
||||
cursor = PR_LIST_TAIL(&ss->serverCerts);
|
||||
PR_REMOVE_LINK(cursor);
|
||||
ssl_FreeServerCert((sslServerCert *)cursor);
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_SetDCAdvertisedSigSchemes(PRFileDesc *fd,
|
||||
const SSLSignatureScheme *schemes,
|
||||
uint32_t num_sig_schemes) {
|
||||
if (!fd) {
|
||||
return SECFailure;
|
||||
}
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Alloc and copy, libssl will free.
|
||||
SSLSignatureScheme *dc_schemes =
|
||||
PORT_ZNewArray(SSLSignatureScheme, num_sig_schemes);
|
||||
if (!dc_schemes) {
|
||||
return SECFailure;
|
||||
}
|
||||
memcpy(dc_schemes, schemes, sizeof(SSLSignatureScheme) * num_sig_schemes);
|
||||
|
||||
if (ss->xtnData.delegCredSigSchemesAdvertised) {
|
||||
PORT_Free(ss->xtnData.delegCredSigSchemesAdvertised);
|
||||
}
|
||||
ss->xtnData.delegCredSigSchemesAdvertised = dc_schemes;
|
||||
ss->xtnData.numDelegCredSigSchemesAdvertised = num_sig_schemes;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
|
||||
PRBool changeScheme) {
|
||||
|
|
@ -96,6 +147,8 @@ PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
|
|||
return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
|
||||
}
|
||||
|
||||
// Tests should not use this function directly, because the keys may
|
||||
// still be in cache. Instead, use TlsConnectTestBase::ClearServerCache.
|
||||
void SSLInt_ClearSelfEncryptKey() { ssl_ResetSelfEncryptKeys(); }
|
||||
|
||||
sslSelfEncryptKeys *ssl_GetSelfEncryptKeysInt();
|
||||
|
|
@ -303,6 +356,9 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
|
|||
|
||||
SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
|
||||
sslSocket *ss;
|
||||
ssl3CipherSpec *spec;
|
||||
PK11Context *pk11ctxt;
|
||||
const ssl3BulkCipherDef *cipher_def;
|
||||
|
||||
ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
|
|
@ -313,7 +369,43 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
|
|||
return SECFailure;
|
||||
}
|
||||
ssl_GetSpecWriteLock(ss);
|
||||
ss->ssl3.cwSpec->nextSeqNum = to;
|
||||
spec = ss->ssl3.cwSpec;
|
||||
cipher_def = spec->cipherDef;
|
||||
spec->nextSeqNum = to;
|
||||
if (cipher_def->type != type_aead) {
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
/* If we are using aead, we need to advance the counter in the
|
||||
* internal IV generator as well.
|
||||
* This could be in the token or software. */
|
||||
pk11ctxt = spec->cipherContext;
|
||||
/* If counter is in the token, we need to switch it to software,
|
||||
* since we don't have access to the internal state of the token. We do
|
||||
* that by turning on the simulated message interface, then setting up the
|
||||
* software IV generator */
|
||||
if (pk11ctxt->ivCounter == 0) {
|
||||
_PK11_ContextSetAEADSimulation(pk11ctxt);
|
||||
pk11ctxt->ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
|
||||
pk11ctxt->ivMaxCount = PR_UINT64(0xffffffffffffffff);
|
||||
if ((cipher_def->explicit_nonce_size == 0) ||
|
||||
(spec->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {
|
||||
pk11ctxt->ivFixedBits =
|
||||
(pk11ctxt->ivLen - sizeof(sslSequenceNumber)) * BPB;
|
||||
pk11ctxt->ivGen = CKG_GENERATE_COUNTER_XOR;
|
||||
} else {
|
||||
pk11ctxt->ivFixedBits = cipher_def->iv_size * BPB;
|
||||
pk11ctxt->ivGen = CKG_GENERATE_COUNTER;
|
||||
}
|
||||
/* DTLS included the epoch in the fixed portion of the IV */
|
||||
if (IS_DTLS(ss)) {
|
||||
pk11ctxt->ivFixedBits += 2 * BPB;
|
||||
}
|
||||
}
|
||||
/* now we can update the internal counter (either we are already using
|
||||
* the software IV generator, or we just switched to it above */
|
||||
pk11ctxt->ivCounter = to;
|
||||
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
@ -332,6 +424,24 @@ SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra) {
|
|||
return SSLInt_AdvanceWriteSeqNum(fd, to);
|
||||
}
|
||||
|
||||
SECStatus SSLInt_AdvanceDtls13DecryptFailures(PRFileDesc *fd, PRUint64 to) {
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetSpecWriteLock(ss);
|
||||
ssl3CipherSpec *spec = ss->ssl3.crSpec;
|
||||
if (spec->cipherDef->type != type_aead) {
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
spec->deprotectionFailures = to;
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
|
||||
const sslNamedGroupDef *groupDef = ssl_LookupNamedGroup(group);
|
||||
if (!groupDef) return ssl_kea_null;
|
||||
|
|
@ -373,3 +483,19 @@ SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
|
|||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_SetRawEchConfigForRetry(PRFileDesc *fd, const uint8_t *buf,
|
||||
size_t len) {
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
sslEchConfig *cfg = (sslEchConfig *)PR_LIST_HEAD(&ss->echConfigs);
|
||||
SECITEM_FreeItem(&cfg->raw, PR_FALSE);
|
||||
SECITEM_AllocItem(NULL, &cfg->raw, len);
|
||||
PORT_Memcpy(cfg->raw.data, buf, len);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
PRBool SSLInt_IsIp(PRUint8 *s, unsigned int len) { return tls13_IsIp(s, len); }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -35,6 +36,7 @@ PRBool SSLInt_DamageEarlyTrafficSecret(PRFileDesc *fd);
|
|||
SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len);
|
||||
PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType);
|
||||
PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type);
|
||||
SECStatus SSLInt_AdvanceDtls13DecryptFailures(PRFileDesc *fd, PRUint64 to);
|
||||
SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to);
|
||||
SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
|
||||
SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
|
||||
|
|
@ -43,5 +45,12 @@ SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
|
|||
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
|
||||
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
|
||||
PRBool changeScheme);
|
||||
SECStatus SSLInt_SetDCAdvertisedSigSchemes(PRFileDesc *fd,
|
||||
const SSLSignatureScheme *schemes,
|
||||
uint32_t num_sig_schemes);
|
||||
SECStatus SSLInt_RemoveServerCertificates(PRFileDesc *fd);
|
||||
SECStatus SSLInt_SetRawEchConfigForRetry(PRFileDesc *fd, const uint8_t *buf,
|
||||
size_t len);
|
||||
PRBool SSLInt_IsIp(PRUint8 *s, unsigned int len);
|
||||
|
||||
#endif // ndef libssl_internals_h_
|
||||
#endif // ifndef libssl_internals_h_
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ CSRCS = \
|
|||
CPPSRCS = \
|
||||
bloomfilter_unittest.cc \
|
||||
ssl_0rtt_unittest.cc \
|
||||
ssl_aead_unittest.cc \
|
||||
ssl_agent_unittest.cc \
|
||||
ssl_auth_unittest.cc \
|
||||
ssl_cert_ext_unittest.cc \
|
||||
|
|
@ -35,8 +36,8 @@ CPPSRCS = \
|
|||
ssl_hrr_unittest.cc \
|
||||
ssl_keyupdate_unittest.cc \
|
||||
ssl_loopback_unittest.cc \
|
||||
ssl_masking_unittest.cc \
|
||||
ssl_misc_unittest.cc \
|
||||
ssl_primitive_unittest.cc \
|
||||
ssl_record_unittest.cc \
|
||||
ssl_recordsep_unittest.cc \
|
||||
ssl_recordsize_unittest.cc \
|
||||
|
|
@ -55,8 +56,9 @@ CPPSRCS = \
|
|||
tls_hkdf_unittest.cc \
|
||||
tls_filter.cc \
|
||||
tls_protect.cc \
|
||||
tls_psk_unittest.cc \
|
||||
tls_subcerts_unittest.cc \
|
||||
tls_esni_unittest.cc \
|
||||
tls_ech_unittest.cc \
|
||||
$(SSLKEYLOGFILE_FILES) \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
|||
107
security/nss/gtests/ssl_gtest/nss_policy.h
Normal file
107
security/nss/gtests/ssl_gtest/nss_policy.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- 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 nss_policy_h_
|
||||
#define nss_policy_h_
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "secoid.h"
|
||||
#include "nss.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// container class to hold all a temp policy
|
||||
class NssPolicy {
|
||||
public:
|
||||
NssPolicy() : oid_(SEC_OID_UNKNOWN), set_(0), clear_(0) {}
|
||||
NssPolicy(SECOidTag _oid, PRUint32 _set, PRUint32 _clear)
|
||||
: oid_(_oid), set_(_set), clear_(_clear) {}
|
||||
NssPolicy(const NssPolicy &p)
|
||||
: oid_(p.oid_), set_(p.set_), clear_(p.clear_) {}
|
||||
// clone the current policy for this oid
|
||||
NssPolicy(SECOidTag _oid) : oid_(_oid), set_(0), clear_(0) {
|
||||
NSS_GetAlgorithmPolicy(_oid, &set_);
|
||||
clear_ = ~set_;
|
||||
}
|
||||
SECOidTag oid(void) const { return oid_; }
|
||||
PRUint32 set(void) const { return set_; }
|
||||
PRUint32 clear(void) const { return clear_; }
|
||||
operator bool() const { return oid_ != SEC_OID_UNKNOWN; }
|
||||
|
||||
private:
|
||||
SECOidTag oid_;
|
||||
PRUint32 set_;
|
||||
PRUint32 clear_;
|
||||
};
|
||||
|
||||
// container class to hold a temp option
|
||||
class NssOption {
|
||||
public:
|
||||
NssOption() : id_(-1), value_(0) {}
|
||||
NssOption(PRInt32 _id, PRInt32 _value) : id_(_id), value_(_value) {}
|
||||
NssOption(const NssOption &o) : id_(o.id_), value_(o.value_) {}
|
||||
// clone the current option for this id
|
||||
NssOption(PRInt32 _id) : id_(_id), value_(0) { NSS_OptionGet(id_, &value_); }
|
||||
PRInt32 id(void) const { return id_; }
|
||||
PRInt32 value(void) const { return value_; }
|
||||
operator bool() const { return id_ != -1; }
|
||||
|
||||
private:
|
||||
PRInt32 id_;
|
||||
PRInt32 value_;
|
||||
};
|
||||
|
||||
// set the policy indicated in NssPolicy and restor the old policy
|
||||
// when we go out of scope
|
||||
class NssManagePolicy {
|
||||
public:
|
||||
NssManagePolicy(const NssPolicy &p, const NssOption &o)
|
||||
: policy_(p), save_policy_(~(PRUint32)0), option_(o), save_option_(0) {
|
||||
if (p) {
|
||||
(void)NSS_GetAlgorithmPolicy(p.oid(), &save_policy_);
|
||||
(void)NSS_SetAlgorithmPolicy(p.oid(), p.set(), p.clear());
|
||||
}
|
||||
if (o) {
|
||||
(void)NSS_OptionGet(o.id(), &save_option_);
|
||||
(void)NSS_OptionSet(o.id(), o.value());
|
||||
}
|
||||
}
|
||||
~NssManagePolicy() {
|
||||
if (policy_) {
|
||||
(void)NSS_SetAlgorithmPolicy(policy_.oid(), save_policy_, ~save_policy_);
|
||||
}
|
||||
if (option_) {
|
||||
(void)NSS_OptionSet(option_.id(), save_option_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NssPolicy policy_;
|
||||
PRUint32 save_policy_;
|
||||
NssOption option_;
|
||||
PRInt32 save_option_;
|
||||
};
|
||||
|
||||
// wrapping PRFileDesc this way ensures that tests that attempt to access
|
||||
// PRFileDesc always correctly apply
|
||||
// the policy that was bound to that socket with TlsAgent::SetPolicy().
|
||||
class NssManagedFileDesc {
|
||||
public:
|
||||
NssManagedFileDesc(PRFileDesc *fd, const NssPolicy &policy,
|
||||
const NssOption &option)
|
||||
: fd_(fd), managed_policy_(policy, option) {}
|
||||
PRFileDesc *get(void) const { return fd_; }
|
||||
operator PRFileDesc *() const { return fd_; }
|
||||
bool operator==(PRFileDesc *fd) const { return fd_ == fd; }
|
||||
|
||||
private:
|
||||
PRFileDesc *fd_;
|
||||
NssManagePolicy managed_policy_;
|
||||
};
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -274,7 +275,7 @@ TEST_F(SelfEncryptTest128, AESWithMacKeyDecrypt) {
|
|||
SEC_ERROR_INVALID_KEY);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(VariousSizes, SelfEncryptTestVariable,
|
||||
::testing::Values(0, 15, 16, 31, 255, 256, 257));
|
||||
INSTANTIATE_TEST_SUITE_P(VariousSizes, SelfEncryptTestVariable,
|
||||
::testing::Values(0, 15, 16, 31, 255, 256, 257));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -14,6 +15,7 @@ extern "C" {
|
|||
#include "libssl_internals.h"
|
||||
}
|
||||
|
||||
#include "cpputil.h"
|
||||
#include "gtest_utils.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "tls_connect.h"
|
||||
|
|
@ -116,16 +118,12 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
|
|||
};
|
||||
|
||||
protected:
|
||||
void RunTest(bool rollover) {
|
||||
// Run the initial handshake
|
||||
SetupForZeroRtt();
|
||||
|
||||
void RunTest(bool rollover, const ScopedPK11SymKey& epsk) {
|
||||
// Now run a true 0-RTT handshake, but capture the first packet.
|
||||
auto first_packet = std::make_shared<SaveFirstPacket>();
|
||||
client_->SetFilter(first_packet);
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
EXPECT_LT(0U, first_packet->packet().len());
|
||||
|
|
@ -141,6 +139,11 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
|
|||
Reset();
|
||||
server_->StartConnect();
|
||||
server_->Set0RttEnabled(true);
|
||||
server_->SetAntiReplayContext(anti_replay_);
|
||||
if (epsk) {
|
||||
AddPsk(epsk, std::string("foo"), ssl_hash_sha256,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
}
|
||||
|
||||
// Capture the early_data extension, which should not appear.
|
||||
auto early_data_ext =
|
||||
|
|
@ -153,11 +156,41 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
|
|||
server_->Handshake();
|
||||
EXPECT_FALSE(early_data_ext->captured());
|
||||
}
|
||||
|
||||
void RunResPskTest(bool rollover) {
|
||||
// Run the initial handshake
|
||||
SetupForZeroRtt();
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
RunTest(rollover, ScopedPK11SymKey(nullptr));
|
||||
}
|
||||
|
||||
void RunExtPskTest(bool rollover) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
|
||||
const std::vector<uint8_t> kPskDummyVal(16, 0xFF);
|
||||
SECItem psk_item = {siBuffer, toUcharPtr(kPskDummyVal.data()),
|
||||
static_cast<unsigned int>(kPskDummyVal.size())};
|
||||
PK11SymKey* key =
|
||||
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &psk_item, NULL);
|
||||
ASSERT_NE(nullptr, key);
|
||||
ScopedPK11SymKey scoped_psk(key);
|
||||
RolloverAntiReplay();
|
||||
AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
StartConnect();
|
||||
RunTest(rollover, scoped_psk);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(TlsZeroRttReplayTest, ZeroRttReplay) { RunTest(false); }
|
||||
TEST_P(TlsZeroRttReplayTest, ResPskZeroRttReplay) { RunResPskTest(false); }
|
||||
|
||||
TEST_P(TlsZeroRttReplayTest, ZeroRttReplayAfterRollover) { RunTest(true); }
|
||||
TEST_P(TlsZeroRttReplayTest, ExtPskZeroRttReplay) { RunExtPskTest(false); }
|
||||
|
||||
TEST_P(TlsZeroRttReplayTest, ZeroRttReplayAfterRollover) {
|
||||
RunResPskTest(true);
|
||||
}
|
||||
|
||||
// Test that we don't try to send 0-RTT data when the server sent
|
||||
// us a ticket without the 0-RTT flags.
|
||||
|
|
@ -178,6 +211,106 @@ TEST_P(TlsConnectTls13, ZeroRttOptionsSetLate) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
// Make sure that a session ticket sent well after the original handshake
|
||||
// can be used for 0-RTT.
|
||||
// Stream because DTLS doesn't support SSL_SendSessionTicket.
|
||||
TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicket) {
|
||||
// Use a small-ish anti-replay window.
|
||||
ResetAntiReplay(100 * PR_USEC_PER_MSEC);
|
||||
RolloverAntiReplay();
|
||||
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
server_->Set0RttEnabled(true);
|
||||
Connect();
|
||||
CheckKeys();
|
||||
|
||||
// Now move time forward 30s and send a ticket.
|
||||
AdvanceTime(30 * PR_USEC_PER_SEC);
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
|
||||
SendReceive();
|
||||
Reset();
|
||||
StartConnect();
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
// Check that post-handshake authentication with a long RTT doesn't
|
||||
// make things worse.
|
||||
TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicketPha) {
|
||||
// Use a small-ish anti-replay window.
|
||||
ResetAntiReplay(100 * PR_USEC_PER_MSEC);
|
||||
RolloverAntiReplay();
|
||||
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
server_->Set0RttEnabled(true);
|
||||
client_->SetupClientAuth();
|
||||
client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
|
||||
Connect();
|
||||
CheckKeys();
|
||||
|
||||
// Add post-handshake authentication, with some added delays.
|
||||
AdvanceTime(10 * PR_USEC_PER_SEC);
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()));
|
||||
AdvanceTime(10 * PR_USEC_PER_SEC);
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
|
||||
AdvanceTime(10 * PR_USEC_PER_SEC);
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
|
||||
server_->SendData(100);
|
||||
client_->ReadBytes(100);
|
||||
Reset();
|
||||
StartConnect();
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
// Same, but with client authentication on the first connection.
|
||||
TEST_F(TlsConnectStreamTls13, ZeroRttUsingLateTicketClientAuth) {
|
||||
// Use a small-ish anti-replay window.
|
||||
ResetAntiReplay(100 * PR_USEC_PER_MSEC);
|
||||
RolloverAntiReplay();
|
||||
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
Connect();
|
||||
CheckKeys();
|
||||
|
||||
// Now move time forward 30s and send a ticket.
|
||||
AdvanceTime(30 * PR_USEC_PER_SEC);
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
|
||||
SendReceive();
|
||||
Reset();
|
||||
StartConnect();
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ZeroRttServerForgetTicket) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
|
|
@ -476,15 +609,6 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
|
|||
client_->CheckErrorCode(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA);
|
||||
}
|
||||
|
||||
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) {
|
||||
EnsureTlsSetup();
|
||||
const char* big_message = "0123456789abcdef";
|
||||
|
|
@ -1022,9 +1146,38 @@ TEST_P(TlsConnectTls13, ZeroRttDifferentIncompatibleCipher) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
// The client failing to provide EndOfEarlyData results in failure.
|
||||
// After 0-RTT working perfectly, things fall apart later.
|
||||
// The server is unable to detect the change in keys, so it fails decryption.
|
||||
// The client thinks everything has worked until it gets the alert.
|
||||
TEST_F(TlsConnectStreamTls13, SuppressEndOfEarlyDataClientOnly) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
client_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
ExpectAlert(server_, kTlsAlertBadRecordMac);
|
||||
Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
|
||||
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
||||
client_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
|
||||
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_ALERT);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, SuppressEndOfEarlyDataNoZeroRtt) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true);
|
||||
server_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true);
|
||||
Connect();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
INSTANTIATE_TEST_SUITE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -53,7 +54,7 @@ class AeadTest : public ::testing::Test {
|
|||
ASSERT_GE(kMaxSize, ciphertext_len);
|
||||
ASSERT_LT(0U, ciphertext_len);
|
||||
|
||||
uint8_t output[kMaxSize];
|
||||
uint8_t output[kMaxSize] = {0};
|
||||
unsigned int output_len = 0;
|
||||
EXPECT_EQ(SECSuccess, SSL_AeadEncrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
kPlaintext, sizeof(kPlaintext),
|
||||
|
|
@ -180,7 +181,7 @@ TEST_F(AeadTest, AeadNoPointer) {
|
|||
}
|
||||
|
||||
TEST_F(AeadTest, AeadAes128Gcm) {
|
||||
SSLAeadContext *ctxInit;
|
||||
SSLAeadContext *ctxInit = nullptr;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
|
||||
|
|
@ -202,7 +203,7 @@ TEST_F(AeadTest, AeadAes256Gcm) {
|
|||
}
|
||||
|
||||
TEST_F(AeadTest, AeadChaCha20Poly1305) {
|
||||
SSLAeadContext *ctxInit;
|
||||
SSLAeadContext *ctxInit = nullptr;
|
||||
ASSERT_EQ(
|
||||
SECSuccess,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_CHACHA20_POLY1305_SHA256,
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -153,7 +154,6 @@ TEST_F(TlsAgentDgramTestClient, AckWithBogusLengthField) {
|
|||
sizeof(ackBuf), &record, 0);
|
||||
agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
ExpectAlert(kTlsAlertDecodeError);
|
||||
ProcessMessage(record, TlsAgent::STATE_ERROR,
|
||||
SSL_ERROR_RX_MALFORMED_DTLS_ACK);
|
||||
}
|
||||
|
|
@ -170,7 +170,8 @@ TEST_F(TlsAgentDgramTestClient, AckWithNonEvenLength) {
|
|||
// Because we haven't negotiated the version,
|
||||
// ssl3_DecodeError() sends an older (pre-TLS error).
|
||||
ExpectAlert(kTlsAlertIllegalParameter);
|
||||
ProcessMessage(record, TlsAgent::STATE_ERROR, SSL_ERROR_BAD_SERVER);
|
||||
ProcessMessage(record, TlsAgent::STATE_ERROR,
|
||||
SSL_ERROR_RX_MALFORMED_DTLS_ACK);
|
||||
}
|
||||
|
||||
TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
|
||||
|
|
@ -223,15 +224,12 @@ TEST_F(TlsAgentStreamTestServer, Set0RttOptionClientHelloThenRead) {
|
|||
ProcessMessage(buffer, TlsAgent::STATE_ERROR, SSL_ERROR_BAD_MAC_READ);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AgentTests, TlsAgentTest,
|
||||
::testing::Combine(TlsAgentTestBase::kTlsRolesAll,
|
||||
TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(ClientTests, TlsAgentTestClient,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(ClientTests13, TlsAgentTestClient13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
INSTANTIATE_TEST_SUITE_P(ClientTests13, TlsAgentTestClient13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -151,17 +152,17 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
|
|||
SendReceive();
|
||||
|
||||
// Check that we used the right cipher suite, auth type and kea type.
|
||||
uint16_t actual;
|
||||
uint16_t actual = TLS_NULL_WITH_NULL_NULL;
|
||||
EXPECT_TRUE(client_->cipher_suite(&actual));
|
||||
EXPECT_EQ(cipher_suite_, actual);
|
||||
EXPECT_TRUE(server_->cipher_suite(&actual));
|
||||
EXPECT_EQ(cipher_suite_, actual);
|
||||
SSLAuthType auth;
|
||||
SSLAuthType auth = ssl_auth_size;
|
||||
EXPECT_TRUE(client_->auth_type(&auth));
|
||||
EXPECT_EQ(auth_type_, auth);
|
||||
EXPECT_TRUE(server_->auth_type(&auth));
|
||||
EXPECT_EQ(auth_type_, auth);
|
||||
SSLKEAType kea;
|
||||
SSLKEAType kea = ssl_kea_size;
|
||||
EXPECT_TRUE(client_->kea_type(&kea));
|
||||
EXPECT_EQ(kea_type_, kea);
|
||||
EXPECT_TRUE(server_->kea_type(&kea));
|
||||
|
|
@ -242,7 +243,7 @@ TEST_P(TlsCipherSuiteTest, SingleCipherSuite) {
|
|||
|
||||
TEST_P(TlsCipherSuiteTest, ResumeCipherSuite) {
|
||||
if (SkipIfCipherSuiteIsDSA()) {
|
||||
return; // Tickets don't work with DSA (bug 1174677).
|
||||
GTEST_SKIP() << "Tickets not supported with DSA (bug 1174677).";
|
||||
}
|
||||
|
||||
SetupCertificate(); // This is only needed once.
|
||||
|
|
@ -262,6 +263,7 @@ TEST_P(TlsCipherSuiteTest, ResumeCipherSuite) {
|
|||
TEST_P(TlsCipherSuiteTest, ReadLimit) {
|
||||
SetupCertificate();
|
||||
EnableSingleCipher();
|
||||
TlsSendCipherSpecCapturer capturer(client_);
|
||||
ConnectAndCheckCipherSuite();
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
uint64_t last = last_safe_write();
|
||||
|
|
@ -294,9 +296,31 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) {
|
|||
} else {
|
||||
epoch = 0;
|
||||
}
|
||||
TlsAgentTestBase::MakeRecord(variant_, ssl_ct_application_data, version_,
|
||||
payload, sizeof(payload), &record,
|
||||
(epoch << 48) | record_limit());
|
||||
|
||||
uint64_t seqno = (epoch << 48) | record_limit();
|
||||
|
||||
// DTLS 1.3 masks the sequence number
|
||||
if (variant_ == ssl_variant_datagram &&
|
||||
version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
auto spec = capturer.spec(1);
|
||||
ASSERT_NE(nullptr, spec.get());
|
||||
ASSERT_EQ(3, spec->epoch());
|
||||
|
||||
DataBuffer pt, ct;
|
||||
uint8_t dtls13_ctype = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
|
||||
kCtDtlsCiphertextLengthPresent;
|
||||
TlsRecordHeader hdr(variant_, version_, dtls13_ctype, seqno);
|
||||
pt.Assign(payload, sizeof(payload));
|
||||
TlsRecordHeader out_hdr;
|
||||
spec->Protect(hdr, pt, &ct, &out_hdr);
|
||||
|
||||
auto rv = out_hdr.Write(&record, 0, ct);
|
||||
EXPECT_EQ(out_hdr.header_length() + ct.len(), rv);
|
||||
} else {
|
||||
TlsAgentTestBase::MakeRecord(variant_, ssl_ct_application_data, version_,
|
||||
payload, sizeof(payload), &record, seqno);
|
||||
}
|
||||
|
||||
client_->SendDirect(record);
|
||||
server_->ExpectReadWriteError();
|
||||
server_->ReadBytes();
|
||||
|
|
@ -306,7 +330,7 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) {
|
|||
TEST_P(TlsCipherSuiteTest, WriteLimit) {
|
||||
// This asserts in TLS 1.3 because we expect an automatic update.
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
SetupCertificate();
|
||||
EnableSingleCipher();
|
||||
|
|
@ -324,7 +348,7 @@ TEST_P(TlsCipherSuiteTest, WriteLimit) {
|
|||
static const uint16_t k##name##CiphersArr[] = {__VA_ARGS__}; \
|
||||
static const ::testing::internal::ParamGenerator<uint16_t> \
|
||||
k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr); \
|
||||
INSTANTIATE_TEST_CASE_P( \
|
||||
INSTANTIATE_TEST_SUITE_P( \
|
||||
CipherSuite##name, TlsCipherSuiteTest, \
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariants##modes, \
|
||||
TlsConnectTestBase::kTls##versions, k##name##Ciphers, \
|
||||
|
|
@ -501,7 +525,7 @@ static const SecStatusParams kSecStatusTestValuesArr[] = {
|
|||
"AES-256-GCM", 256},
|
||||
{SSL_LIBRARY_VERSION_TLS_1_2, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
"ChaCha20-Poly1305", 256}};
|
||||
INSTANTIATE_TEST_CASE_P(TestSecurityStatus, SecurityStatusTest,
|
||||
::testing::ValuesIn(kSecStatusTestValuesArr));
|
||||
INSTANTIATE_TEST_SUITE_P(TestSecurityStatus, SecurityStatusTest,
|
||||
::testing::ValuesIn(kSecStatusTestValuesArr));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -22,23 +23,23 @@ static void IncrementCounterArg(void *arg) {
|
|||
}
|
||||
}
|
||||
|
||||
PRBool NoopExtensionWriter(PRFileDesc *fd, SSLHandshakeType message,
|
||||
PRUint8 *data, unsigned int *len,
|
||||
unsigned int maxLen, void *arg) {
|
||||
static PRBool NoopExtensionWriter(PRFileDesc *fd, SSLHandshakeType message,
|
||||
PRUint8 *data, unsigned int *len,
|
||||
unsigned int maxLen, void *arg) {
|
||||
IncrementCounterArg(arg);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool EmptyExtensionWriter(PRFileDesc *fd, SSLHandshakeType message,
|
||||
PRUint8 *data, unsigned int *len,
|
||||
unsigned int maxLen, void *arg) {
|
||||
static PRBool EmptyExtensionWriter(PRFileDesc *fd, SSLHandshakeType message,
|
||||
PRUint8 *data, unsigned int *len,
|
||||
unsigned int maxLen, void *arg) {
|
||||
IncrementCounterArg(arg);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
SECStatus NoopExtensionHandler(PRFileDesc *fd, SSLHandshakeType message,
|
||||
const PRUint8 *data, unsigned int len,
|
||||
SSLAlertDescription *alert, void *arg) {
|
||||
static SECStatus NoopExtensionHandler(PRFileDesc *fd, SSLHandshakeType message,
|
||||
const PRUint8 *data, unsigned int len,
|
||||
SSLAlertDescription *alert, void *arg) {
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
|
@ -66,8 +67,8 @@ static const uint16_t kManyExtensions[] = {
|
|||
ssl_tls13_certificate_authorities_xtn,
|
||||
ssl_next_proto_nego_xtn,
|
||||
ssl_renegotiation_info_xtn,
|
||||
ssl_tls13_short_header_xtn,
|
||||
ssl_record_size_limit_xtn,
|
||||
ssl_tls13_encrypted_client_hello_xtn,
|
||||
1,
|
||||
0xffff};
|
||||
// The list here includes all extensions we expect to use (SSL_MAX_EXTENSIONS),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -27,8 +28,7 @@ extern FILE* ssl_keylog_iob;
|
|||
TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLDEBUGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
Connect();
|
||||
|
|
@ -40,8 +40,7 @@ TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
|
|||
TEST_P(TlsConnectGeneric, DebugEnvKeylogFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLKEYLOGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
Connect();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -345,11 +346,11 @@ static const bool kTrueFalseArr[] = {true, false};
|
|||
static ::testing::internal::ParamGenerator<bool> kTrueFalse =
|
||||
::testing::ValuesIn(kTrueFalseArr);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DamageYStream, TlsDamageDHYTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12, kAllY, kTrueFalse));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DamageYDatagram, TlsDamageDHYTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12, kAllY, kTrueFalse));
|
||||
|
|
@ -642,37 +643,6 @@ TEST_P(TlsConnectGenericPre13, InvalidDERSignatureFfdhe) {
|
|||
client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
||||
}
|
||||
|
||||
// Replace SignatureAndHashAlgorithm of a SKE.
|
||||
class DHEServerKEXSigAlgReplacer : public TlsHandshakeFilter {
|
||||
public:
|
||||
DHEServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent>& server,
|
||||
SSLSignatureScheme sig_scheme)
|
||||
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
||||
sig_scheme_(sig_scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
|
||||
uint32_t len;
|
||||
uint32_t idx = 0;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
output->Write(idx, sig_scheme_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
SSLSignatureScheme sig_scheme_;
|
||||
};
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectInconsistentSigAlgDHE) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
|
|
@ -753,6 +723,34 @@ TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicyDhe) {
|
|||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectPre12, ConnectSigAlgDisabledWeakGroupByOption3072DhePre12) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
// explicitly enable the weak groups
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_EnableWeakDHEPrimeGroup(client_->ssl_fd(), PR_TRUE));
|
||||
server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072);
|
||||
Connect();
|
||||
client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectPre12, ConnectSigAlgDisabledWeakGroupByOption2048DhePre12) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
// explicitly enable the weak groups
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_EnableWeakDHEPrimeGroup(client_->ssl_fd(), PR_TRUE));
|
||||
server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 2048);
|
||||
Connect();
|
||||
client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_2048, 2048);
|
||||
server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_2048, 2048);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectPre12, ConnectSigAlgDisabledByPolicyDhePre12) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
|
|
@ -777,4 +775,28 @@ TEST_P(TlsConnectPre12, ConnectSigAlgDisabledByPolicyDhePre12) {
|
|||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgDisablePreferredGroupByOption3072Dhe) {
|
||||
EnableOnlyDheCiphers();
|
||||
static const SSLDHEGroupType dhe_groups[] = {
|
||||
ssl_ff_dhe_2048_group, // first in the lists is the preferred group
|
||||
ssl_ff_dhe_3072_group};
|
||||
|
||||
server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072);
|
||||
EXPECT_EQ(SECSuccess, SSL_DHEGroupPrefSet(server_->ssl_fd(), &dhe_groups[0],
|
||||
PR_ARRAY_SIZE(dhe_groups)));
|
||||
Connect();
|
||||
// our option size should override the preferred group
|
||||
client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgDisableGroupByOption3072Dhe) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
server_->SetNssOption(NSS_DH_MIN_KEY_SIZE, 3072);
|
||||
Connect();
|
||||
client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -618,55 +619,6 @@ TEST_P(TlsDropDatagram13, ReorderServerEE) {
|
|||
|
||||
// The client sends an out of order non-handshake message
|
||||
// but with the handshake key.
|
||||
class TlsSendCipherSpecCapturer {
|
||||
public:
|
||||
TlsSendCipherSpecCapturer(const std::shared_ptr<TlsAgent>& agent)
|
||||
: agent_(agent), send_cipher_specs_() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_SecretCallback(agent_->ssl_fd(), SecretCallback, this));
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsCipherSpec> spec(size_t i) {
|
||||
if (i >= send_cipher_specs_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return send_cipher_specs_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
static void SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLSecretDirection dir, PK11SymKey* secret,
|
||||
void* arg) {
|
||||
auto self = static_cast<TlsSendCipherSpecCapturer*>(arg);
|
||||
std::cerr << self->agent_->role_str() << ": capture " << dir
|
||||
<< " secret for epoch " << epoch << std::endl;
|
||||
|
||||
if (dir == ssl_secret_read) {
|
||||
return;
|
||||
}
|
||||
|
||||
SSLPreliminaryChannelInfo preinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetPreliminaryChannelInfo(self->agent_->ssl_fd(), &preinfo,
|
||||
sizeof(preinfo)));
|
||||
EXPECT_EQ(sizeof(preinfo), preinfo.length);
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
|
||||
|
||||
SSLCipherSuiteInfo cipherinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetCipherSuiteInfo(preinfo.cipherSuite, &cipherinfo,
|
||||
sizeof(cipherinfo)));
|
||||
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);
|
||||
|
||||
auto spec = std::make_shared<TlsCipherSpec>(true, epoch);
|
||||
EXPECT_TRUE(spec->SetKeys(&cipherinfo, secret));
|
||||
self->send_cipher_specs_.push_back(spec);
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent> agent_;
|
||||
std::vector<std::shared_ptr<TlsCipherSpec>> send_cipher_specs_;
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
|
||||
StartConnect();
|
||||
// Capturing secrets means that we can't use decrypting filters on the client.
|
||||
|
|
@ -683,8 +635,10 @@ TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
|
|||
auto spec = capturer.spec(0);
|
||||
ASSERT_NE(nullptr, spec.get());
|
||||
ASSERT_EQ(2, spec->epoch());
|
||||
ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002,
|
||||
ssl_ct_application_data,
|
||||
|
||||
uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
|
||||
kCtDtlsCiphertextLengthPresent;
|
||||
ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002, dtls13_ct,
|
||||
DataBuffer(buf, sizeof(buf))));
|
||||
|
||||
// Now have the server consume the bogus message.
|
||||
|
|
@ -843,7 +797,7 @@ static void GetCipherAndLimit(uint16_t version, uint16_t* cipher,
|
|||
// a reasonable amount of time.
|
||||
*cipher = TLS_CHACHA20_POLY1305_SHA256;
|
||||
// Assume that we are starting with an expected sequence number of 0.
|
||||
*limit = (1ULL << 29) - 1;
|
||||
*limit = (1ULL << 15) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -865,14 +819,14 @@ TEST_P(TlsConnectDatagram, MissLotsOfPackets) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
// Send a sequence number of 0xfffffffd and it should be interpreted as that
|
||||
// Send a sequence number of 0xfffd and it should be interpreted as that
|
||||
// (and not -3 or UINT64_MAX - 2).
|
||||
TEST_F(TlsConnectDatagram13, UnderflowSequenceNumber) {
|
||||
Connect();
|
||||
// This is only valid if short headers are disabled.
|
||||
client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_FALSE);
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), (1ULL << 30) - 3));
|
||||
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), (1ULL << 16) - 3));
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
|
|
@ -917,9 +871,13 @@ class TlsReplaceFirstRecordWithJunk : public TlsRecordFilter {
|
|||
return KEEP;
|
||||
}
|
||||
replaced_ = true;
|
||||
TlsRecordHeader out_header(header.variant(), header.version(),
|
||||
ssl_ct_application_data,
|
||||
header.sequence_number());
|
||||
|
||||
uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
|
||||
kCtDtlsCiphertextLengthPresent;
|
||||
TlsRecordHeader out_header(
|
||||
header.variant(), header.version(),
|
||||
is_dtls13() ? dtls13_ct : ssl_ct_application_data,
|
||||
header.sequence_number());
|
||||
|
||||
static const uint8_t junk[] = {1, 2, 3, 4};
|
||||
*offset = out_header.Write(output, *offset, DataBuffer(junk, sizeof(junk)));
|
||||
|
|
@ -942,15 +900,15 @@ TEST_P(TlsConnectDatagram, ReplaceFirstClientRecordWithApplicationData) {
|
|||
Connect();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Datagram12Plus, TlsConnectDatagram12Plus,
|
||||
TlsConnectTestBase::kTlsV12Plus);
|
||||
INSTANTIATE_TEST_CASE_P(DatagramPre13, TlsConnectDatagramPre13,
|
||||
TlsConnectTestBase::kTlsV11V12);
|
||||
INSTANTIATE_TEST_CASE_P(DatagramDrop13, TlsDropDatagram13,
|
||||
::testing::Values(true, false));
|
||||
INSTANTIATE_TEST_CASE_P(DatagramReorder13, TlsReorderDatagram13,
|
||||
::testing::Values(true, false));
|
||||
INSTANTIATE_TEST_CASE_P(DatagramFragment13, TlsFragmentationAndRecoveryTest,
|
||||
::testing::Values(true, false));
|
||||
INSTANTIATE_TEST_SUITE_P(Datagram12Plus, TlsConnectDatagram12Plus,
|
||||
TlsConnectTestBase::kTlsV12Plus);
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramPre13, TlsConnectDatagramPre13,
|
||||
TlsConnectTestBase::kTlsV11V12);
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramDrop13, TlsDropDatagram13,
|
||||
::testing::Values(true, false));
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramReorder13, TlsReorderDatagram13,
|
||||
::testing::Values(true, false));
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramFragment13, TlsFragmentationAndRecoveryTest,
|
||||
::testing::Values(true, false));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -619,31 +620,6 @@ TEST_P(TlsConnectGenericPre13, ConnectUnsupportedPointFormat) {
|
|||
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
|
||||
}
|
||||
|
||||
// Replace SignatureAndHashAlgorithm of a SKE.
|
||||
class ECCServerKEXSigAlgReplacer : public TlsHandshakeFilter {
|
||||
public:
|
||||
ECCServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent> &server,
|
||||
SSLSignatureScheme sig_scheme)
|
||||
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
||||
sig_scheme_(sig_scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
||||
const DataBuffer &input,
|
||||
DataBuffer *output) {
|
||||
*output = input;
|
||||
|
||||
uint32_t point_len;
|
||||
EXPECT_TRUE(output->Read(3, 1, &point_len));
|
||||
output->Write(4 + point_len, sig_scheme_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
SSLSignatureScheme sig_scheme_;
|
||||
};
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectUnsupportedSigAlg) {
|
||||
EnsureTlsSetup();
|
||||
client_->DisableAllCiphers();
|
||||
|
|
@ -739,14 +715,14 @@ TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicy) {
|
|||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
INSTANTIATE_TEST_SUITE_P(KeyExchangeTest, TlsKeyExchangeTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
INSTANTIATE_TEST_SUITE_P(KeyExchangeTest, TlsKeyExchangeTest13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -147,4 +148,41 @@ TEST_P(TlsConnectTls13, EarlyExporter) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, EarlyExporterExternalPsk) {
|
||||
RolloverAntiReplay();
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(!!slot);
|
||||
ScopedPK11SymKey scoped_psk(
|
||||
PK11_KeyGen(slot.get(), CKM_HKDF_KEY_GEN, nullptr, 16, nullptr));
|
||||
AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
StartConnect();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
client_->Handshake(); // Send ClientHello.
|
||||
uint8_t client_value[10] = {0};
|
||||
RegularExporterShouldFail(client_.get(), nullptr, 0);
|
||||
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_ExportEarlyKeyingMaterial(
|
||||
client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
|
||||
kExporterContext, sizeof(kExporterContext), client_value,
|
||||
sizeof(client_value)));
|
||||
|
||||
server_->SetSniCallback(RegularExporterShouldFail);
|
||||
server_->Handshake(); // Handle ClientHello.
|
||||
uint8_t server_value[10] = {0};
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_ExportEarlyKeyingMaterial(
|
||||
server_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
|
||||
kExporterContext, sizeof(kExporterContext), server_value,
|
||||
sizeof(server_value)));
|
||||
EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value)));
|
||||
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -19,6 +20,45 @@
|
|||
|
||||
namespace nss_test {
|
||||
|
||||
class Dtls13LegacyCookieInjector : public TlsHandshakeFilter {
|
||||
public:
|
||||
Dtls13LegacyCookieInjector(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeClientHello}) {}
|
||||
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
const uint8_t cookie_bytes[] = {0x03, 0x0A, 0x0B, 0x0C};
|
||||
uint32_t offset = 2 /* version */ + 32 /* random */;
|
||||
|
||||
if (agent()->variant() != ssl_variant_datagram) {
|
||||
ADD_FAILURE();
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
if (header.handshake_type() != ssl_hs_client_hello) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
DataBuffer cookie(cookie_bytes, sizeof(cookie_bytes));
|
||||
*output = input;
|
||||
|
||||
// Add the SID length (if any) to locate the cookie.
|
||||
uint32_t sid_len = 0;
|
||||
if (!output->Read(offset, 1, &sid_len)) {
|
||||
ADD_FAILURE();
|
||||
return KEEP;
|
||||
}
|
||||
offset += 1 + sid_len;
|
||||
output->Splice(cookie, offset, 1);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
DataBuffer cookie_;
|
||||
};
|
||||
|
||||
class TlsExtensionTruncator : public TlsExtensionFilter {
|
||||
public:
|
||||
TlsExtensionTruncator(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
|
||||
|
|
@ -43,63 +83,6 @@ class TlsExtensionTruncator : public TlsExtensionFilter {
|
|||
size_t length_;
|
||||
};
|
||||
|
||||
class TlsExtensionAppender : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsExtensionAppender(const std::shared_ptr<TlsAgent>& a,
|
||||
uint8_t handshake_type, uint16_t ext, DataBuffer& data)
|
||||
: TlsHandshakeFilter(a, {handshake_type}), extension_(ext), data_(data) {}
|
||||
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
TlsParser parser(input);
|
||||
if (!TlsExtensionFilter::FindExtensions(&parser, header)) {
|
||||
return KEEP;
|
||||
}
|
||||
*output = input;
|
||||
|
||||
// Increase the length of the extensions block.
|
||||
if (!UpdateLength(output, parser.consumed(), 2)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
// Extensions in Certificate are nested twice. Increase the size of the
|
||||
// certificate list.
|
||||
if (header.handshake_type() == kTlsHandshakeCertificate) {
|
||||
TlsParser p2(input);
|
||||
if (!p2.SkipVariable(1)) {
|
||||
ADD_FAILURE();
|
||||
return KEEP;
|
||||
}
|
||||
if (!UpdateLength(output, p2.consumed(), 3)) {
|
||||
return KEEP;
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset = output->len();
|
||||
offset = output->Write(offset, extension_, 2);
|
||||
WriteVariable(output, offset, data_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
bool UpdateLength(DataBuffer* output, size_t offset, size_t size) {
|
||||
uint32_t len;
|
||||
if (!output->Read(offset, size, &len)) {
|
||||
ADD_FAILURE();
|
||||
return false;
|
||||
}
|
||||
|
||||
len += 4 + data_.len();
|
||||
output->Write(offset, len, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint16_t extension_;
|
||||
const DataBuffer data_;
|
||||
};
|
||||
|
||||
class TlsExtensionTestBase : public TlsConnectTestBase {
|
||||
protected:
|
||||
TlsExtensionTestBase(SSLProtocolVariant variant, uint16_t version)
|
||||
|
|
@ -188,8 +171,29 @@ class TlsExtensionTest13
|
|||
}
|
||||
|
||||
void ConnectWithReplacementVersionList(uint16_t version) {
|
||||
DataBuffer versions_buf;
|
||||
// Convert the version encoding for DTLS, if needed.
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
switch (version) {
|
||||
case SSL_LIBRARY_VERSION_TLS_1_3:
|
||||
#ifdef DTLS_1_3_DRAFT_VERSION
|
||||
version = 0x7f00 | DTLS_1_3_DRAFT_VERSION;
|
||||
#else
|
||||
version = SSL_LIBRARY_VERSION_DTLS_1_3_WIRE;
|
||||
#endif
|
||||
break;
|
||||
case SSL_LIBRARY_VERSION_TLS_1_2:
|
||||
version = SSL_LIBRARY_VERSION_DTLS_1_2_WIRE;
|
||||
break;
|
||||
case SSL_LIBRARY_VERSION_TLS_1_1:
|
||||
/* TLS_1_1 maps to DTLS_1_0, see sslproto.h. */
|
||||
version = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
|
||||
break;
|
||||
default:
|
||||
PORT_Assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
DataBuffer versions_buf;
|
||||
size_t index = versions_buf.Write(0, 2, 1);
|
||||
versions_buf.Write(index, version, 2);
|
||||
MakeTlsFilter<TlsExtensionReplacer>(
|
||||
|
|
@ -322,6 +326,28 @@ TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
|
|||
server_->EnableAlpn(server_alpn, sizeof(server_alpn));
|
||||
|
||||
ClientHelloErrorTest(nullptr, kTlsAlertNoApplicationProtocol);
|
||||
client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTestGeneric, AlpnDisabledServer) {
|
||||
const uint8_t client_alpn[] = {0x01, 0x61};
|
||||
client_->EnableAlpn(client_alpn, sizeof(client_alpn));
|
||||
server_->EnableAlpn(nullptr, 0);
|
||||
|
||||
ClientHelloErrorTest(nullptr, kTlsAlertUnsupportedExtension);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, AlpnDisabled) {
|
||||
server_->EnableAlpn(nullptr, 0);
|
||||
Connect();
|
||||
|
||||
SSLNextProtoState state;
|
||||
uint8_t buf[255] = {0};
|
||||
unsigned int buf_len = 3;
|
||||
EXPECT_EQ(SECSuccess, SSL_GetNextProto(client_->ssl_fd(), &state, buf,
|
||||
&buf_len, sizeof(buf)));
|
||||
EXPECT_EQ(SSL_NEXT_PROTO_NO_SUPPORT, state);
|
||||
EXPECT_EQ(0U, buf_len);
|
||||
}
|
||||
|
||||
// Many of these tests fail in TLS 1.3 because the extension is encrypted, which
|
||||
|
|
@ -405,7 +431,10 @@ TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
|
|||
}
|
||||
|
||||
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
|
||||
const uint8_t val[] = {0x00, 0x02, 0x04, 0x01, 0x00}; // sha-256, rsa
|
||||
// make sure the test uses an algorithm that is legal for
|
||||
// tls 1.3 (or tls 1.3 will throw a handshake failure alert
|
||||
// instead of a decode error alert)
|
||||
const uint8_t val[] = {0x00, 0x02, 0x08, 0x09, 0x00}; // sha-256, rsa-pss-pss
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
||||
client_, ssl_signature_algorithms_xtn, extension));
|
||||
|
|
@ -569,6 +598,22 @@ TEST_P(TlsExtensionTestPre13, SupportedPointsTrailingData) {
|
|||
client_, ssl_ec_point_formats_xtn, extension));
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTestPre13, SupportedPointsCompressed) {
|
||||
const uint8_t val[] = {0x01, 0x02};
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
||||
client_, ssl_ec_point_formats_xtn, extension),
|
||||
kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTestPre13, SupportedPointsUndefined) {
|
||||
const uint8_t val[] = {0x01, 0xAA};
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
||||
client_, ssl_ec_point_formats_xtn, extension),
|
||||
kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTestPre13, RenegotiationInfoBadLength) {
|
||||
const uint8_t val[] = {0x99};
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
|
|
@ -887,6 +932,26 @@ TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderValue) {
|
|||
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
||||
}
|
||||
|
||||
// Do the same with an External PSK.
|
||||
TEST_P(TlsConnectTls13, TestTls13PskInvalidBinderValue) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(!!slot);
|
||||
ScopedPK11SymKey key(
|
||||
PK11_KeyGen(slot.get(), CKM_HKDF_KEY_GEN, nullptr, 16, nullptr));
|
||||
ASSERT_TRUE(!!key);
|
||||
AddPsk(key, std::string("foo"), ssl_hash_sha256);
|
||||
StartConnect();
|
||||
ASSERT_TRUE(client_->MaybeSetResumptionToken());
|
||||
|
||||
MakeTlsFilter<TlsPreSharedKeyReplacer>(
|
||||
client_, [](TlsPreSharedKeyReplacer* r) {
|
||||
r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
|
||||
});
|
||||
ConnectExpectAlert(server_, kTlsAlertDecryptError);
|
||||
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
||||
}
|
||||
|
||||
// Extend the binder by one.
|
||||
TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderLength) {
|
||||
SetupForResume();
|
||||
|
|
@ -1077,13 +1142,34 @@ TEST_P(TlsExtensionTest13, HrrThenRemoveSupportedGroups) {
|
|||
}
|
||||
|
||||
TEST_P(TlsExtensionTest13, EmptyVersionList) {
|
||||
static const uint8_t ext[] = {0x00, 0x00};
|
||||
ConnectWithBogusVersionList(ext, sizeof(ext));
|
||||
static const uint8_t kExt[] = {0x00, 0x00};
|
||||
ConnectWithBogusVersionList(kExt, sizeof(kExt));
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTest13, OddVersionList) {
|
||||
static const uint8_t ext[] = {0x00, 0x01, 0x00};
|
||||
ConnectWithBogusVersionList(ext, sizeof(ext));
|
||||
static const uint8_t kExt[] = {0x00, 0x01, 0x00};
|
||||
ConnectWithBogusVersionList(kExt, sizeof(kExt));
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTest13, SignatureAlgorithmsInvalidTls13) {
|
||||
// testing the case where we ask for a invalid parameter for tls13
|
||||
const uint8_t val[] = {0x00, 0x02, 0x04, 0x01}; // sha-256, rsa-pkcs1
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
|
||||
client_, ssl_signature_algorithms_xtn, extension),
|
||||
kTlsAlertHandshakeFailure);
|
||||
}
|
||||
|
||||
// Use the stream version number for TLS 1.3 (0x0304) in DTLS.
|
||||
TEST_F(TlsConnectDatagram13, TlsVersionInDtls) {
|
||||
static const uint8_t kExt[] = {0x02, 0x03, 0x04};
|
||||
|
||||
DataBuffer versions_buf(kExt, sizeof(kExt));
|
||||
MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_tls13_supported_versions_xtn,
|
||||
versions_buf);
|
||||
ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
|
||||
client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
|
||||
}
|
||||
|
||||
// TODO: this only tests extensions in server messages. The client can extend
|
||||
|
|
@ -1246,6 +1332,7 @@ TEST_P(TlsDisallowedUnadvertisedExtensionTest13,
|
|||
|
||||
TEST_P(TlsConnectStream, IncludePadding) {
|
||||
EnsureTlsSetup();
|
||||
SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE); // Don't GREASE
|
||||
|
||||
// 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.
|
||||
|
|
@ -1262,48 +1349,157 @@ TEST_P(TlsConnectStream, IncludePadding) {
|
|||
EXPECT_TRUE(capture->captured());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
TEST_F(TlsConnectDatagram13, Dtls13RejectLegacyCookie) {
|
||||
EnsureTlsSetup();
|
||||
MakeTlsFilter<Dtls13LegacyCookieInjector>(client_);
|
||||
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
||||
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, ClientHelloExtensionPermutation) {
|
||||
EnsureTlsSetup();
|
||||
PR_ASSERT(SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_CH_EXTENSION_PERMUTATION,
|
||||
PR_TRUE) == SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ClientHelloExtensionPermutationWithPSK) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
SECItem psk_item;
|
||||
psk_item.type = siBuffer;
|
||||
psk_item.len = sizeof(kPskDummyVal_);
|
||||
psk_item.data = const_cast<uint8_t*>(kPskDummyVal_);
|
||||
PK11SymKey* key =
|
||||
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &psk_item, NULL);
|
||||
|
||||
ScopedPK11SymKey scoped_psk_(key);
|
||||
const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
|
||||
const SSLHashType kPskHash_ = ssl_hash_sha384;
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
|
||||
PR_ASSERT(SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_CH_EXTENSION_PERMUTATION,
|
||||
PR_TRUE) == SECSuccess);
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
/* This test checks that the ClientHello extension order is actually permuted
|
||||
* if ss->opt.chXtnPermutation is set. It is asserted that at least one out of
|
||||
* 10 extension orders differs from the others.
|
||||
*
|
||||
* This is a probabilistic test: The default TLS 1.3 ClientHello contains 8
|
||||
* extensions, leading to a 1/8! probability for any extension order and the
|
||||
* same probability for two drawn extension orders to coincide.
|
||||
* Since all sequences are compared against each other this leads to a false
|
||||
* positive rate of (1/8!)^(n^2-n).
|
||||
* To achieve a spurious failure rate << 1/2^64, we compare n=10 drawn orders.
|
||||
*
|
||||
* This test assures that randomisation is happening but does not check quality
|
||||
* of the used Fisher-Yates shuffle. */
|
||||
TEST_F(TlsConnectStreamTls13,
|
||||
ClientHelloExtensionPermutationProbabilisticTest) {
|
||||
std::vector<std::vector<uint16_t>> orders;
|
||||
|
||||
/* Capture the extension order of 10 ClientHello messages. */
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
client_->StartConnect();
|
||||
/* Enable ClientHello extension permutation. */
|
||||
ASSERT_TRUE(SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_CH_EXTENSION_PERMUTATION,
|
||||
PR_TRUE) == SECSuccess);
|
||||
/* Capture extension order filter. */
|
||||
auto filter = MakeTlsFilter<TlsExtensionOrderCapture>(
|
||||
client_, kTlsHandshakeClientHello);
|
||||
/* Send ClientHello. */
|
||||
client_->Handshake();
|
||||
/* Remember extension order. */
|
||||
orders.push_back(filter->order);
|
||||
/* Reset client / server state. */
|
||||
Reset();
|
||||
}
|
||||
|
||||
/* Check for extension order inequality. */
|
||||
size_t inequal = 0;
|
||||
for (auto& outerOrders : orders) {
|
||||
for (auto& innerOrders : orders) {
|
||||
if (outerOrders != innerOrders) {
|
||||
inequal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(inequal >= 1);
|
||||
}
|
||||
|
||||
// The certificate_authorities xtn can be included in a ClientHello [RFC 8446,
|
||||
// Section 4.2]
|
||||
TEST_F(TlsConnectStreamTls13, ClientHelloCertAuthXtnToleration) {
|
||||
EnsureTlsSetup();
|
||||
uint8_t bodyBuf[3] = {0x00, 0x01, 0xff};
|
||||
DataBuffer body(bodyBuf, sizeof(bodyBuf));
|
||||
auto ch = MakeTlsFilter<TlsExtensionAppender>(
|
||||
client_, kTlsHandshakeClientHello, ssl_tls13_certificate_authorities_xtn,
|
||||
body);
|
||||
// The Connection will fail because the added extension isn't in the client's
|
||||
// transcript not because the extension is unsupported (Bug 1815167).
|
||||
server_->ExpectSendAlert(bad_record_mac);
|
||||
client_->ExpectSendAlert(bad_record_mac);
|
||||
ConnectExpectFail();
|
||||
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
||||
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExtensionStream, TlsExtensionTestGeneric,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExtensionDatagram, TlsExtensionTestGeneric,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
INSTANTIATE_TEST_SUITE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionTls12, TlsExtensionTest12,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12));
|
||||
INSTANTIATE_TEST_SUITE_P(ExtensionTls12, TlsExtensionTest12,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12Plus));
|
||||
INSTANTIATE_TEST_SUITE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12Plus));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExtensionPre13Stream, TlsExtensionTestPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_SUITE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionTls13, TlsExtensionTest13,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
INSTANTIATE_TEST_SUITE_P(ExtensionTls13, TlsExtensionTest13,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BogusExtensionStream, TlsBogusExtensionTestPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BogusExtensionDatagram, TlsBogusExtensionTestPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BogusExtension13, TlsBogusExtensionTest13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
INSTANTIATE_TEST_SUITE_P(BogusExtension13, TlsBogusExtensionTest13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DisallowedExtension13, TlsDisallowedExtensionTest13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ FUZZ_P(TlsFuzzTest, DeterministicExporter) {
|
|||
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
DisableECDHEServerKeyReuse();
|
||||
|
||||
// Reset the RNG state.
|
||||
EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
|
||||
|
|
@ -71,7 +70,6 @@ FUZZ_P(TlsFuzzTest, DeterministicExporter) {
|
|||
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
DisableECDHEServerKeyReuse();
|
||||
|
||||
// Reset the RNG state.
|
||||
EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0));
|
||||
|
|
@ -97,7 +95,6 @@ FUZZ_P(TlsFuzzTest, DeterministicTranscript) {
|
|||
for (size_t i = 0; i < 5; i++) {
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
DisableECDHEServerKeyReuse();
|
||||
|
||||
DataBuffer buffer;
|
||||
MakeTlsFilter<TlsConversationRecorder>(client_, buffer);
|
||||
|
|
@ -244,11 +241,11 @@ FUZZ_P(TlsFuzzTest, UnencryptedSessionTickets) {
|
|||
client_->CheckCipherSuite(static_cast<uint16_t>(suite));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FuzzStream, TlsFuzzTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FuzzDatagram, TlsFuzzTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -24,21 +25,6 @@ class GatherV2ClientHelloTest : public TlsConnectTestBase {
|
|||
}
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
|
@ -140,4 +126,31 @@ TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader) {
|
|||
ConnectExpectMalformedClientHello(buffer);
|
||||
}
|
||||
|
||||
/* Test correct gather buffer clearing/freeing and (re-)allocation.
|
||||
*
|
||||
* Freeing and (re-)allocation of the gather buffers after reception of single
|
||||
* records is only done in DEBUG builds. Normally they are created and
|
||||
* destroyed with the SSL socket.
|
||||
*
|
||||
* TLS 1.0 record splitting leads to implicit complete read of the data.
|
||||
*
|
||||
* The NSS DTLS impelmentation does not allow partial reads
|
||||
* (see sslsecur.c, line 535-543). */
|
||||
TEST_P(TlsConnectStream, GatherBufferPartialReadTest) {
|
||||
EnsureTlsSetup();
|
||||
Connect();
|
||||
|
||||
client_->SendData(1000);
|
||||
|
||||
if (version_ > SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
for (unsigned i = 1; i <= 20; i++) {
|
||||
server_->ReadBytes(50);
|
||||
ASSERT_EQ(server_->received_bytes(), 50U * i);
|
||||
}
|
||||
} else {
|
||||
server_->ReadBytes(50);
|
||||
ASSERT_EQ(server_->received_bytes(), 1000U);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
'libssl_internals.c',
|
||||
'selfencrypt_unittest.cc',
|
||||
'ssl_0rtt_unittest.cc',
|
||||
'ssl_aead_unittest.cc',
|
||||
'ssl_agent_unittest.cc',
|
||||
'ssl_auth_unittest.cc',
|
||||
'ssl_cert_ext_unittest.cc',
|
||||
|
|
@ -36,8 +37,8 @@
|
|||
'ssl_hrr_unittest.cc',
|
||||
'ssl_keyupdate_unittest.cc',
|
||||
'ssl_loopback_unittest.cc',
|
||||
'ssl_masking_unittest.cc',
|
||||
'ssl_misc_unittest.cc',
|
||||
'ssl_primitive_unittest.cc',
|
||||
'ssl_record_unittest.cc',
|
||||
'ssl_recordsep_unittest.cc',
|
||||
'ssl_recordsize_unittest.cc',
|
||||
|
|
@ -54,9 +55,11 @@
|
|||
'tls_connect.cc',
|
||||
'tls_filter.cc',
|
||||
'tls_hkdf_unittest.cc',
|
||||
'tls_esni_unittest.cc',
|
||||
'tls_ech_unittest.cc',
|
||||
'tls_protect.cc',
|
||||
'tls_subcerts_unittest.cc'
|
||||
'tls_psk_unittest.cc',
|
||||
'tls_subcerts_unittest.cc',
|
||||
'tls_grease_unittest.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
|
|
@ -103,6 +106,18 @@
|
|||
'NSS_ALLOW_SSLKEYLOGFILE',
|
||||
],
|
||||
}],
|
||||
# ssl_gtest fuzz defines should only be determined by the 'fuzz_tls'
|
||||
# flag (so as to match lib/ssl). If gtest.gypi added the define due
|
||||
# to '--fuzz' only, remove it.
|
||||
['fuzz_tls==1', {
|
||||
'defines': [
|
||||
'UNSAFE_FUZZER_MODE',
|
||||
],
|
||||
}, {
|
||||
'defines!': [
|
||||
'UNSAFE_FUZZER_MODE',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -958,6 +959,34 @@ TEST_P(TlsKeyExchange13, ConnectEcdhePreferenceMismatchHrr) {
|
|||
CheckKEXDetails(client_groups, expectedShares, ssl_grp_ec_curve25519);
|
||||
}
|
||||
|
||||
TEST_P(TlsKeyExchange13, SecondClientHelloPreambleMatches) {
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
|
||||
ConfigureSelfEncrypt();
|
||||
static const std::vector<SSLNamedGroup> client_groups = {
|
||||
ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
||||
static const std::vector<SSLNamedGroup> server_groups = {
|
||||
ssl_grp_ec_curve25519};
|
||||
client_->ConfigNamedGroups(client_groups);
|
||||
server_->ConfigNamedGroups(server_groups);
|
||||
|
||||
auto ch1 = MakeTlsFilter<ClientHelloPreambleCapture>(client_);
|
||||
StartConnect();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
|
||||
MakeNewServer();
|
||||
auto ch2 = MakeTlsFilter<ClientHelloPreambleCapture>(client_);
|
||||
Handshake();
|
||||
|
||||
EXPECT_TRUE(ch1->captured());
|
||||
EXPECT_TRUE(ch2->captured());
|
||||
EXPECT_EQ(ch1->contents(), ch2->contents());
|
||||
}
|
||||
|
||||
// This should work, but not use HRR because the key share for x25519 was
|
||||
// pre-generated by the client.
|
||||
TEST_P(TlsKeyExchange13, ConnectEcdhePreferenceMismatchHrrExtraShares) {
|
||||
|
|
@ -1107,9 +1136,10 @@ class HelloRetryRequestAgentTest : public TlsAgentTestClient {
|
|||
|
||||
hrr_data.Allocate(len + 6);
|
||||
size_t i = 0;
|
||||
i = hrr_data.Write(i, variant_ == ssl_variant_datagram
|
||||
? SSL_LIBRARY_VERSION_DTLS_1_2_WIRE
|
||||
: SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
i = hrr_data.Write(i,
|
||||
variant_ == ssl_variant_datagram
|
||||
? SSL_LIBRARY_VERSION_DTLS_1_2_WIRE
|
||||
: SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
2);
|
||||
i = hrr_data.Write(i, ssl_hello_retry_random,
|
||||
sizeof(ssl_hello_retry_random));
|
||||
|
|
@ -1121,9 +1151,10 @@ class HelloRetryRequestAgentTest : public TlsAgentTestClient {
|
|||
// Now the supported version.
|
||||
i = hrr_data.Write(i, ssl_tls13_supported_versions_xtn, 2);
|
||||
i = hrr_data.Write(i, 2, 2);
|
||||
i = hrr_data.Write(i, (variant_ == ssl_variant_datagram)
|
||||
? (0x7f00 | DTLS_1_3_DRAFT_VERSION)
|
||||
: SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
i = hrr_data.Write(i,
|
||||
(variant_ == ssl_variant_datagram)
|
||||
? (0x7f00 | DTLS_1_3_DRAFT_VERSION)
|
||||
: SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
2);
|
||||
if (len) {
|
||||
hrr_data.Write(i, body, len);
|
||||
|
|
@ -1320,13 +1351,14 @@ TEST_F(TlsConnectStreamTls13, HrrThenTls12SupportedVersions) {
|
|||
client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(HelloRetryRequestAgentTests, HelloRetryRequestAgentTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
INSTANTIATE_TEST_SUITE_P(HelloRetryRequestAgentTests,
|
||||
HelloRetryRequestAgentTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(HelloRetryRequestKeyExchangeTests, TlsKeyExchange13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
INSTANTIATE_TEST_SUITE_P(HelloRetryRequestKeyExchangeTests, TlsKeyExchange13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -112,16 +113,16 @@ TEST_P(KeyLogFileTest, KeyLogFile) {
|
|||
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileDTLS12, KeyLogFileTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileTLS12, KeyLogFileTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileTLS13, KeyLogFileTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
|
|
@ -145,16 +146,16 @@ TEST_P(KeyLogFileUnsetTest, KeyLogFile) {
|
|||
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileDTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KeyLogFileTLS13, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -389,7 +390,7 @@ TEST_P(TlsConnectDatagram, ShortRead) {
|
|||
TEST_P(TlsConnectStream, ShortRead) {
|
||||
// This test behaves oddly with TLS 1.0 because of 1/n+1 splitting,
|
||||
// so skip in that case.
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) return;
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) GTEST_SKIP();
|
||||
|
||||
Connect();
|
||||
server_->SendData(50, 50);
|
||||
|
|
@ -727,74 +728,74 @@ TEST_P(TlsConnectGeneric, ShutdownOneSideThenCloseTcp) {
|
|||
EXPECT_EQ(PR_NOT_CONNECTED_ERROR, PR_GetError());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericStream, TlsConnectGeneric,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericDatagram, TlsConnectGeneric,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(StreamOnly, TlsConnectStream,
|
||||
TlsConnectTestBase::kTlsVAll);
|
||||
INSTANTIATE_TEST_CASE_P(DatagramOnly, TlsConnectDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
INSTANTIATE_TEST_CASE_P(DatagramHolddown, TlsHolddownTest,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
INSTANTIATE_TEST_SUITE_P(StreamOnly, TlsConnectStream,
|
||||
TlsConnectTestBase::kTlsVAll);
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramOnly, TlsConnectDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
INSTANTIATE_TEST_SUITE_P(DatagramHolddown, TlsHolddownTest,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Pre12Stream, TlsConnectPre12,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10V11));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Pre12Datagram, TlsConnectPre12,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Version12Only, TlsConnectTls12,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
INSTANTIATE_TEST_SUITE_P(Version12Only, TlsConnectTls12,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(Version13Only, TlsConnectTls13,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
INSTANTIATE_TEST_SUITE_P(Version13Only, TlsConnectTls13,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
#endif
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Pre13Stream, TlsConnectGenericPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Pre13Datagram, TlsConnectGenericPre13,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(Pre13StreamOnly, TlsConnectStreamPre13,
|
||||
TlsConnectTestBase::kTlsV10ToV12);
|
||||
INSTANTIATE_TEST_SUITE_P(Pre13StreamOnly, TlsConnectStreamPre13,
|
||||
TlsConnectTestBase::kTlsV10ToV12);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Version12Plus, TlsConnectTls12Plus,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12Plus));
|
||||
INSTANTIATE_TEST_SUITE_P(Version12Plus, TlsConnectTls12Plus,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12Plus));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericStream, TlsConnectGenericResumption,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll,
|
||||
::testing::Values(true, false)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericDatagram, TlsConnectGenericResumption,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus,
|
||||
::testing::Values(true, false)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericStream, TlsConnectGenericResumptionToken,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GenericDatagram, TlsConnectGenericResumptionToken,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(GenericDatagram, TlsConnectTls13ResumptionToken,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
INSTANTIATE_TEST_SUITE_P(GenericDatagram, TlsConnectTls13ResumptionToken,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
350
security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc
Normal file
350
security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
/* -*- 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 <memory>
|
||||
|
||||
#include "keyhi.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslexp.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "scoped_ptrs_ssl.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// From tls_hkdf_unittest.cc:
|
||||
extern size_t GetHashLength(SSLHashType ht);
|
||||
|
||||
const std::string kLabel = "sn";
|
||||
|
||||
class MaskingTest : public ::testing::Test {
|
||||
public:
|
||||
MaskingTest() : slot_(PK11_GetInternalSlot()) {}
|
||||
|
||||
void InitSecret(SSLHashType hash_type) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
PK11SymKey *s = PK11_KeyGen(slot_.get(), CKM_GENERIC_SECRET_KEY_GEN,
|
||||
nullptr, AES_128_KEY_LENGTH, nullptr);
|
||||
ASSERT_NE(nullptr, s);
|
||||
secret_.reset(s);
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
InitSecret(ssl_hash_sha256);
|
||||
PORT_SetError(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
ScopedPK11SymKey secret_;
|
||||
ScopedPK11SlotInfo slot_;
|
||||
// Should have 4B ctr, 12B nonce for ChaCha, or >=16B ciphertext for AES.
|
||||
// Use the same default size for mask output.
|
||||
static const int kSampleSize = 16;
|
||||
static const int kMaskSize = 16;
|
||||
void CreateMask(PRUint16 ciphersuite, SSLProtocolVariant variant,
|
||||
std::string label, const std::vector<uint8_t> &sample,
|
||||
std::vector<uint8_t> *out_mask) {
|
||||
ASSERT_NE(nullptr, out_mask);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite, variant,
|
||||
secret_.get(), label.c_str(), label.size(), &ctx_init));
|
||||
ASSERT_NE(nullptr, ctx_init);
|
||||
ScopedSSLMaskingContext ctx(ctx_init);
|
||||
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateMask(ctx.get(), sample.data(), sample.size(),
|
||||
out_mask->data(), out_mask->size()));
|
||||
bool all_zeros = std::all_of(out_mask->begin(), out_mask->end(),
|
||||
[](uint8_t v) { return v == 0; });
|
||||
|
||||
// If out_mask is short, |all_zeros| will be (expectedly) true often enough
|
||||
// to fail tests.
|
||||
// In this case, just retry to make sure we're not outputting zeros
|
||||
// continuously.
|
||||
if (all_zeros && out_mask->size() < 3) {
|
||||
unsigned int tries = 2;
|
||||
std::vector<uint8_t> tmp_sample = sample;
|
||||
std::vector<uint8_t> tmp_mask(out_mask->size());
|
||||
while (tries--) {
|
||||
tmp_sample.data()[0]++; // Tweak something to get a new mask.
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateMask(ctx.get(), tmp_sample.data(),
|
||||
tmp_sample.size(), tmp_mask.data(),
|
||||
tmp_mask.size()));
|
||||
bool retry_zero = std::all_of(tmp_mask.begin(), tmp_mask.end(),
|
||||
[](uint8_t v) { return v == 0; });
|
||||
if (!retry_zero) {
|
||||
all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(all_zeros);
|
||||
}
|
||||
};
|
||||
|
||||
class SuiteTest : public MaskingTest,
|
||||
public ::testing::WithParamInterface<uint16_t> {
|
||||
public:
|
||||
SuiteTest() : ciphersuite_(GetParam()) {}
|
||||
void CreateMask(std::string label, const std::vector<uint8_t> &sample,
|
||||
std::vector<uint8_t> *out_mask) {
|
||||
MaskingTest::CreateMask(ciphersuite_, ssl_variant_datagram, label, sample,
|
||||
out_mask);
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint16_t ciphersuite_;
|
||||
};
|
||||
|
||||
class VariantTest : public MaskingTest,
|
||||
public ::testing::WithParamInterface<SSLProtocolVariant> {
|
||||
public:
|
||||
VariantTest() : variant_(GetParam()) {}
|
||||
void CreateMask(uint16_t ciphersuite, std::string label,
|
||||
const std::vector<uint8_t> &sample,
|
||||
std::vector<uint8_t> *out_mask) {
|
||||
MaskingTest::CreateMask(ciphersuite, variant_, label, sample, out_mask);
|
||||
}
|
||||
|
||||
protected:
|
||||
const SSLProtocolVariant variant_;
|
||||
};
|
||||
|
||||
class VariantSuiteTest : public MaskingTest,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<SSLProtocolVariant, uint16_t>> {
|
||||
public:
|
||||
VariantSuiteTest()
|
||||
: variant_(std::get<0>(GetParam())),
|
||||
ciphersuite_(std::get<1>(GetParam())) {}
|
||||
void CreateMask(std::string label, const std::vector<uint8_t> &sample,
|
||||
std::vector<uint8_t> *out_mask) {
|
||||
MaskingTest::CreateMask(ciphersuite_, variant_, label, sample, out_mask);
|
||||
}
|
||||
|
||||
protected:
|
||||
const SSLProtocolVariant variant_;
|
||||
const uint16_t ciphersuite_;
|
||||
};
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskContextNoLabel) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(kMaskSize);
|
||||
CreateMask(std::string(""), sample, &mask);
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskNoSample) {
|
||||
std::vector<uint8_t> mask(kMaskSize);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_, variant_,
|
||||
secret_.get(), kLabel.c_str(), kLabel.size(), &ctx_init));
|
||||
ASSERT_NE(nullptr, ctx_init);
|
||||
ScopedSSLMaskingContext ctx(ctx_init);
|
||||
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_CreateMask(ctx.get(), nullptr, 0, mask.data(), mask.size()));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
|
||||
EXPECT_EQ(SECFailure, SSL_CreateMask(ctx.get(), nullptr, mask.size(),
|
||||
mask.data(), mask.size()));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskShortSample) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(kMaskSize);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_, variant_,
|
||||
secret_.get(), kLabel.c_str(), kLabel.size(), &ctx_init));
|
||||
ASSERT_NE(nullptr, ctx_init);
|
||||
ScopedSSLMaskingContext ctx(ctx_init);
|
||||
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_CreateMask(ctx.get(), sample.data(), sample.size() - 1,
|
||||
mask.data(), mask.size()));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskContextUnsupportedMech) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(kMaskSize);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||
variant_, secret_.get(), nullptr, 0, &ctx_init));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(nullptr, ctx_init);
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskContextUnsupportedVersion) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(kMaskSize);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECFailure, SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_2, ciphersuite_, variant_,
|
||||
secret_.get(), nullptr, 0, &ctx_init));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(nullptr, ctx_init);
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskMaxLength) {
|
||||
uint32_t max_mask_len = kMaskSize;
|
||||
if (ciphersuite_ == TLS_CHACHA20_POLY1305_SHA256) {
|
||||
// Internal limitation for ChaCha20 masks.
|
||||
max_mask_len = 128;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(max_mask_len + 1);
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_, variant_,
|
||||
secret_.get(), kLabel.c_str(), kLabel.size(), &ctx_init));
|
||||
ASSERT_NE(nullptr, ctx_init);
|
||||
ScopedSSLMaskingContext ctx(ctx_init);
|
||||
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateMask(ctx.get(), sample.data(), sample.size(),
|
||||
mask.data(), mask.size() - 1));
|
||||
EXPECT_EQ(SECFailure, SSL_CreateMask(ctx.get(), sample.data(), sample.size(),
|
||||
mask.data(), mask.size()));
|
||||
EXPECT_EQ(SEC_ERROR_OUTPUT_LEN, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskMinLength) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask(1); // Don't pass a null
|
||||
|
||||
SSLMaskingContext *ctx_init = nullptr;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_, variant_,
|
||||
secret_.get(), kLabel.c_str(), kLabel.size(), &ctx_init));
|
||||
ASSERT_NE(nullptr, ctx_init);
|
||||
ScopedSSLMaskingContext ctx(ctx_init);
|
||||
EXPECT_EQ(SECFailure, SSL_CreateMask(ctx.get(), sample.data(), sample.size(),
|
||||
mask.data(), 0));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateMask(ctx.get(), sample.data(), sample.size(),
|
||||
mask.data(), 1));
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskRotateLabel) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask1(kMaskSize);
|
||||
std::vector<uint8_t> mask2(kMaskSize);
|
||||
EXPECT_EQ(SECSuccess, PK11_GenerateRandomOnSlot(slot_.get(), sample.data(),
|
||||
sample.size()));
|
||||
|
||||
CreateMask(kLabel, sample, &mask1);
|
||||
CreateMask(std::string("sn1"), sample, &mask2);
|
||||
EXPECT_FALSE(mask1 == mask2);
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskRotateSample) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask1(kMaskSize);
|
||||
std::vector<uint8_t> mask2(kMaskSize);
|
||||
|
||||
EXPECT_EQ(SECSuccess, PK11_GenerateRandomOnSlot(slot_.get(), sample.data(),
|
||||
sample.size()));
|
||||
CreateMask(kLabel, sample, &mask1);
|
||||
|
||||
EXPECT_EQ(SECSuccess, PK11_GenerateRandomOnSlot(slot_.get(), sample.data(),
|
||||
sample.size()));
|
||||
CreateMask(kLabel, sample, &mask2);
|
||||
EXPECT_FALSE(mask1 == mask2);
|
||||
}
|
||||
|
||||
TEST_P(VariantSuiteTest, MaskRederive) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> mask1(kMaskSize);
|
||||
std::vector<uint8_t> mask2(kMaskSize);
|
||||
|
||||
SECStatus rv =
|
||||
PK11_GenerateRandomOnSlot(slot_.get(), sample.data(), sample.size());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// Check that re-using inputs with a new context produces the same mask.
|
||||
CreateMask(kLabel, sample, &mask1);
|
||||
CreateMask(kLabel, sample, &mask2);
|
||||
EXPECT_TRUE(mask1 == mask2);
|
||||
}
|
||||
|
||||
TEST_P(SuiteTest, MaskTlsVariantKeySeparation) {
|
||||
std::vector<uint8_t> sample(kSampleSize);
|
||||
std::vector<uint8_t> tls_mask(kMaskSize);
|
||||
std::vector<uint8_t> dtls_mask(kMaskSize);
|
||||
SSLMaskingContext *stream_ctx_init = nullptr;
|
||||
SSLMaskingContext *datagram_ctx_init = nullptr;
|
||||
|
||||
// Init
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_,
|
||||
ssl_variant_stream, secret_.get(), kLabel.c_str(),
|
||||
kLabel.size(), &stream_ctx_init));
|
||||
ASSERT_NE(nullptr, stream_ctx_init);
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ciphersuite_,
|
||||
ssl_variant_datagram, secret_.get(), kLabel.c_str(),
|
||||
kLabel.size(), &datagram_ctx_init));
|
||||
ASSERT_NE(nullptr, datagram_ctx_init);
|
||||
ScopedSSLMaskingContext tls_ctx(stream_ctx_init);
|
||||
ScopedSSLMaskingContext dtls_ctx(datagram_ctx_init);
|
||||
|
||||
// Derive
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateMask(tls_ctx.get(), sample.data(), sample.size(),
|
||||
tls_mask.data(), tls_mask.size()));
|
||||
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_CreateMask(dtls_ctx.get(), sample.data(), sample.size(),
|
||||
dtls_mask.data(), dtls_mask.size()));
|
||||
EXPECT_NE(tls_mask, dtls_mask);
|
||||
}
|
||||
|
||||
TEST_P(VariantTest, MaskChaChaRederiveOddSizes) {
|
||||
// Non-block-aligned.
|
||||
std::vector<uint8_t> sample(27);
|
||||
std::vector<uint8_t> mask1(26);
|
||||
std::vector<uint8_t> mask2(25);
|
||||
EXPECT_EQ(SECSuccess, PK11_GenerateRandomOnSlot(slot_.get(), sample.data(),
|
||||
sample.size()));
|
||||
CreateMask(TLS_CHACHA20_POLY1305_SHA256, kLabel, sample, &mask1);
|
||||
CreateMask(TLS_CHACHA20_POLY1305_SHA256, kLabel, sample, &mask2);
|
||||
mask1.pop_back();
|
||||
EXPECT_TRUE(mask1 == mask2);
|
||||
}
|
||||
|
||||
static const uint16_t kMaskingCiphersuites[] = {TLS_CHACHA20_POLY1305_SHA256,
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_AES_256_GCM_SHA384};
|
||||
::testing::internal::ParamGenerator<uint16_t> kMaskingCiphersuiteParams =
|
||||
::testing::ValuesIn(kMaskingCiphersuites);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GenericMasking, SuiteTest, kMaskingCiphersuiteParams);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GenericMasking, VariantTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GenericMasking, VariantSuiteTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
kMaskingCiphersuiteParams));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -184,12 +185,42 @@ TEST_F(TlsConnectStreamTls13, TooLargeRecord) {
|
|||
class ShortHeaderChecker : public PacketFilter {
|
||||
public:
|
||||
PacketFilter::Action Filter(const DataBuffer& input, DataBuffer* output) {
|
||||
// The first octet should be 0b001xxxxx.
|
||||
EXPECT_EQ(1, input.data()[0] >> 5);
|
||||
// The first octet should be 0b001000xx.
|
||||
EXPECT_EQ(kCtDtlsCiphertext, (input.data()[0] & ~0x3));
|
||||
return KEEP;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectDatagram13, AeadLimit) {
|
||||
Connect();
|
||||
EXPECT_EQ(SECSuccess, SSLInt_AdvanceDtls13DecryptFailures(server_->ssl_fd(),
|
||||
(1ULL << 36) - 2));
|
||||
SendReceive(50);
|
||||
|
||||
// Expect this to increment the counter. We should still be able to talk.
|
||||
client_->SetFilter(std::make_shared<TlsRecordLastByteDamager>(client_));
|
||||
client_->SendData(10);
|
||||
server_->ReadBytes(10);
|
||||
client_->ClearFilter();
|
||||
client_->ResetSentBytes(50);
|
||||
SendReceive(60);
|
||||
|
||||
// Expect alert when the limit is hit.
|
||||
client_->SetFilter(std::make_shared<TlsRecordLastByteDamager>(client_));
|
||||
client_->SendData(10);
|
||||
ExpectAlert(server_, kTlsAlertBadRecordMac);
|
||||
|
||||
// Check the error on both endpoints.
|
||||
uint8_t buf[10];
|
||||
PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_EQ(-1, rv);
|
||||
EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, PORT_GetError());
|
||||
|
||||
rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_EQ(-1, rv);
|
||||
EXPECT_EQ(SSL_ERROR_BAD_MAC_ALERT, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectDatagram13, ShortHeadersClient) {
|
||||
Connect();
|
||||
client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_TRUE);
|
||||
|
|
@ -204,6 +235,35 @@ TEST_F(TlsConnectDatagram13, ShortHeadersServer) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
// Send a DTLSCiphertext header with a 2B sequence number, and no length.
|
||||
TEST_F(TlsConnectDatagram13, DtlsAlternateShortHeader) {
|
||||
StartConnect();
|
||||
TlsSendCipherSpecCapturer capturer(client_);
|
||||
Connect();
|
||||
SendReceive(50);
|
||||
|
||||
uint8_t buf[] = {0x32, 0x33, 0x34};
|
||||
auto spec = capturer.spec(1);
|
||||
ASSERT_NE(nullptr, spec.get());
|
||||
ASSERT_EQ(3, spec->epoch());
|
||||
|
||||
uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno;
|
||||
TlsRecordHeader header(variant_, SSL_LIBRARY_VERSION_TLS_1_3, dtls13_ct,
|
||||
0x0003000000000001);
|
||||
TlsRecordHeader out_header(header);
|
||||
DataBuffer msg(buf, sizeof(buf));
|
||||
msg.Write(msg.len(), ssl_ct_application_data, 1);
|
||||
DataBuffer ciphertext;
|
||||
EXPECT_TRUE(spec->Protect(header, msg, &ciphertext, &out_header));
|
||||
|
||||
DataBuffer record;
|
||||
auto rv = out_header.Write(&record, 0, ciphertext);
|
||||
EXPECT_EQ(out_header.header_length() + ciphertext.len(), rv);
|
||||
client_->SendDirect(record);
|
||||
|
||||
server_->ReadBytes(3);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, UnencryptedFinishedMessage) {
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
|
@ -247,6 +307,520 @@ auto kContentSizes = ::testing::ValuesIn(kContentSizesArr);
|
|||
const static bool kTrueFalseArr[] = {true, false};
|
||||
auto kTrueFalse = ::testing::ValuesIn(kTrueFalseArr);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TlsPadding, TlsPaddingTest,
|
||||
::testing::Combine(kContentSizes, kTrueFalse));
|
||||
} // namespace nss_test
|
||||
INSTANTIATE_TEST_SUITE_P(TlsPadding, TlsPaddingTest,
|
||||
::testing::Combine(kContentSizes, kTrueFalse));
|
||||
|
||||
/* Filter to modify record header and content */
|
||||
class Tls13RecordModifier : public TlsRecordFilter {
|
||||
public:
|
||||
Tls13RecordModifier(const std::shared_ptr<TlsAgent>& a,
|
||||
uint8_t contentType = ssl_ct_handshake, size_t size = 0,
|
||||
size_t padding = 0)
|
||||
: TlsRecordFilter(a),
|
||||
contentType_(contentType),
|
||||
size_(size),
|
||||
padding_(padding) {}
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& record, size_t* offset,
|
||||
DataBuffer* output) override {
|
||||
if (!header.is_protected()) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
uint16_t protection_epoch;
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
TlsRecordHeader out_header;
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext, &out_header)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
if (decrypting() && inner_content_type != ssl_ct_application_data) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool ok = Protect(spec(protection_epoch), out_header, contentType_,
|
||||
DataBuffer(size_), &ciphertext, &out_header, padding_);
|
||||
EXPECT_TRUE(ok);
|
||||
if (!ok) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
*offset = out_header.Write(output, *offset, ciphertext);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t contentType_;
|
||||
size_t size_;
|
||||
size_t padding_;
|
||||
};
|
||||
|
||||
/* Zero-length InnerPlaintext test class
|
||||
*
|
||||
* Parameter = Tuple of:
|
||||
* - TLS variant (datagram/stream)
|
||||
* - Content type to be set in zero-length inner plaintext record
|
||||
* - Padding of record plaintext
|
||||
*/
|
||||
class ZeroLengthInnerPlaintextSetupTls13
|
||||
: public TlsConnectTestBase,
|
||||
public testing::WithParamInterface<
|
||||
std::tuple<SSLProtocolVariant, SSLContentType, size_t>> {
|
||||
public:
|
||||
ZeroLengthInnerPlaintextSetupTls13()
|
||||
: TlsConnectTestBase(std::get<0>(GetParam()),
|
||||
SSL_LIBRARY_VERSION_TLS_1_3),
|
||||
contentType_(std::get<1>(GetParam())),
|
||||
padding_(std::get<2>(GetParam())){};
|
||||
|
||||
protected:
|
||||
SSLContentType contentType_;
|
||||
size_t padding_;
|
||||
};
|
||||
|
||||
/* Test correct rejection of TLS 1.3 encrypted handshake/alert records with
|
||||
* zero-length inner plaintext content length with and without padding.
|
||||
*
|
||||
* Implementations MUST NOT send Handshake and Alert records that have a
|
||||
* zero-length TLSInnerPlaintext.content; if such a message is received,
|
||||
* the receiving implementation MUST terminate the connection with an
|
||||
* "unexpected_message" alert [RFC8446, Section 5.4]. */
|
||||
TEST_P(ZeroLengthInnerPlaintextSetupTls13, ZeroLengthInnerPlaintextRun) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Filter modifies record to be zero-length
|
||||
auto filter =
|
||||
MakeTlsFilter<Tls13RecordModifier>(client_, contentType_, 0, padding_);
|
||||
filter->EnableDecryption();
|
||||
filter->Disable();
|
||||
|
||||
Connect();
|
||||
|
||||
filter->Enable();
|
||||
|
||||
// Record will be overwritten
|
||||
client_->SendData(0xf);
|
||||
|
||||
// Receive corrupt record
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
// 22B = 16B MAC + 1B innerContentType + 5B Header
|
||||
server_->ReadBytes(22);
|
||||
// Process alert at peer
|
||||
client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
|
||||
client_->Handshake();
|
||||
} else { /* DTLS */
|
||||
size_t received = server_->received_bytes();
|
||||
// 22B = 16B MAC + 1B innerContentType + 5B Header
|
||||
server_->ReadBytes(22);
|
||||
// Check that no bytes were received => packet was dropped
|
||||
ASSERT_EQ(received, server_->received_bytes());
|
||||
// Check that we are still connected / not in error state
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
}
|
||||
}
|
||||
|
||||
// Test for TLS and DTLS
|
||||
const SSLProtocolVariant kZeroLengthInnerPlaintextVariants[] = {
|
||||
ssl_variant_stream, ssl_variant_datagram};
|
||||
// Test for handshake and alert fragments
|
||||
const SSLContentType kZeroLengthInnerPlaintextContentTypes[] = {
|
||||
ssl_ct_handshake, ssl_ct_alert};
|
||||
// Test with 0,1 and 100 octets of padding
|
||||
const size_t kZeroLengthInnerPlaintextPadding[] = {0, 1, 100};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ZeroLengthInnerPlaintextTest, ZeroLengthInnerPlaintextSetupTls13,
|
||||
testing::Combine(testing::ValuesIn(kZeroLengthInnerPlaintextVariants),
|
||||
testing::ValuesIn(kZeroLengthInnerPlaintextContentTypes),
|
||||
testing::ValuesIn(kZeroLengthInnerPlaintextPadding)),
|
||||
[](const testing::TestParamInfo<
|
||||
ZeroLengthInnerPlaintextSetupTls13::ParamType>& inf) {
|
||||
return std::string(std::get<0>(inf.param) == ssl_variant_stream
|
||||
? "Tls"
|
||||
: "Dtls") +
|
||||
"ZeroLengthInnerPlaintext" +
|
||||
(std::get<1>(inf.param) == ssl_ct_handshake ? "Handshake"
|
||||
: "Alert") +
|
||||
(std::get<2>(inf.param)
|
||||
? "Padding" + std::to_string(std::get<2>(inf.param)) + "B"
|
||||
: "") +
|
||||
"Test";
|
||||
});
|
||||
|
||||
/* Zero-length record test class
|
||||
*
|
||||
* Parameter = Tuple of:
|
||||
* - TLS variant (datagram/stream)
|
||||
* - TLS version
|
||||
* - Content type to be set in zero-length record
|
||||
*/
|
||||
class ZeroLengthRecordSetup
|
||||
: public TlsConnectTestBase,
|
||||
public testing::WithParamInterface<
|
||||
std::tuple<SSLProtocolVariant, uint16_t, SSLContentType>> {
|
||||
public:
|
||||
ZeroLengthRecordSetup()
|
||||
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())),
|
||||
variant_(std::get<0>(GetParam())),
|
||||
contentType_(std::get<2>(GetParam())){};
|
||||
|
||||
void createZeroLengthRecord(DataBuffer& buffer, unsigned epoch = 0,
|
||||
unsigned seqn = 0) {
|
||||
size_t idx = 0;
|
||||
// Set header content type
|
||||
idx = buffer.Write(idx, contentType_, 1);
|
||||
// The record version is not checked during record layer handling
|
||||
idx = buffer.Write(idx, 0xDEAD, 2);
|
||||
// DTLS (version always < TLS 1.3)
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
// Set epoch (Should be 0 before handshake)
|
||||
idx = buffer.Write(idx, 0U, 2);
|
||||
// Set 6B sequence number (0 if send as first message)
|
||||
idx = buffer.Write(idx, 0U, 2);
|
||||
idx = buffer.Write(idx, 0U, 4);
|
||||
}
|
||||
// Set fragment to be of zero-length
|
||||
(void)buffer.Write(idx, 0U, 2);
|
||||
}
|
||||
|
||||
protected:
|
||||
SSLProtocolVariant variant_;
|
||||
SSLContentType contentType_;
|
||||
};
|
||||
|
||||
/* Test handling of zero-length (ciphertext/fragment) records before handshake.
|
||||
*
|
||||
* This is only tested before the first handshake, since after it all of these
|
||||
* messages are expected to be encrypted which is impossible for a content
|
||||
* length of zero, always leading to a bad record mac. For TLS 1.3 only
|
||||
* records of application data content type is legal after the handshake.
|
||||
*
|
||||
* Handshake records of length zero will be ignored in the record layer since
|
||||
* the RFC does only specify that such records MUST NOT be sent but it does not
|
||||
* state that an alert should be sent or the connection be terminated
|
||||
* [RFC8446, Section 5.1].
|
||||
*
|
||||
* Even though only handshake messages are handled (ignored) in the record
|
||||
* layer handling, this test covers zero-length records of all content types
|
||||
* for complete coverage of cases.
|
||||
*
|
||||
* !!! Expected TLS (Stream) behavior !!!
|
||||
* - Handshake records of zero length are ignored.
|
||||
* - Alert and ChangeCipherSpec records of zero-length lead to illegal
|
||||
* parameter alerts due to the malformed record content.
|
||||
* - ApplicationData before the handshake leads to an unexpected message alert.
|
||||
*
|
||||
* !!! Expected DTLS (Datagram) behavior !!!
|
||||
* - Handshake message of zero length are ignored.
|
||||
* - Alert messages lead to an illegal parameter alert due to malformed record
|
||||
* content.
|
||||
* - ChangeCipherSpec records before the first handshake are not expected and
|
||||
* ignored (see ssl3con.c, line 3276).
|
||||
* - ApplicationData before the handshake is ignored since it could be a packet
|
||||
* received in incorrect order (see ssl3con.c, line 13353).
|
||||
*/
|
||||
TEST_P(ZeroLengthRecordSetup, ZeroLengthRecordRun) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Send zero-length record
|
||||
DataBuffer buffer;
|
||||
createZeroLengthRecord(buffer);
|
||||
client_->SendDirect(buffer);
|
||||
// This must be set, otherwise handshake completness assertions might fail
|
||||
server_->StartConnect();
|
||||
|
||||
SSLAlertDescription alert = close_notify;
|
||||
|
||||
switch (variant_) {
|
||||
case ssl_variant_datagram:
|
||||
switch (contentType_) {
|
||||
case ssl_ct_alert:
|
||||
// Should actually be ignored, see bug 1829391.
|
||||
alert = illegal_parameter;
|
||||
break;
|
||||
case ssl_ct_ack:
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// Skipped due to bug 1829391.
|
||||
GTEST_SKIP();
|
||||
}
|
||||
// DTLS versions < 1.3 correctly ignore the invalid record
|
||||
// so we fall through.
|
||||
case ssl_ct_change_cipher_spec:
|
||||
case ssl_ct_application_data:
|
||||
case ssl_ct_handshake:
|
||||
server_->Handshake();
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ssl_variant_stream:
|
||||
switch (contentType_) {
|
||||
case ssl_ct_alert:
|
||||
case ssl_ct_change_cipher_spec:
|
||||
alert = illegal_parameter;
|
||||
break;
|
||||
case ssl_ct_application_data:
|
||||
case ssl_ct_ack:
|
||||
alert = unexpected_message;
|
||||
break;
|
||||
case ssl_ct_handshake:
|
||||
// TLS ignores unprotected zero-length handshake records
|
||||
server_->Handshake();
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Assert alert is send for TLS and DTLS alert records
|
||||
server_->ExpectSendAlert(alert);
|
||||
server_->Handshake();
|
||||
|
||||
// Consume alert at peer, expect alert for TLS and DTLS alert records
|
||||
client_->StartConnect();
|
||||
client_->ExpectReceiveAlert(alert);
|
||||
client_->Handshake();
|
||||
}
|
||||
|
||||
// Test for handshake, alert, change_cipher_spec and application data fragments
|
||||
const SSLContentType kZeroLengthRecordContentTypes[] = {
|
||||
ssl_ct_handshake, ssl_ct_alert, ssl_ct_change_cipher_spec,
|
||||
ssl_ct_application_data, ssl_ct_ack};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ZeroLengthRecordTest, ZeroLengthRecordSetup,
|
||||
testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11Plus,
|
||||
testing::ValuesIn(kZeroLengthRecordContentTypes)),
|
||||
[](const testing::TestParamInfo<ZeroLengthRecordSetup::ParamType>& inf) {
|
||||
std::string variant =
|
||||
(std::get<0>(inf.param) == ssl_variant_stream) ? "Tls" : "Dtls";
|
||||
std::string version = VersionString(std::get<1>(inf.param));
|
||||
std::replace(version.begin(), version.end(), '.', '_');
|
||||
std::string contentType;
|
||||
switch (std::get<2>(inf.param)) {
|
||||
case ssl_ct_handshake:
|
||||
contentType = "Handshake";
|
||||
break;
|
||||
case ssl_ct_alert:
|
||||
contentType = "Alert";
|
||||
break;
|
||||
case ssl_ct_application_data:
|
||||
contentType = "ApplicationData";
|
||||
break;
|
||||
case ssl_ct_change_cipher_spec:
|
||||
contentType = "ChangeCipherSpec";
|
||||
break;
|
||||
case ssl_ct_ack:
|
||||
contentType = "Ack";
|
||||
break;
|
||||
}
|
||||
return variant + version + "ZeroLength" + contentType + "Test";
|
||||
});
|
||||
|
||||
/* Test correct handling of records with invalid content types.
|
||||
*
|
||||
* TLS:
|
||||
* If a TLS implementation receives an unexpected record type, it MUST
|
||||
* terminate the connection with an "unexpected_message" alert
|
||||
* [RFC8446, Section 5].
|
||||
*
|
||||
* DTLS:
|
||||
* In general, invalid records SHOULD be silently discarded...
|
||||
* [RFC6347, Section 4.1.2.7]. */
|
||||
class UndefinedContentTypeSetup : public TlsConnectGeneric {
|
||||
public:
|
||||
UndefinedContentTypeSetup() : TlsConnectGeneric() { StartConnect(); };
|
||||
|
||||
void createUndefinedContentTypeRecord(DataBuffer& buffer, unsigned epoch = 0,
|
||||
unsigned seqn = 0) {
|
||||
// dummy data
|
||||
uint8_t data[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE};
|
||||
|
||||
size_t idx = 0;
|
||||
// Set undefined content type
|
||||
idx = buffer.Write(idx, 0xFF, 1);
|
||||
// The record version is not checked during record layer handling
|
||||
idx = buffer.Write(idx, 0xDEAD, 2);
|
||||
// DTLS (version always < TLS 1.3)
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
// Set epoch (Should be 0 before/during handshake)
|
||||
idx = buffer.Write(idx, epoch, 2);
|
||||
// Set 6B sequence number (0 if send as first message)
|
||||
idx = buffer.Write(idx, 0U, 2);
|
||||
idx = buffer.Write(idx, seqn, 4);
|
||||
}
|
||||
// Set fragment length
|
||||
idx = buffer.Write(idx, 5U, 2);
|
||||
// Add data to record
|
||||
(void)buffer.Write(idx, data, 5);
|
||||
}
|
||||
|
||||
void checkUndefinedContentTypeHandling(std::shared_ptr<TlsAgent> sender,
|
||||
std::shared_ptr<TlsAgent> receiver) {
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
// Handle record and expect alert to be sent
|
||||
receiver->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
receiver->ReadBytes();
|
||||
/* Digest and assert that the correct alert was received at peer
|
||||
*
|
||||
* The 1.3 server expects all messages other than the ClientHello to be
|
||||
* encrypted and responds with an unexpected message alert to alerts. */
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3 && sender == server_) {
|
||||
sender->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
} else {
|
||||
sender->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
|
||||
}
|
||||
sender->ReadBytes();
|
||||
} else { // DTLS drops invalid records silently
|
||||
size_t received = receiver->received_bytes();
|
||||
receiver->ReadBytes();
|
||||
// Ensure no bytes were received/record was dropped
|
||||
ASSERT_EQ(received, receiver->received_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
DataBuffer buffer_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
UndefinedContentTypePreHandshakeStream, UndefinedContentTypeSetup,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
UndefinedContentTypePreHandshakeDatagram, UndefinedContentTypeSetup,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
||||
TEST_P(UndefinedContentTypeSetup,
|
||||
ServerReceiveUndefinedContentTypePreClientHello) {
|
||||
createUndefinedContentTypeRecord(buffer_);
|
||||
|
||||
// Send undefined content type record
|
||||
client_->SendDirect(buffer_);
|
||||
|
||||
checkUndefinedContentTypeHandling(client_, server_);
|
||||
}
|
||||
|
||||
TEST_P(UndefinedContentTypeSetup,
|
||||
ServerReceiveUndefinedContentTypePostClientHello) {
|
||||
// Set epoch to 0 (handshake), and sequence number to 1 since hello is sent
|
||||
createUndefinedContentTypeRecord(buffer_, 0, 1);
|
||||
|
||||
// Send ClientHello
|
||||
client_->Handshake();
|
||||
// Send undefined content type record
|
||||
client_->SendDirect(buffer_);
|
||||
|
||||
checkUndefinedContentTypeHandling(client_, server_);
|
||||
}
|
||||
|
||||
TEST_P(UndefinedContentTypeSetup,
|
||||
ClientReceiveUndefinedContentTypePreClientHello) {
|
||||
createUndefinedContentTypeRecord(buffer_);
|
||||
|
||||
// Send undefined content type record
|
||||
server_->SendDirect(buffer_);
|
||||
|
||||
checkUndefinedContentTypeHandling(server_, client_);
|
||||
}
|
||||
|
||||
TEST_P(UndefinedContentTypeSetup,
|
||||
ClientReceiveUndefinedContentTypePostClientHello) {
|
||||
// Set epoch to 0 (handshake), and sequence number to 1 since hello is sent
|
||||
createUndefinedContentTypeRecord(buffer_, 0, 1);
|
||||
|
||||
// Send ClientHello
|
||||
client_->Handshake();
|
||||
// Send undefined content type record
|
||||
server_->SendDirect(buffer_);
|
||||
|
||||
checkUndefinedContentTypeHandling(server_, client_);
|
||||
}
|
||||
|
||||
class RecordOuterContentTypeSetter : public TlsRecordFilter {
|
||||
public:
|
||||
RecordOuterContentTypeSetter(const std::shared_ptr<TlsAgent>& a,
|
||||
uint8_t contentType = ssl_ct_handshake)
|
||||
: TlsRecordFilter(a), contentType_(contentType) {}
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& record, size_t* offset,
|
||||
DataBuffer* output) override {
|
||||
TlsRecordHeader hdr(header.variant(), header.version(), contentType_,
|
||||
header.sequence_number());
|
||||
|
||||
*offset = hdr.Write(output, *offset, record);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t contentType_;
|
||||
};
|
||||
|
||||
/* Test correct handling of invalid inner and outer record content type.
|
||||
* This is only possible for TLS 1.3, since only for this version decryption
|
||||
* and encryption of manipulated records is supported by the test suite. */
|
||||
TEST_P(TlsConnectTls13, UndefinedOuterContentType13) {
|
||||
EnsureTlsSetup();
|
||||
Connect();
|
||||
|
||||
// Manipulate record: set invalid content type 0xff
|
||||
MakeTlsFilter<RecordOuterContentTypeSetter>(client_, 0xff);
|
||||
client_->SendData(50);
|
||||
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
// Handle invalid record
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
server_->ReadBytes();
|
||||
// Handle alert at peer
|
||||
client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
|
||||
client_->ReadBytes();
|
||||
} else {
|
||||
// Make sure DTLS drops invalid record silently
|
||||
size_t received = server_->received_bytes();
|
||||
server_->ReadBytes();
|
||||
ASSERT_EQ(received, server_->received_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, UndefinedInnerContentType13) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Manipulate record: set invalid content type 0xff and length to 50.
|
||||
auto filter = MakeTlsFilter<Tls13RecordModifier>(client_, 0xff, 50, 0);
|
||||
filter->EnableDecryption();
|
||||
filter->Disable();
|
||||
|
||||
Connect();
|
||||
|
||||
filter->Enable();
|
||||
// Send manipulate record with invalid content type
|
||||
client_->SendData(50);
|
||||
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
// Handle invalid record
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
server_->ReadBytes();
|
||||
// Handle alert at peer
|
||||
client_->ExpectReceiveAlert(kTlsAlertUnexpectedMessage);
|
||||
client_->ReadBytes();
|
||||
} else {
|
||||
// Make sure DTLS drops invalid record silently
|
||||
size_t received = server_->received_bytes();
|
||||
server_->ReadBytes();
|
||||
ASSERT_EQ(received, server_->received_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -276,7 +277,8 @@ class StagedRecords {
|
|||
// Now there should be staged data.
|
||||
EXPECT_FALSE(data_.empty());
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << role_ << ": forward " << data_ << std::endl;
|
||||
std::cerr << role_ << ": forward epoch " << epoch_ << " " << data_
|
||||
<< std::endl;
|
||||
}
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_RecordLayerData(peer->ssl_fd(), epoch_, content_type_,
|
||||
|
|
@ -364,14 +366,24 @@ TEST_P(TlsConnectStream, ReplaceRecordLayer) {
|
|||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
// This processes the ClientHello and stages the first server flight.
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// In TLS 1.3, this is 0-RTT; in <TLS 1.3, this is application data.
|
||||
// Neither is acceptable.
|
||||
RefuseApplicationData(client_, 1);
|
||||
RefuseApplicationData(server_, 1);
|
||||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// Application data in handshake is never acceptable.
|
||||
RefuseApplicationData(client_, 2);
|
||||
RefuseApplicationData(server_, 2);
|
||||
// Don't accept real data until the handshake is done.
|
||||
RefuseApplicationData(client_, 3);
|
||||
RefuseApplicationData(server_, 3);
|
||||
// Process the server flight and the client is done.
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
} else {
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
RefuseApplicationData(client_, 1);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
}
|
||||
|
|
@ -382,6 +394,52 @@ TEST_P(TlsConnectStream, ReplaceRecordLayer) {
|
|||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ReplaceRecordLayerZeroRtt) {
|
||||
SetupForZeroRtt();
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
StartConnect();
|
||||
client_->SetServerKeyBits(server_->server_key_bits());
|
||||
|
||||
BadPrSocket bad_layer_client(client_);
|
||||
BadPrSocket bad_layer_server(server_);
|
||||
|
||||
StagedRecords client_stage(client_);
|
||||
StagedRecords server_stage(server_);
|
||||
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
// Send ClientHello
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// The client can never accept 0-RTT.
|
||||
RefuseApplicationData(client_, 1);
|
||||
|
||||
// Send some 0-RTT data, which get staged in `client_stage`.
|
||||
const char* kMsg = "EarlyData";
|
||||
const PRInt32 kMsgLen = static_cast<PRInt32>(strlen(kMsg));
|
||||
PRInt32 rv = PR_Write(client_->ssl_fd(), kMsg, kMsgLen);
|
||||
EXPECT_EQ(kMsgLen, rv);
|
||||
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// The server should now have 0-RTT to read.
|
||||
std::vector<uint8_t> buf(kMsgLen);
|
||||
rv = PR_Read(server_->ssl_fd(), buf.data(), kMsgLen);
|
||||
EXPECT_EQ(kMsgLen, rv);
|
||||
|
||||
// The handshake should happily finish.
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
|
||||
// Reading and writing application data should work.
|
||||
SendForwardReceive(client_, client_stage, server_);
|
||||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
static SECStatus AuthCompleteBlock(TlsAgent*, PRBool, PRBool) {
|
||||
return SECWouldBlock;
|
||||
}
|
||||
|
|
@ -573,4 +631,49 @@ TEST_F(TlsConnectDatagram13, ForwardDataDtls) {
|
|||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, SuppressEndOfEarlyData) {
|
||||
SetupForZeroRtt();
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
client_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true);
|
||||
server_->SetOption(SSL_SUPPRESS_END_OF_EARLY_DATA, true);
|
||||
StartConnect();
|
||||
client_->SetServerKeyBits(server_->server_key_bits());
|
||||
|
||||
BadPrSocket bad_layer_client(client_);
|
||||
BadPrSocket bad_layer_server(server_);
|
||||
|
||||
StagedRecords client_stage(client_);
|
||||
StagedRecords server_stage(server_);
|
||||
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
// Send ClientHello
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// Send some 0-RTT data, which get staged in `client_stage`.
|
||||
const char* kMsg = "ABCDEF";
|
||||
const PRInt32 kMsgLen = static_cast<PRInt32>(strlen(kMsg));
|
||||
PRInt32 rv = PR_Write(client_->ssl_fd(), kMsg, kMsgLen);
|
||||
EXPECT_EQ(kMsgLen, rv);
|
||||
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// The server should now have 0-RTT to read.
|
||||
std::vector<uint8_t> buf(kMsgLen);
|
||||
rv = PR_Read(server_->ssl_fd(), buf.data(), kMsgLen);
|
||||
EXPECT_EQ(kMsgLen, rv);
|
||||
|
||||
// The handshake should happily finish, without the end of the early data.
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
|
||||
// Reading and writing application data should work.
|
||||
SendForwardReceive(client_, client_stage, server_);
|
||||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -18,7 +19,8 @@ namespace nss_test {
|
|||
|
||||
// This class tracks the maximum size of record that was sent, both cleartext
|
||||
// and plain. It only tracks records that have an outer type of
|
||||
// application_data. In TLS 1.3, this includes handshake messages.
|
||||
// application_data or DTLSCiphertext. In TLS 1.3, this includes handshake
|
||||
// messages.
|
||||
class TlsRecordMaximum : public TlsRecordFilter {
|
||||
public:
|
||||
TlsRecordMaximum(const std::shared_ptr<TlsAgent>& a)
|
||||
|
|
@ -33,7 +35,7 @@ class TlsRecordMaximum : public TlsRecordFilter {
|
|||
DataBuffer* output) override {
|
||||
std::cerr << "max: " << record << std::endl;
|
||||
// Ignore unprotected packets.
|
||||
if (header.content_type() != ssl_ct_application_data) {
|
||||
if (!header.is_protected()) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
|
|
@ -194,9 +196,23 @@ class TlsRecordExpander : public TlsRecordFilter {
|
|||
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) {
|
||||
if (header.content_type() != ssl_ct_application_data) {
|
||||
return KEEP;
|
||||
if (!header.is_protected()) {
|
||||
// We're targeting application_data records. If the record is
|
||||
// |!is_protected()|, we have two possibilities:
|
||||
if (!decrypting()) {
|
||||
// 1) We're not decrypting, in which this case this is truly an
|
||||
// unencrypted record (Keep).
|
||||
return KEEP;
|
||||
}
|
||||
if (header.content_type() != ssl_ct_application_data) {
|
||||
// 2) We are decrypting, so is_protected() read the internal
|
||||
// content_type. If the internal ct IS NOT application_data, then
|
||||
// it's not our target (Keep).
|
||||
return KEEP;
|
||||
}
|
||||
// Otherwise, the the internal ct IS application_data (Change).
|
||||
}
|
||||
|
||||
changed->Allocate(data.len() + expansion_);
|
||||
changed->Write(0, data.data(), data.len());
|
||||
return CHANGE;
|
||||
|
|
@ -207,7 +223,7 @@ class TlsRecordExpander : public TlsRecordFilter {
|
|||
};
|
||||
|
||||
// Tweak the plaintext of server records so that they exceed the client's limit.
|
||||
TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
|
||||
TEST_F(TlsConnectStreamTls13, RecordSizePlaintextExceed) {
|
||||
EnsureTlsSetup();
|
||||
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 1);
|
||||
server_expand->EnableDecryption();
|
||||
|
|
@ -231,7 +247,7 @@ TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
|
|||
// This requires a much larger expansion than for plaintext to trigger the
|
||||
// guard, which runs before decryption (current allowance is 320 octets,
|
||||
// see MAX_EXPANSION in ssl3con.c).
|
||||
TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
|
||||
TEST_F(TlsConnectStreamTls13, RecordSizeCiphertextExceed) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
|
|
@ -250,6 +266,27 @@ TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
|
|||
server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ClientHelloF5Padding) {
|
||||
EnsureTlsSetup();
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey key(
|
||||
PK11_KeyGen(slot.get(), CKM_NSS_CHACHA20_POLY1305, nullptr, 32, nullptr));
|
||||
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(client_, kTlsHandshakeClientHello);
|
||||
|
||||
// Add PSK with label long enough to push CH length into [256, 511].
|
||||
std::vector<uint8_t> label(100);
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_AddExternalPsk(client_->ssl_fd(), key.get(), label.data(),
|
||||
label.size(), ssl_hash_sha256));
|
||||
StartConnect();
|
||||
client_->Handshake();
|
||||
|
||||
// Filter removes the 4B handshake header.
|
||||
EXPECT_EQ(508UL, filter->buffer().len());
|
||||
}
|
||||
|
||||
// This indiscriminately adds padding to application data records.
|
||||
class TlsRecordPadder : public TlsRecordFilter {
|
||||
public:
|
||||
|
|
@ -260,30 +297,31 @@ class TlsRecordPadder : public TlsRecordFilter {
|
|||
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& record, size_t* offset,
|
||||
DataBuffer* output) override {
|
||||
if (header.content_type() != ssl_ct_application_data) {
|
||||
if (!header.is_protected()) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
uint16_t protection_epoch;
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
TlsRecordHeader out_header;
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext)) {
|
||||
&plaintext, &out_header)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
if (inner_content_type != ssl_ct_application_data) {
|
||||
if (decrypting() && inner_content_type != ssl_ct_application_data) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool ok = Protect(spec(protection_epoch), header, inner_content_type,
|
||||
plaintext, &ciphertext, padding_);
|
||||
bool ok = Protect(spec(protection_epoch), out_header, inner_content_type,
|
||||
plaintext, &ciphertext, &out_header, padding_);
|
||||
EXPECT_TRUE(ok);
|
||||
if (!ok) {
|
||||
return KEEP;
|
||||
}
|
||||
*offset = header.Write(output, *offset, ciphertext);
|
||||
*offset = out_header.Write(output, *offset, ciphertext);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
|
|
@ -291,7 +329,7 @@ class TlsRecordPadder : public TlsRecordFilter {
|
|||
size_t padding_;
|
||||
};
|
||||
|
||||
TEST_P(TlsConnectTls13, RecordSizeExceedPad) {
|
||||
TEST_F(TlsConnectStreamTls13, RecordSizeExceedPad) {
|
||||
EnsureTlsSetup();
|
||||
auto server_max = std::make_shared<TlsRecordMaximum>(server_);
|
||||
auto server_expand = std::make_shared<TlsRecordPadder>(server_, 1);
|
||||
|
|
@ -456,4 +494,233 @@ TEST_F(RecordSizeDefaultsTest, RecordSizeGetValue) {
|
|||
EXPECT_EQ(3000, v);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
class TlsCtextResizer : public TlsRecordFilter {
|
||||
public:
|
||||
TlsCtextResizer(const std::shared_ptr<TlsAgent>& a, size_t size)
|
||||
: TlsRecordFilter(a), size_(size) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& data,
|
||||
DataBuffer* changed) {
|
||||
// allocate and initialise buffer
|
||||
changed->Allocate(size_);
|
||||
|
||||
// copy record data (partially)
|
||||
changed->Write(0, data.data(),
|
||||
((data.len() >= size_) ? size_ : data.len()));
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
/* (D)TLS overlong record test for maximum default record size of
|
||||
* 2^14 + (256 (TLS 1.3) OR 2048 (TLS <= 1.2)
|
||||
* [RFC8446, Section 5.2; RFC5246 , Section 6.2.3].
|
||||
* This should fail the first size check in ssl3gthr.c/ssl3_GatherData().
|
||||
* DTLS Record errors are dropped silently. [RFC6347, Section 4.1.2.7]. */
|
||||
TEST_P(TlsConnectGeneric, RecordGatherOverlong) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
size_t max_ctext = MAX_FRAGMENT_LENGTH;
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
max_ctext += TLS_1_3_MAX_EXPANSION;
|
||||
} else {
|
||||
max_ctext += TLS_1_2_MAX_EXPANSION;
|
||||
}
|
||||
|
||||
Connect();
|
||||
|
||||
MakeTlsFilter<TlsCtextResizer>(server_, max_ctext + 1);
|
||||
// Dummy record will be overwritten
|
||||
server_->SendData(0xf0);
|
||||
|
||||
/* Drop DTLS Record Errors silently [RFC6347, Section 4.1.2.7]. */
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
size_t received = client_->received_bytes();
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
ASSERT_EQ(received, client_->received_bytes());
|
||||
} else {
|
||||
client_->ExpectSendAlert(kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
server_->ExpectReceiveAlert(kTlsAlertRecordOverflow);
|
||||
server_->Handshake();
|
||||
}
|
||||
}
|
||||
|
||||
/* (D)TLS overlong record test with recordSizeLimit Extension and plus RFC
|
||||
* specified maximum Expansion: 2^14 + (256 (TLS 1.3) OR 2048 (TLS <= 1.2)
|
||||
* [RFC8446, Section 5.2; RFC5246 , Section 6.2.3].
|
||||
* DTLS Record errors are dropped silently. [RFC6347, Section 4.1.2.7]. */
|
||||
TEST_P(TlsConnectGeneric, RecordSizeExtensionOverlong) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Set some boundary
|
||||
size_t max_ctext = 1000;
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, max_ctext);
|
||||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// The record size limit includes the inner content type byte
|
||||
max_ctext += TLS_1_3_MAX_EXPANSION - 1;
|
||||
} else {
|
||||
max_ctext += TLS_1_2_MAX_EXPANSION;
|
||||
}
|
||||
|
||||
Connect();
|
||||
|
||||
MakeTlsFilter<TlsCtextResizer>(server_, max_ctext + 1);
|
||||
// Dummy record will be overwritten
|
||||
server_->SendData(0xf);
|
||||
|
||||
/* Drop DTLS Record Errors silently [RFC6347, Section 4.1.2.7].
|
||||
* For DTLS 1.0 and 1.2 the package is dropped before the size check because
|
||||
* of the modification. This just tests that no error is thrown as required.
|
||||
*/
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
size_t received = client_->received_bytes();
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
ASSERT_EQ(received, client_->received_bytes());
|
||||
} else {
|
||||
client_->ExpectSendAlert(kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
server_->ExpectReceiveAlert(kTlsAlertRecordOverflow);
|
||||
server_->Handshake();
|
||||
}
|
||||
}
|
||||
|
||||
/* For TLS <= 1.2:
|
||||
* MAX_EXPANSION is the amount by which a record might plausibly be expanded
|
||||
* when protected. It's the worst case estimate, so the sum of block cipher
|
||||
* padding (up to 256 octets), HMAC (48 octets for SHA-384), and IV (16
|
||||
* octets for AES). */
|
||||
#define MAX_EXPANSION (256 + 48 + 16)
|
||||
|
||||
/* (D)TLS overlong record test for specific ciphersuite expansion.
|
||||
* Testing the smallest illegal record.
|
||||
* This check is performed in ssl3con.c/ssl3_UnprotectRecord() OR
|
||||
* tls13con.c/tls13_UnprotectRecord() and enforces stricter size limitations,
|
||||
* dependent on the implemented cipher suites, than the RFC.
|
||||
* DTLS Record errors are dropped silently. [RFC6347, Section 4.1.2.7]. */
|
||||
TEST_P(TlsConnectGeneric, RecordExpansionOverlong) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Set some boundary
|
||||
size_t max_ctext = 1000;
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, max_ctext);
|
||||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// For TLS1.3 all ciphers expand the cipherext by 16B
|
||||
// The inner content type byte is included in the record size limit
|
||||
max_ctext += 16;
|
||||
} else {
|
||||
// For TLS<=1.2 the max possible expansion in the NSS implementation is 320
|
||||
max_ctext += MAX_EXPANSION;
|
||||
}
|
||||
|
||||
Connect();
|
||||
|
||||
MakeTlsFilter<TlsCtextResizer>(server_, max_ctext + 1);
|
||||
// Dummy record will be overwritten
|
||||
server_->SendData(0xf);
|
||||
|
||||
/* Drop DTLS Record Errors silently [RFC6347, Section 4.1.2.7].
|
||||
* For DTLS 1.0 and 1.2 the package is dropped before the size check because
|
||||
* of the modification. This just tests that no error is thrown as required/
|
||||
* no bytes are received. */
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
size_t received = client_->received_bytes();
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
ASSERT_EQ(received, client_->received_bytes());
|
||||
} else {
|
||||
client_->ExpectSendAlert(kTlsAlertRecordOverflow);
|
||||
client_->ReadBytes(max_ctext + 1);
|
||||
server_->ExpectReceiveAlert(kTlsAlertRecordOverflow);
|
||||
server_->Handshake();
|
||||
}
|
||||
}
|
||||
|
||||
/* (D)TLS longest allowed record default size test. */
|
||||
TEST_P(TlsConnectGeneric, RecordSizeDefaultLong) {
|
||||
EnsureTlsSetup();
|
||||
Connect();
|
||||
|
||||
// Maximum allowed plaintext size
|
||||
size_t max = MAX_FRAGMENT_LENGTH;
|
||||
|
||||
/* For TLS 1.0 the first byte of application data is sent in a single record
|
||||
* as explained in the documentation of SSL_CBC_RANDOM_IV in ssl.h.
|
||||
* Because of that we use TlsCTextResizer to send a record of max size.
|
||||
* A bad record mac alert is expected since we modify the record. */
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0 &&
|
||||
variant_ == ssl_variant_stream) {
|
||||
// Set size to maxi plaintext + max allowed expansion
|
||||
MakeTlsFilter<TlsCtextResizer>(server_, max + MAX_EXPANSION);
|
||||
// Dummy record will be overwritten
|
||||
server_->SendData(0xF);
|
||||
// Expect alert
|
||||
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
||||
// Receive record
|
||||
client_->ReadBytes(max);
|
||||
// Handle alert on server side
|
||||
server_->ExpectReceiveAlert(kTlsAlertBadRecordMac);
|
||||
server_->Handshake();
|
||||
} else { // Everything but TLS 1.0
|
||||
// Send largest legal plaintext as single record
|
||||
// by setting SendData() block size to max.
|
||||
server_->SendData(max, max);
|
||||
// Receive record
|
||||
client_->ReadBytes(max);
|
||||
// Assert that data was received successfully
|
||||
ASSERT_EQ(client_->received_bytes(), max);
|
||||
}
|
||||
}
|
||||
|
||||
/* (D)TLS longest allowed record size limit extension test. */
|
||||
TEST_P(TlsConnectGeneric, RecordSizeLimitLong) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
// Set some boundary
|
||||
size_t max = 1000;
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, max);
|
||||
|
||||
Connect();
|
||||
|
||||
// For TLS 1.3 the InnerContentType byte is included in the record size limit
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
max--;
|
||||
}
|
||||
|
||||
/* For TLS 1.0 the first byte of application data is sent in a single record
|
||||
* as explained in the documentation of SSL_CBC_RANDOM_IV in ssl.h.
|
||||
* Because of that we use TlsCTextResizer to send a record of max size.
|
||||
* A bad record mac alert is expected since we modify the record. */
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0 &&
|
||||
variant_ == ssl_variant_stream) {
|
||||
// Set size to maxi plaintext + max allowed expansion
|
||||
MakeTlsFilter<TlsCtextResizer>(server_, max + MAX_EXPANSION);
|
||||
// Dummy record will be overwritten
|
||||
server_->SendData(0xF);
|
||||
// Expect alert
|
||||
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
||||
// Receive record
|
||||
client_->ReadBytes(max);
|
||||
// Handle alert on server side
|
||||
server_->ExpectReceiveAlert(kTlsAlertBadRecordMac);
|
||||
server_->Handshake();
|
||||
} else { // Everything but TLS 1.0
|
||||
// Send largest legal plaintext as single record
|
||||
// by setting SendData() block size to max.
|
||||
server_->SendData(max, max);
|
||||
// Receive record
|
||||
client_->ReadBytes(max);
|
||||
// Assert that data was received successfully
|
||||
ASSERT_EQ(client_->received_bytes(), max);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -69,7 +70,7 @@ TEST_F(TlsConnectTest, RenegotiationConfigTls13) {
|
|||
|
||||
TEST_P(TlsConnectStream, ConnectTls10AndServerRenegotiateHigher) {
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
// Set the client so it will accept any version from 1.0
|
||||
// to |version_|.
|
||||
|
|
@ -109,7 +110,7 @@ TEST_P(TlsConnectStream, ConnectTls10AndServerRenegotiateHigher) {
|
|||
|
||||
TEST_P(TlsConnectStream, ConnectTls10AndClientRenegotiateHigher) {
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
// Set the client so it will accept any version from 1.0
|
||||
// to |version_|.
|
||||
|
|
@ -147,7 +148,7 @@ TEST_P(TlsConnectStream, ConnectTls10AndClientRenegotiateHigher) {
|
|||
|
||||
TEST_P(TlsConnectStream, ConnectAndServerRenegotiateLower) {
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
Connect();
|
||||
|
||||
|
|
@ -180,7 +181,7 @@ TEST_P(TlsConnectStream, ConnectAndServerRenegotiateLower) {
|
|||
|
||||
TEST_P(TlsConnectStream, ConnectAndServerWontRenegotiateLower) {
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
Connect();
|
||||
|
||||
|
|
@ -199,7 +200,7 @@ TEST_P(TlsConnectStream, ConnectAndServerWontRenegotiateLower) {
|
|||
|
||||
TEST_P(TlsConnectStream, ConnectAndClientWontRenegotiateLower) {
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
Connect();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -456,10 +457,10 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
|
|||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
|
||||
}
|
||||
|
||||
// Prior to TLS 1.3, we were not fully ephemeral; though 1.3 fixes that
|
||||
TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
|
||||
auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
EnableECDHEServerKeyReuse();
|
||||
Connect();
|
||||
CheckKeys();
|
||||
TlsServerKeyExchangeEcdhe dhe1;
|
||||
|
|
@ -467,6 +468,7 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
|
|||
|
||||
// Restart
|
||||
Reset();
|
||||
EnableECDHEServerKeyReuse();
|
||||
auto filter2 = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
|
|
@ -484,7 +486,6 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
|
|||
|
||||
// This test parses the ServerKeyExchange, which isn't in 1.3
|
||||
TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) {
|
||||
server_->SetOption(SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
|
||||
auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
Connect();
|
||||
|
|
@ -494,7 +495,6 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) {
|
|||
|
||||
// Restart
|
||||
Reset();
|
||||
server_->SetOption(SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
|
||||
auto filter2 = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
|
|
@ -736,7 +736,7 @@ TEST_P(TlsConnectGenericPre13, TestResumptionOverrideVersion) {
|
|||
if (variant_ == ssl_variant_stream) {
|
||||
switch (version_) {
|
||||
case SSL_LIBRARY_VERSION_TLS_1_0:
|
||||
return; // Skip the test.
|
||||
GTEST_SKIP();
|
||||
case SSL_LIBRARY_VERSION_TLS_1_1:
|
||||
override_version = SSL_LIBRARY_VERSION_TLS_1_0;
|
||||
break;
|
||||
|
|
@ -751,7 +751,7 @@ TEST_P(TlsConnectGenericPre13, TestResumptionOverrideVersion) {
|
|||
override_version = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
|
||||
} else {
|
||||
ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, version_);
|
||||
return; // Skip the test.
|
||||
GTEST_SKIP();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +836,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNST) {
|
|||
Connect();
|
||||
|
||||
// Clear the session ticket keys to invalidate the old ticket.
|
||||
SSLInt_ClearSelfEncryptKey();
|
||||
ClearServerCache();
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
|
||||
|
||||
SendReceive(); // Need to read so that we absorb the session tickets.
|
||||
|
|
@ -884,7 +884,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNSTWithToken) {
|
|||
Connect();
|
||||
|
||||
// Clear the session ticket keys to invalidate the old ticket.
|
||||
SSLInt_ClearSelfEncryptKey();
|
||||
ClearServerCache();
|
||||
nst_capture->Reset();
|
||||
uint8_t token[] = {0x20, 0x20, 0xff, 0x00};
|
||||
EXPECT_EQ(SECSuccess,
|
||||
|
|
@ -914,8 +914,7 @@ TEST_F(TlsConnectTest, SendSessionTicketWithTicketsDisabled) {
|
|||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(),
|
||||
SSL_ENABLE_SESSION_TICKETS, PR_FALSE));
|
||||
server_->SetOption(SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
|
||||
|
||||
auto nst_capture =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_new_session_ticket);
|
||||
|
|
@ -943,6 +942,50 @@ TEST_F(TlsConnectTest, SendSessionTicketWithTicketsDisabled) {
|
|||
NstTicketMatchesPskIdentity(nst_capture->buffer(), psk_capture->extension());
|
||||
}
|
||||
|
||||
// Successfully send a session ticket after resuming and then use it.
|
||||
TEST_F(TlsConnectTest, SendTicketAfterResumption) {
|
||||
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();
|
||||
|
||||
// Resume the connection.
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
// We need to capture just one ticket, so
|
||||
// disable automatic sending of tickets at the server.
|
||||
// ConfigureSessionCache enables this option, so revert that.
|
||||
server_->SetOption(SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
|
||||
auto nst_capture =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_new_session_ticket);
|
||||
nst_capture->EnableDecryption();
|
||||
Connect();
|
||||
|
||||
ClearServerCache();
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
|
||||
SendReceive();
|
||||
|
||||
// Reset stats so that the counters for resumptions match up.
|
||||
ClearStats();
|
||||
// Resume again and ensure that we get the same ticket.
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
auto psk_capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_pre_shared_key_xtn);
|
||||
Connect();
|
||||
SendReceive();
|
||||
|
||||
NstTicketMatchesPskIdentity(nst_capture->buffer(), psk_capture->extension());
|
||||
}
|
||||
|
||||
// Test calling SSL_SendSessionTicket in inappropriate conditions.
|
||||
TEST_F(TlsConnectTest, SendSessionTicketInappropriate) {
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -233,13 +234,13 @@ TEST_P(Tls13SkipTest, SkipClientCertificateVerify) {
|
|||
SSL_ERROR_RX_UNEXPECTED_FINISHED);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
INSTANTIATE_TEST_SUITE_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);
|
||||
INSTANTIATE_TEST_SUITE_P(SkipVariants, TlsSkipTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_SUITE_P(Skip13Variants, Tls13SkipTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -213,6 +214,29 @@ TEST_F(Tls13CompatTest, EnabledHrrZeroRtt) {
|
|||
CheckForCompatHandshake();
|
||||
}
|
||||
|
||||
TEST_F(Tls13CompatTest, EnabledAcceptedEch) {
|
||||
EnsureTlsSetup();
|
||||
SetupEch(client_, server_);
|
||||
EnableCompatMode();
|
||||
InstallFilters();
|
||||
Connect();
|
||||
CheckForCompatHandshake();
|
||||
}
|
||||
|
||||
TEST_F(Tls13CompatTest, EnabledRejectedEch) {
|
||||
EnsureTlsSetup();
|
||||
// Configure ECH on the client only, and expect CCS.
|
||||
SetupEch(client_, server_, HpkeDhKemX25519Sha256, false, true, false);
|
||||
EnableCompatMode();
|
||||
InstallFilters();
|
||||
ExpectAlert(client_, kTlsAlertEchRequired);
|
||||
ConnectExpectFailOneSide(TlsAgent::CLIENT);
|
||||
client_->CheckErrorCode(SSL_ERROR_ECH_RETRY_WITHOUT_ECH);
|
||||
CheckForCompatHandshake();
|
||||
// Reset expectations for the TlsAgent dtor.
|
||||
server_->ExpectReceiveAlert(kTlsAlertCloseNotify, kTlsAlertWarning);
|
||||
}
|
||||
|
||||
class TlsSessionIDEchoFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsSessionIDEchoFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
|
|
@ -462,14 +486,16 @@ TEST_F(TlsConnectDatagram13, CompatModeDtlsClient) {
|
|||
|
||||
ASSERT_EQ(2U, client_records->count()); // CH, Fin
|
||||
EXPECT_EQ(ssl_ct_handshake, client_records->record(0).header.content_type());
|
||||
EXPECT_EQ(ssl_ct_application_data,
|
||||
client_records->record(1).header.content_type());
|
||||
EXPECT_EQ(kCtDtlsCiphertext,
|
||||
(client_records->record(1).header.content_type() &
|
||||
kCtDtlsCiphertextMask));
|
||||
|
||||
ASSERT_EQ(6U, server_records->count()); // SH, EE, CT, CV, Fin, Ack
|
||||
EXPECT_EQ(ssl_ct_handshake, server_records->record(0).header.content_type());
|
||||
for (size_t i = 1; i < server_records->count(); ++i) {
|
||||
EXPECT_EQ(ssl_ct_application_data,
|
||||
server_records->record(i).header.content_type());
|
||||
EXPECT_EQ(kCtDtlsCiphertext,
|
||||
(server_records->record(i).header.content_type() &
|
||||
kCtDtlsCiphertextMask));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -518,8 +544,9 @@ TEST_F(TlsConnectDatagram13, CompatModeDtlsServer) {
|
|||
ASSERT_EQ(5U, server_records->count()); // SH, EE, CT, CV, Fin
|
||||
EXPECT_EQ(ssl_ct_handshake, server_records->record(0).header.content_type());
|
||||
for (size_t i = 1; i < server_records->count(); ++i) {
|
||||
EXPECT_EQ(ssl_ct_application_data,
|
||||
server_records->record(i).header.content_type());
|
||||
EXPECT_EQ(kCtDtlsCiphertext,
|
||||
(server_records->record(i).header.content_type() &
|
||||
kCtDtlsCiphertextMask));
|
||||
}
|
||||
|
||||
uint32_t session_id_len = 0;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -213,7 +214,7 @@ TEST_P(SSLv2ClientHelloTest, ConnectDisabled) {
|
|||
// But to be certain, feed in more data to see if an error comes out.
|
||||
uint8_t zeros[SSL_LIBRARY_VERSION_TLS_1_2] = {0};
|
||||
client_->SendDirect(DataBuffer(zeros, sizeof(zeros)));
|
||||
ExpectAlert(server_, kTlsAlertIllegalParameter);
|
||||
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
}
|
||||
|
|
@ -236,8 +237,8 @@ TEST_P(SSLv2ClientHelloTest, ConnectAfterEmptyV3Record) {
|
|||
// as the record length.
|
||||
SetPadding(255);
|
||||
|
||||
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
||||
EXPECT_EQ(SSL_ERROR_BAD_CLIENT, server_->error_code());
|
||||
ConnectExpectAlert(server_, kTlsAlertUnexpectedMessage);
|
||||
EXPECT_EQ(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, server_->error_code());
|
||||
}
|
||||
|
||||
// Test negotiating TLS 1.3.
|
||||
|
|
@ -276,7 +277,7 @@ TEST_P(SSLv2ClientHelloTest, SendSecurityEscape) {
|
|||
// Set a big padding so that the server fails instead of timing out.
|
||||
SetPadding(255);
|
||||
|
||||
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
||||
ConnectExpectAlert(server_, kTlsAlertUnexpectedMessage);
|
||||
}
|
||||
|
||||
// Invalid SSLv2 client hello padding must fail the handshake.
|
||||
|
|
@ -405,9 +406,9 @@ TEST_F(SSLv2ClientHelloTestF, InappropriateFallbackSCSV) {
|
|||
EXPECT_EQ(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, server_->error_code());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(VersionsStream10Pre13, SSLv2ClientHelloTest,
|
||||
TlsConnectTestBase::kTlsV10);
|
||||
INSTANTIATE_TEST_CASE_P(VersionsStreamPre13, SSLv2ClientHelloTest,
|
||||
TlsConnectTestBase::kTlsV11V12);
|
||||
INSTANTIATE_TEST_SUITE_P(VersionsStream10Pre13, SSLv2ClientHelloTest,
|
||||
TlsConnectTestBase::kTlsV10);
|
||||
INSTANTIATE_TEST_SUITE_P(VersionsStreamPre13, SSLv2ClientHelloTest,
|
||||
TlsConnectTestBase::kTlsV11V12);
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -27,7 +28,7 @@ TEST_P(TlsConnectStream, ServerNegotiateTls10) {
|
|||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, ServerNegotiateTls11) {
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) return;
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_1) GTEST_SKIP();
|
||||
|
||||
uint16_t minver, maxver;
|
||||
client_->GetVersionRange(&minver, &maxver);
|
||||
|
|
@ -38,7 +39,7 @@ TEST_P(TlsConnectGeneric, ServerNegotiateTls11) {
|
|||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, ServerNegotiateTls12) {
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) return;
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) GTEST_SKIP();
|
||||
|
||||
uint16_t minver, maxver;
|
||||
client_->GetVersionRange(&minver, &maxver);
|
||||
|
|
@ -59,8 +60,8 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
|
|||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2);
|
||||
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
|
||||
SSL_LIBRARY_VERSION_TLS_1_1);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
SSL_LIBRARY_VERSION_TLS_1_1);
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
|
|
@ -68,11 +69,10 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
|
|||
|
||||
// Attempt to negotiate the bogus DTLS 1.1 version.
|
||||
TEST_F(DtlsConnectTest, TestDtlsVersion11) {
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_, ((~0x0101) & 0xffff));
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
// It's kind of surprising that SSL_ERROR_NO_CYPHER_OVERLAP is
|
||||
// what is returned here, but this is deliberate in ssl3_HandleAlert().
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
((~0x0101) & 0xffff));
|
||||
ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
|
||||
client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ TEST_P(TlsDowngradeTest, TlsDowngradeSentinelTest) {
|
|||
static const size_t kRandomLen = 32;
|
||||
|
||||
if (c_ver > s_ver) {
|
||||
return;
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
client_->SetVersionRange(c_ver, c_ver);
|
||||
|
|
@ -161,8 +161,8 @@ TEST_P(TlsDowngradeTest, TlsDowngradeSentinelTest) {
|
|||
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
|
||||
// Setting the option here has no effect.
|
||||
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
|
||||
SSL_LIBRARY_VERSION_TLS_1_0);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
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,
|
||||
|
|
@ -203,6 +203,7 @@ TEST_F(TlsConnectTest, DisableFalseStartOnFallback) {
|
|||
SSL_SetCanFalseStartCallback(client_->ssl_fd(), AllowFalseStart,
|
||||
&false_start_attempted));
|
||||
|
||||
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_FALSE);
|
||||
client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2);
|
||||
|
|
@ -275,8 +276,8 @@ class Tls13NoSupportedVersions : public TlsConnectStreamTls12 {
|
|||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2);
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, max_server_version);
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
|
||||
overwritten_client_version);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
overwritten_client_version);
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(server_, kTlsHandshakeServerHello);
|
||||
ConnectExpectAlert(server_, kTlsAlertDecryptError);
|
||||
|
|
@ -310,8 +311,8 @@ 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) {
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3 + 1);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3 + 1);
|
||||
auto capture = MakeTlsFilter<TlsExtensionCapture>(
|
||||
server_, ssl_tls13_supported_versions_xtn);
|
||||
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
|
||||
|
|
@ -330,12 +331,14 @@ TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) {
|
|||
// Offer 1.3 but with Server/ClientHello.legacy_version == SSL 3.0. This
|
||||
// causes a protocol version alert. See RFC 8446 Appendix D.5.
|
||||
TEST_F(TlsConnectStreamTls13, Ssl30ClientHelloWithSupportedVersions) {
|
||||
MakeTlsFilter<TlsClientHelloVersionSetter>(client_, SSL_LIBRARY_VERSION_3_0);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(client_, kTlsHandshakeClientHello,
|
||||
SSL_LIBRARY_VERSION_3_0);
|
||||
ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, Ssl30ServerHelloWithSupportedVersions) {
|
||||
MakeTlsFilter<TlsServerHelloVersionSetter>(server_, SSL_LIBRARY_VERSION_3_0);
|
||||
MakeTlsFilter<TlsMessageVersionSetter>(server_, kTlsHandshakeServerHello,
|
||||
SSL_LIBRARY_VERSION_3_0);
|
||||
StartConnect();
|
||||
client_->ExpectSendAlert(kTlsAlertProtocolVersion);
|
||||
/* Since the handshake is not finished the client will send an unencrypted
|
||||
|
|
@ -345,7 +348,106 @@ TEST_F(TlsConnectStreamTls13, Ssl30ServerHelloWithSupportedVersions) {
|
|||
Handshake();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
// Verify the client sends only DTLS versions in supported_versions
|
||||
TEST_F(DtlsConnectTest, DtlsSupportedVersionsEncoding) {
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
auto capture = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_supported_versions_xtn);
|
||||
Connect();
|
||||
|
||||
ASSERT_EQ(7U, capture->extension().len());
|
||||
uint32_t version = 0;
|
||||
ASSERT_TRUE(capture->extension().Read(1, 2, &version));
|
||||
EXPECT_EQ(0x7f00 | DTLS_1_3_DRAFT_VERSION, static_cast<int>(version));
|
||||
ASSERT_TRUE(capture->extension().Read(3, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, static_cast<int>(version));
|
||||
ASSERT_TRUE(capture->extension().Read(5, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_DTLS_1_0_WIRE, static_cast<int>(version));
|
||||
}
|
||||
|
||||
// Verify the DTLS 1.3 supported_versions interop workaround.
|
||||
TEST_F(DtlsConnectTest, Dtls13VersionWorkaround) {
|
||||
static const uint16_t kExpectVersionsWorkaround[] = {
|
||||
0x7f00 | DTLS_1_3_DRAFT_VERSION, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2, SSL_LIBRARY_VERSION_DTLS_1_0_WIRE,
|
||||
SSL_LIBRARY_VERSION_TLS_1_1};
|
||||
const int min_ver = SSL_LIBRARY_VERSION_TLS_1_1,
|
||||
max_ver = SSL_LIBRARY_VERSION_TLS_1_3;
|
||||
|
||||
// Toggle the workaround, then verify both encodings are present.
|
||||
EnsureTlsSetup();
|
||||
SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE);
|
||||
SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_FALSE);
|
||||
SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE);
|
||||
client_->SetVersionRange(min_ver, max_ver);
|
||||
server_->SetVersionRange(min_ver, max_ver);
|
||||
auto capture = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_supported_versions_xtn);
|
||||
Connect();
|
||||
|
||||
uint32_t version = 0;
|
||||
size_t off = 1;
|
||||
ASSERT_EQ(1 + sizeof(kExpectVersionsWorkaround), capture->extension().len());
|
||||
for (unsigned int i = 0; i < PR_ARRAY_SIZE(kExpectVersionsWorkaround); i++) {
|
||||
ASSERT_TRUE(capture->extension().Read(off, 2, &version));
|
||||
EXPECT_EQ(kExpectVersionsWorkaround[i], static_cast<uint16_t>(version));
|
||||
off += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the client sends only TLS versions in supported_versions
|
||||
TEST_F(TlsConnectTest, TlsSupportedVersionsEncoding) {
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
auto capture = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_supported_versions_xtn);
|
||||
Connect();
|
||||
|
||||
ASSERT_EQ(9U, capture->extension().len());
|
||||
uint32_t version = 0;
|
||||
ASSERT_TRUE(capture->extension().Read(1, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_3, static_cast<int>(version));
|
||||
ASSERT_TRUE(capture->extension().Read(3, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, static_cast<int>(version));
|
||||
ASSERT_TRUE(capture->extension().Read(5, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, static_cast<int>(version));
|
||||
ASSERT_TRUE(capture->extension().Read(7, 2, &version));
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, static_cast<int>(version));
|
||||
}
|
||||
|
||||
/* Test that on reception of unsupported ClientHello.legacy_version the TLS 1.3
|
||||
* server sends the correct alert.
|
||||
*
|
||||
* If the "supported_versions" extension is absent and the server only supports
|
||||
* versions greater than ClientHello.legacy_version, the server MUST abort the
|
||||
* handshake with a "protocol_version" alert [RFC8446, Appendix D.2]. */
|
||||
TEST_P(TlsConnectGenericPre13, ClientHelloUnsupportedTlsVersion) {
|
||||
StartConnect();
|
||||
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
} else {
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_DTLS_1_3,
|
||||
SSL_LIBRARY_VERSION_DTLS_1_3);
|
||||
}
|
||||
|
||||
// Try to handshake
|
||||
client_->Handshake();
|
||||
// Expect protocol version alert
|
||||
server_->ExpectSendAlert(kTlsAlertProtocolVersion);
|
||||
server_->Handshake();
|
||||
// Digest alert at peer
|
||||
client_->ExpectReceiveAlert(kTlsAlertProtocolVersion);
|
||||
client_->ReadBytes();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TlsDowngradeSentinelTest, TlsDowngradeTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -375,9 +376,10 @@ TEST_P(TestPolicyVersionRange, TestAllTLSVersionsAndPolicyCombinations) {
|
|||
Connect();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TLSVersionRanges, TestPolicyVersionRange,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
kExpandedVersions, kExpandedVersions,
|
||||
kExpandedVersions,
|
||||
kExpandedVersions));
|
||||
INSTANTIATE_TEST_SUITE_P(TLSVersionRanges, TestPolicyVersionRange,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
kExpandedVersions,
|
||||
kExpandedVersions,
|
||||
kExpandedVersions,
|
||||
kExpandedVersions));
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -109,7 +110,6 @@ int32_t DummyPrSocket::Recv(PRFileDesc *f, void *buf, int32_t buflen,
|
|||
|
||||
auto &front = input_.front();
|
||||
if (static_cast<size_t>(buflen) < front.len()) {
|
||||
PR_ASSERT(false);
|
||||
PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -48,6 +49,7 @@ const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
|
|||
const std::string TlsAgent::kServerDsa = "dsa";
|
||||
const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
|
||||
const std::string TlsAgent::kDelegatorRsae2048 = "delegator_rsae2048";
|
||||
const std::string TlsAgent::kDelegatorRsaPss2048 = "delegator_rsa_pss2048";
|
||||
|
||||
static const uint8_t kCannedTls13ServerHello[] = {
|
||||
0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
|
||||
|
|
@ -71,8 +73,9 @@ TlsAgent::TlsAgent(const std::string& nm, Role rl, SSLProtocolVariant var)
|
|||
falsestart_enabled_(false),
|
||||
expected_version_(0),
|
||||
expected_cipher_suite_(0),
|
||||
expect_resumption_(false),
|
||||
expect_client_auth_(false),
|
||||
expect_ech_(false),
|
||||
expect_psk_(ssl_psk_none),
|
||||
can_falsestart_hook_called_(false),
|
||||
sni_hook_called_(false),
|
||||
auth_certificate_hook_called_(false),
|
||||
|
|
@ -90,7 +93,8 @@ TlsAgent::TlsAgent(const std::string& nm, Role rl, SSLProtocolVariant var)
|
|||
auth_certificate_callback_(),
|
||||
sni_callback_(),
|
||||
skip_version_checks_(false),
|
||||
resumption_token_() {
|
||||
resumption_token_(),
|
||||
policy_() {
|
||||
memset(&info_, 0, sizeof(info_));
|
||||
memset(&csinfo_, 0, sizeof(csinfo_));
|
||||
SECStatus rv = SSL_VersionRangeGetDefault(variant_, &vrange_);
|
||||
|
|
@ -224,6 +228,7 @@ bool TlsAgent::ConfigServerCert(const std::string& id, bool updateKeyBits,
|
|||
bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
|
||||
// Don't set up twice
|
||||
if (ssl_fd_) return true;
|
||||
NssManagePolicy policyManage(policy_, option_);
|
||||
|
||||
ScopedPRFileDesc dummy_fd(adapter_->CreateFD());
|
||||
EXPECT_NE(nullptr, dummy_fd);
|
||||
|
|
@ -299,7 +304,7 @@ bool TlsAgent::MaybeSetResumptionToken() {
|
|||
|
||||
// rv is SECFailure with error set to SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR
|
||||
// if the resumption token was bad (expired/malformed/etc.).
|
||||
if (expect_resumption_) {
|
||||
if (expect_psk_ == ssl_psk_resume) {
|
||||
// Only in case we expect resumption this has to be successful. We might
|
||||
// not expect resumption due to some reason but the token is totally fine.
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
|
@ -307,8 +312,8 @@ bool TlsAgent::MaybeSetResumptionToken() {
|
|||
if (rv != SECSuccess) {
|
||||
EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
|
||||
resumption_token_.clear();
|
||||
EXPECT_FALSE(expect_resumption_);
|
||||
if (expect_resumption_) return false;
|
||||
EXPECT_FALSE(expect_psk_ == ssl_psk_resume);
|
||||
if (expect_psk_ == ssl_psk_resume) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -316,13 +321,22 @@ bool TlsAgent::MaybeSetResumptionToken() {
|
|||
}
|
||||
|
||||
void TlsAgent::SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx) {
|
||||
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(ssl_fd_.get(), ctx.get()));
|
||||
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(ssl_fd(), ctx.get()));
|
||||
}
|
||||
|
||||
void TlsAgent::SetupClientAuth() {
|
||||
// Defaults to a Sync callback returning success
|
||||
void TlsAgent::SetupClientAuth(ClientAuthCallbackType callbackType,
|
||||
bool callbackSuccess) {
|
||||
EXPECT_TRUE(EnsureTlsSetup());
|
||||
ASSERT_EQ(CLIENT, role_);
|
||||
|
||||
client_auth_callback_type_ = callbackType;
|
||||
client_auth_callback_success_ = callbackSuccess;
|
||||
|
||||
if (callbackType == ClientAuthCallbackType::kNone && !callbackSuccess) {
|
||||
// Don't set a callback for this case.
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetClientAuthDataHook(ssl_fd(), GetClientAuthDataHook,
|
||||
reinterpret_cast<void*>(this)));
|
||||
|
|
@ -339,26 +353,95 @@ void CheckCertReqAgainstDefaultCAs(const CERTDistNames* caNames) {
|
|||
}
|
||||
}
|
||||
|
||||
// Complete processing of Client Certificate Selection
|
||||
// A No-op if the agent is using synchronous client cert selection.
|
||||
// Otherwise, calls SSL_ClientCertCallbackComplete.
|
||||
// kAsyncDelay triggers a call to SSL_ForceHandshake prior to completion to
|
||||
// ensure that the socket is correctly blocked.
|
||||
void TlsAgent::ClientAuthCallbackComplete() {
|
||||
ASSERT_EQ(CLIENT, role_);
|
||||
|
||||
if (client_auth_callback_type_ != ClientAuthCallbackType::kAsyncDelay &&
|
||||
client_auth_callback_type_ != ClientAuthCallbackType::kAsyncImmediate) {
|
||||
return;
|
||||
}
|
||||
client_auth_callback_fired_++;
|
||||
EXPECT_TRUE(client_auth_callback_awaiting_);
|
||||
|
||||
std::cerr << "client: calling SSL_ClientCertCallbackComplete with status "
|
||||
<< (client_auth_callback_success_ ? "success" : "failed")
|
||||
<< std::endl;
|
||||
|
||||
client_auth_callback_awaiting_ = false;
|
||||
|
||||
if (client_auth_callback_type_ == ClientAuthCallbackType::kAsyncDelay) {
|
||||
std::cerr
|
||||
<< "Running Handshake prior to running SSL_ClientCertCallbackComplete"
|
||||
<< std::endl;
|
||||
SECStatus rv = SSL_ForceHandshake(ssl_fd());
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(PORT_GetError(), PR_WOULD_BLOCK_ERROR);
|
||||
}
|
||||
|
||||
ScopedCERTCertificate cert;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
if (client_auth_callback_success_) {
|
||||
ASSERT_TRUE(TlsAgent::LoadCertificate(name(), &cert, &priv));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_ClientCertCallbackComplete(ssl_fd(), SECSuccess,
|
||||
priv.release(), cert.release()));
|
||||
} else {
|
||||
EXPECT_EQ(SECSuccess, SSL_ClientCertCallbackComplete(ssl_fd(), SECFailure,
|
||||
nullptr, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
|
||||
CERTDistNames* caNames,
|
||||
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";
|
||||
EXPECT_EQ(CLIENT, agent->role_);
|
||||
agent->client_auth_callback_fired_++;
|
||||
|
||||
// See bug 1573945
|
||||
// CheckCertReqAgainstDefaultCAs(caNames);
|
||||
switch (agent->client_auth_callback_type_) {
|
||||
case ClientAuthCallbackType::kAsyncDelay:
|
||||
case ClientAuthCallbackType::kAsyncImmediate:
|
||||
std::cerr << "Waiting for complete call" << std::endl;
|
||||
agent->client_auth_callback_awaiting_ = true;
|
||||
return SECWouldBlock;
|
||||
case ClientAuthCallbackType::kSync:
|
||||
case ClientAuthCallbackType::kNone:
|
||||
// Handle the sync case. None && Success is treated as Sync and Success.
|
||||
if (!agent->client_auth_callback_success_) {
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
|
||||
EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
|
||||
|
||||
ScopedCERTCertificate cert;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) {
|
||||
return SECFailure;
|
||||
// See bug 1573945
|
||||
// CheckCertReqAgainstDefaultCAs(caNames);
|
||||
|
||||
ScopedCERTCertificate cert;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*clientCert = cert.release();
|
||||
*clientKey = priv.release();
|
||||
return SECSuccess;
|
||||
}
|
||||
/* This is unreachable, but some old compilers can't tell that. */
|
||||
PORT_Assert(0);
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*clientCert = cert.release();
|
||||
*clientKey = priv.release();
|
||||
return SECSuccess;
|
||||
// Increments by 1 for each callback
|
||||
bool TlsAgent::CheckClientAuthCallbacksCompleted(uint8_t expected) {
|
||||
EXPECT_EQ(CLIENT, role_);
|
||||
return expected == client_auth_callback_fired_;
|
||||
}
|
||||
|
||||
bool TlsAgent::GetPeerChainLength(size_t* count) {
|
||||
|
|
@ -632,7 +715,9 @@ void TlsAgent::CheckAuthType(SSLAuthType auth,
|
|||
SSLSignatureScheme sig_scheme) const {
|
||||
EXPECT_EQ(STATE_CONNECTED, state_);
|
||||
EXPECT_EQ(auth, info_.authType);
|
||||
EXPECT_EQ(server_key_bits_, info_.authKeyBits);
|
||||
if (auth != ssl_auth_psk) {
|
||||
EXPECT_EQ(server_key_bits_, info_.authKeyBits);
|
||||
}
|
||||
if (expected_version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
|
||||
switch (auth) {
|
||||
case ssl_auth_rsa_sign:
|
||||
|
|
@ -683,13 +768,33 @@ void TlsAgent::EnableFalseStart() {
|
|||
SetOption(SSL_ENABLE_FALSE_START, PR_TRUE);
|
||||
}
|
||||
|
||||
void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
|
||||
void TlsAgent::ExpectEch(bool expected) { expect_ech_ = expected; }
|
||||
|
||||
void TlsAgent::ExpectPsk(SSLPskType psk) { expect_psk_ = psk; }
|
||||
|
||||
void TlsAgent::ExpectResumption() { expect_psk_ = ssl_psk_resume; }
|
||||
|
||||
void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
|
||||
EXPECT_TRUE(EnsureTlsSetup());
|
||||
EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd(), val, len));
|
||||
}
|
||||
|
||||
void TlsAgent::AddPsk(const ScopedPK11SymKey& psk, std::string label,
|
||||
SSLHashType hash, uint16_t zeroRttSuite) {
|
||||
EXPECT_TRUE(EnsureTlsSetup());
|
||||
EXPECT_EQ(SECSuccess, SSL_AddExternalPsk0Rtt(
|
||||
ssl_fd(), psk.get(),
|
||||
reinterpret_cast<const uint8_t*>(label.data()),
|
||||
label.length(), hash, zeroRttSuite, 1000));
|
||||
}
|
||||
|
||||
void TlsAgent::RemovePsk(std::string label) {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_RemoveExternalPsk(
|
||||
ssl_fd(), reinterpret_cast<const uint8_t*>(label.data()),
|
||||
label.length()));
|
||||
}
|
||||
|
||||
void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
|
||||
const std::string& expected) const {
|
||||
SSLNextProtoState alpn_state;
|
||||
|
|
@ -798,7 +903,6 @@ void TlsAgent::CheckPreliminaryInfo() {
|
|||
SSL_GetPreliminaryChannelInfo(ssl_fd(), &preinfo, sizeof(preinfo)));
|
||||
EXPECT_EQ(sizeof(preinfo), preinfo.length);
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_version);
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
|
||||
|
||||
// A version of 0 is invalid and indicates no expectation. This value is
|
||||
// initialized to 0 so that tests that don't explicitly set an expected
|
||||
|
|
@ -819,22 +923,22 @@ void TlsAgent::CheckPreliminaryInfo() {
|
|||
void TlsAgent::CheckCallbacks() const {
|
||||
// If false start happens, the handshake is reported as being complete at the
|
||||
// point that false start happens.
|
||||
if (expect_resumption_ || !falsestart_enabled_) {
|
||||
if (expect_psk_ == ssl_psk_resume || !falsestart_enabled_) {
|
||||
EXPECT_TRUE(handshake_callback_called_);
|
||||
}
|
||||
|
||||
// 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);
|
||||
EXPECT_EQ(((!expect_resumption_ && have_sni) ||
|
||||
EXPECT_EQ(((expect_psk_ != ssl_psk_resume && have_sni) ||
|
||||
expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3),
|
||||
sni_hook_called_);
|
||||
} else {
|
||||
EXPECT_EQ(!expect_resumption_, auth_certificate_hook_called_);
|
||||
EXPECT_EQ(expect_psk_ == ssl_psk_none, auth_certificate_hook_called_);
|
||||
// Note that this isn't unconditionally called, even with false start on.
|
||||
// But the callback is only skipped if a cipher that is ridiculously weak
|
||||
// (80 bits) is chosen. Don't test that: plan to remove bad ciphers.
|
||||
EXPECT_EQ(falsestart_enabled_ && !expect_resumption_,
|
||||
EXPECT_EQ(falsestart_enabled_ && expect_psk_ != ssl_psk_resume,
|
||||
can_falsestart_hook_called_);
|
||||
}
|
||||
}
|
||||
|
|
@ -845,8 +949,8 @@ void TlsAgent::ResetPreliminaryInfo() {
|
|||
}
|
||||
|
||||
void TlsAgent::UpdatePreliminaryChannelInfo() {
|
||||
SECStatus rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pre_info_,
|
||||
sizeof(pre_info_));
|
||||
SECStatus rv =
|
||||
SSL_GetPreliminaryChannelInfo(ssl_fd(), &pre_info_, sizeof(pre_info_));
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(sizeof(pre_info_), pre_info_.length);
|
||||
}
|
||||
|
|
@ -870,7 +974,7 @@ void TlsAgent::ValidateCipherSpecs() {
|
|||
} else {
|
||||
// For DTLS 1.1 and 1.2, the last endpoint to send maintains a cipher spec
|
||||
// until the holddown timer runs down.
|
||||
if (expect_resumption_) {
|
||||
if (expect_psk_ == ssl_psk_resume) {
|
||||
if (role_ == CLIENT) {
|
||||
expected = 3;
|
||||
}
|
||||
|
|
@ -908,7 +1012,9 @@ void TlsAgent::Connected() {
|
|||
EXPECT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(sizeof(info_), info_.length);
|
||||
|
||||
EXPECT_EQ(expect_resumption_, info_.resumed == PR_TRUE);
|
||||
EXPECT_EQ(expect_psk_ == ssl_psk_resume, info_.resumed == PR_TRUE);
|
||||
EXPECT_EQ(expect_psk_, info_.pskType);
|
||||
EXPECT_EQ(expect_ech_, info_.echAccepted);
|
||||
|
||||
// Preliminary values are exposed through callbacks during the handshake.
|
||||
// If either expected values were set or the callbacks were called, check
|
||||
|
|
@ -926,6 +1032,24 @@ void TlsAgent::Connected() {
|
|||
SetState(STATE_CONNECTED);
|
||||
}
|
||||
|
||||
void TlsAgent::CheckClientAuthCompleted(uint8_t handshakes) {
|
||||
EXPECT_FALSE(client_auth_callback_awaiting_);
|
||||
switch (client_auth_callback_type_) {
|
||||
case ClientAuthCallbackType::kNone:
|
||||
if (!client_auth_callback_success_) {
|
||||
EXPECT_TRUE(CheckClientAuthCallbacksCompleted(0));
|
||||
break;
|
||||
}
|
||||
case ClientAuthCallbackType::kSync:
|
||||
EXPECT_TRUE(CheckClientAuthCallbacksCompleted(handshakes));
|
||||
break;
|
||||
case ClientAuthCallbackType::kAsyncDelay:
|
||||
case ClientAuthCallbackType::kAsyncImmediate:
|
||||
EXPECT_TRUE(CheckClientAuthCallbacksCompleted(2 * handshakes));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TlsAgent::EnableExtendedMasterSecret() {
|
||||
SetOption(SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
|
||||
}
|
||||
|
|
@ -960,6 +1084,10 @@ void TlsAgent::SetDowngradeCheckVersion(uint16_t ver) {
|
|||
void TlsAgent::Handshake() {
|
||||
LOGV("Handshake");
|
||||
SECStatus rv = SSL_ForceHandshake(ssl_fd());
|
||||
if (client_auth_callback_awaiting_) {
|
||||
ClientAuthCallbackComplete();
|
||||
rv = SSL_ForceHandshake(ssl_fd());
|
||||
}
|
||||
if (rv == SECSuccess) {
|
||||
Connected();
|
||||
Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
|
||||
|
|
@ -1063,21 +1191,28 @@ void TlsAgent::SendBuffer(const DataBuffer& buf) {
|
|||
bool TlsAgent::SendEncryptedRecord(const std::shared_ptr<TlsCipherSpec>& spec,
|
||||
uint64_t seq, uint8_t ct,
|
||||
const DataBuffer& buf) {
|
||||
LOGV("Encrypting " << buf.len() << " bytes");
|
||||
// Ensure that we are doing TLS 1.3.
|
||||
EXPECT_GE(expected_version_, SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
TlsRecordHeader header(variant_, expected_version_, ssl_ct_application_data,
|
||||
seq);
|
||||
if (variant_ != ssl_variant_datagram) {
|
||||
ADD_FAILURE();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGV("Encrypting " << buf.len() << " bytes");
|
||||
uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
|
||||
kCtDtlsCiphertextLengthPresent;
|
||||
TlsRecordHeader header(variant_, expected_version_, dtls13_ct, seq);
|
||||
TlsRecordHeader out_header(header);
|
||||
DataBuffer padded = buf;
|
||||
padded.Write(padded.len(), ct, 1);
|
||||
DataBuffer ciphertext;
|
||||
if (!spec->Protect(header, padded, &ciphertext)) {
|
||||
if (!spec->Protect(header, padded, &ciphertext, &out_header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataBuffer record;
|
||||
auto rv = header.Write(&record, 0, ciphertext);
|
||||
EXPECT_EQ(header.header_length() + ciphertext.len(), rv);
|
||||
auto rv = out_header.Write(&record, 0, ciphertext);
|
||||
EXPECT_EQ(out_header.header_length() + ciphertext.len(), rv);
|
||||
SendDirect(record);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1124,7 +1259,7 @@ void TlsAgent::ReadBytes(size_t amount) {
|
|||
}
|
||||
}
|
||||
|
||||
void TlsAgent::ResetSentBytes() { send_ctr_ = 0; }
|
||||
void TlsAgent::ResetSentBytes(size_t bytes) { send_ctr_ = bytes; }
|
||||
|
||||
void TlsAgent::SetOption(int32_t option, int value) {
|
||||
ASSERT_TRUE(EnsureTlsSetup());
|
||||
|
|
@ -1137,9 +1272,9 @@ void TlsAgent::ConfigureSessionCache(SessionResumptionMode mode) {
|
|||
mode & RESUME_TICKET ? PR_TRUE : PR_FALSE);
|
||||
}
|
||||
|
||||
void TlsAgent::DisableECDHEServerKeyReuse() {
|
||||
void TlsAgent::EnableECDHEServerKeyReuse() {
|
||||
ASSERT_EQ(TlsAgent::SERVER, role_);
|
||||
SetOption(SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
|
||||
SetOption(SSL_REUSE_SERVER_ECDHE_KEY, PR_TRUE);
|
||||
}
|
||||
|
||||
static const std::string kTlsRolesAllArr[] = {"CLIENT", "SERVER"};
|
||||
|
|
@ -1201,16 +1336,26 @@ void TlsAgentTestBase::MakeRecord(SSLProtocolVariant variant, uint8_t type,
|
|||
uint16_t version, const uint8_t* buf,
|
||||
size_t len, DataBuffer* out,
|
||||
uint64_t sequence_number) {
|
||||
// Fixup the content type for DTLSCiphertext
|
||||
if (variant == ssl_variant_datagram &&
|
||||
version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
|
||||
type == ssl_ct_application_data) {
|
||||
type = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
|
||||
kCtDtlsCiphertextLengthPresent;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
index = out->Write(index, type, 1);
|
||||
if (variant == ssl_variant_stream) {
|
||||
index = out->Write(index, type, 1);
|
||||
index = out->Write(index, version, 2);
|
||||
} else if (version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
|
||||
type == ssl_ct_application_data) {
|
||||
(type & kCtDtlsCiphertextMask) == kCtDtlsCiphertext) {
|
||||
uint32_t epoch = (sequence_number >> 48) & 0x3;
|
||||
uint32_t seqno = sequence_number & ((1ULL << 30) - 1);
|
||||
index = out->Write(index, (epoch << 30) | seqno, 4);
|
||||
index = out->Write(index, type | epoch, 1);
|
||||
uint32_t seqno = sequence_number & ((1ULL << 16) - 1);
|
||||
index = out->Write(index, seqno, 2);
|
||||
} else {
|
||||
index = out->Write(index, type, 1);
|
||||
index = out->Write(index, TlsVersionToDtlsVersion(version), 2);
|
||||
index = out->Write(index, sequence_number >> 32, 4);
|
||||
index = out->Write(index, sequence_number & PR_UINT32_MAX, 4);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -8,10 +9,12 @@
|
|||
|
||||
#include "prio.h"
|
||||
#include "ssl.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
#include "nss_policy.h"
|
||||
#include "test_io.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
|
|
@ -36,6 +39,13 @@ enum SessionResumptionMode {
|
|||
RESUME_BOTH = RESUME_SESSIONID | RESUME_TICKET
|
||||
};
|
||||
|
||||
enum class ClientAuthCallbackType {
|
||||
kAsyncImmediate,
|
||||
kAsyncDelay,
|
||||
kSync,
|
||||
kNone,
|
||||
};
|
||||
|
||||
class PacketFilter;
|
||||
class TlsAgent;
|
||||
class TlsCipherSpec;
|
||||
|
|
@ -75,8 +85,9 @@ class TlsAgent : public PollTarget {
|
|||
static const std::string kServerEcdhEcdsa;
|
||||
static const std::string kServerEcdhRsa;
|
||||
static const std::string kServerDsa;
|
||||
static const std::string kDelegatorEcdsa256; // draft-ietf-tls-subcerts
|
||||
static const std::string kDelegatorRsae2048; // draft-ietf-tls-subcerts
|
||||
static const std::string kDelegatorEcdsa256; // draft-ietf-tls-subcerts
|
||||
static const std::string kDelegatorRsae2048; // draft-ietf-tls-subcerts
|
||||
static const std::string kDelegatorRsaPss2048; // draft-ietf-tls-subcerts
|
||||
|
||||
TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
|
||||
virtual ~TlsAgent();
|
||||
|
|
@ -140,9 +151,13 @@ class TlsAgent : public PollTarget {
|
|||
bool ConfigServerCertWithChain(const std::string& name);
|
||||
bool EnsureTlsSetup(PRFileDesc* modelSocket = nullptr);
|
||||
|
||||
void SetupClientAuth();
|
||||
void SetupClientAuth(
|
||||
ClientAuthCallbackType callbackType = ClientAuthCallbackType::kSync,
|
||||
bool callbackSuccess = true);
|
||||
void RequestClientAuth(bool requireAuth);
|
||||
|
||||
void ClientAuthCallbackComplete();
|
||||
bool CheckClientAuthCallbacksCompleted(uint8_t expected);
|
||||
void CheckClientAuthCompleted(uint8_t handshakes = 1);
|
||||
void SetOption(int32_t option, int value);
|
||||
void ConfigureSessionCache(SessionResumptionMode mode);
|
||||
void Set0RttEnabled(bool en);
|
||||
|
|
@ -155,6 +170,9 @@ class TlsAgent : public PollTarget {
|
|||
void SetServerKeyBits(uint16_t bits);
|
||||
void ExpectReadWriteError();
|
||||
void EnableFalseStart();
|
||||
void ExpectEch(bool expected = true);
|
||||
bool GetEchExpected() const { return expect_ech_; }
|
||||
void ExpectPsk(SSLPskType psk = ssl_psk_external);
|
||||
void ExpectResumption();
|
||||
void SkipVersionChecks();
|
||||
void SetSignatureSchemes(const SSLSignatureScheme* schemes, size_t count);
|
||||
|
|
@ -174,15 +192,19 @@ class TlsAgent : public PollTarget {
|
|||
// Send data directly to the underlying socket, skipping the TLS layer.
|
||||
void SendDirect(const DataBuffer& buf);
|
||||
void SendRecordDirect(const TlsRecord& record);
|
||||
void AddPsk(const ScopedPK11SymKey& psk, std::string label, SSLHashType hash,
|
||||
uint16_t zeroRttSuite = TLS_NULL_WITH_NULL_NULL);
|
||||
void RemovePsk(std::string label);
|
||||
void ReadBytes(size_t max = 16384U);
|
||||
void ResetSentBytes(); // Hack to test drops.
|
||||
void ResetSentBytes(size_t bytes = 0); // Hack to test drops.
|
||||
void EnableExtendedMasterSecret();
|
||||
void CheckExtendedMasterSecret(bool expected);
|
||||
void CheckEarlyDataAccepted(bool expected);
|
||||
void CheckEchAccepted(bool expected);
|
||||
void SetDowngradeCheckVersion(uint16_t version);
|
||||
void CheckSecretsDestroyed();
|
||||
void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
|
||||
void DisableECDHEServerKeyReuse();
|
||||
void EnableECDHEServerKeyReuse();
|
||||
bool GetPeerChainLength(size_t* count);
|
||||
void CheckCipherSuite(uint16_t cipher_suite);
|
||||
void SetResumptionTokenCallback();
|
||||
|
|
@ -221,7 +243,9 @@ class TlsAgent : public PollTarget {
|
|||
|
||||
static const char* state_str(State state) { return states[state]; }
|
||||
|
||||
PRFileDesc* ssl_fd() const { return ssl_fd_.get(); }
|
||||
NssManagedFileDesc ssl_fd() const {
|
||||
return NssManagedFileDesc(ssl_fd_.get(), policy_, option_);
|
||||
}
|
||||
std::shared_ptr<DummyPrSocket>& adapter() { return adapter_; }
|
||||
|
||||
const SSLChannelInfo& info() const {
|
||||
|
|
@ -246,6 +270,8 @@ class TlsAgent : public PollTarget {
|
|||
return true;
|
||||
}
|
||||
|
||||
void expected_cipher_suite(uint16_t suite) { expected_cipher_suite_ = suite; }
|
||||
|
||||
std::string cipher_suite_name() const {
|
||||
if (state_ != STATE_CONNECTED) return "UNKNOWN";
|
||||
|
||||
|
|
@ -295,6 +321,13 @@ class TlsAgent : public PollTarget {
|
|||
void ExpectSendAlert(uint8_t alert, uint8_t level = 0);
|
||||
|
||||
std::string alpn_value_to_use_ = "";
|
||||
// set the given policy before this agent runs
|
||||
void SetPolicy(SECOidTag oid, PRUint32 set, PRUint32 clear) {
|
||||
policy_ = NssPolicy(oid, set, clear);
|
||||
}
|
||||
void SetNssOption(PRInt32 id, PRInt32 value) {
|
||||
option_ = NssOption(id, value);
|
||||
}
|
||||
|
||||
private:
|
||||
const static char* states[];
|
||||
|
|
@ -416,8 +449,9 @@ class TlsAgent : public PollTarget {
|
|||
bool falsestart_enabled_;
|
||||
uint16_t expected_version_;
|
||||
uint16_t expected_cipher_suite_;
|
||||
bool expect_resumption_;
|
||||
bool expect_client_auth_;
|
||||
bool expect_ech_;
|
||||
SSLPskType expect_psk_;
|
||||
bool can_falsestart_hook_called_;
|
||||
bool sni_hook_called_;
|
||||
bool auth_certificate_hook_called_;
|
||||
|
|
@ -440,6 +474,13 @@ class TlsAgent : public PollTarget {
|
|||
SniCallbackFunction sni_callback_;
|
||||
bool skip_version_checks_;
|
||||
std::vector<uint8_t> resumption_token_;
|
||||
NssPolicy policy_;
|
||||
NssOption option_;
|
||||
ClientAuthCallbackType client_auth_callback_type_ =
|
||||
ClientAuthCallbackType::kNone;
|
||||
bool client_auth_callback_success_ = false;
|
||||
uint8_t client_auth_callback_fired_ = 0;
|
||||
bool client_auth_callback_awaiting_ = false;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -106,7 +107,7 @@ std::string VersionString(uint16_t version) {
|
|||
}
|
||||
|
||||
// The default anti-replay window for tests. Tests that rely on a different
|
||||
// value call SSL_InitAntiReplay directly.
|
||||
// value call ResetAntiReplay directly.
|
||||
static PRTime kAntiReplayWindow = 100 * PR_USEC_PER_SEC;
|
||||
|
||||
TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
|
||||
|
|
@ -194,6 +195,13 @@ void TlsConnectTestBase::SaveAlgorithmPolicy() {
|
|||
ASSERT_EQ(SECSuccess, rv);
|
||||
saved_policies_.push_back(std::make_tuple(*it, policy));
|
||||
}
|
||||
saved_options_.clear();
|
||||
for (auto it : options_) {
|
||||
int32_t option;
|
||||
SECStatus rv = NSS_OptionGet(it, &option);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
saved_options_.push_back(std::make_tuple(it, option));
|
||||
}
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::RestoreAlgorithmPolicy() {
|
||||
|
|
@ -204,6 +212,12 @@ void TlsConnectTestBase::RestoreAlgorithmPolicy() {
|
|||
algorithm, policy, NSS_USE_POLICY_IN_SSL | NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
}
|
||||
for (auto it = saved_options_.begin(); it != saved_options_.end(); ++it) {
|
||||
auto option_id = std::get<0>(*it);
|
||||
auto option = std::get<1>(*it);
|
||||
SECStatus rv = NSS_OptionSet(option_id, option);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
}
|
||||
}
|
||||
|
||||
PRTime TlsConnectTestBase::TimeFunc(void* arg) {
|
||||
|
|
@ -247,6 +261,90 @@ void TlsConnectTestBase::ResetAntiReplay(PRTime window) {
|
|||
anti_replay_.reset(p_anti_replay);
|
||||
}
|
||||
|
||||
ScopedSECItem TlsConnectTestBase::MakeEcKeyParams(SSLNamedGroup group) {
|
||||
auto groupDef = ssl_LookupNamedGroup(group);
|
||||
EXPECT_NE(nullptr, groupDef);
|
||||
|
||||
auto oidData = SECOID_FindOIDByTag(groupDef->oidTag);
|
||||
EXPECT_NE(nullptr, oidData);
|
||||
ScopedSECItem params(
|
||||
SECITEM_AllocItem(nullptr, nullptr, (2 + oidData->oid.len)));
|
||||
EXPECT_TRUE(!!params);
|
||||
params->data[0] = SEC_ASN1_OBJECT_ID;
|
||||
params->data[1] = oidData->oid.len;
|
||||
memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
|
||||
return params;
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::GenerateEchConfig(
|
||||
HpkeKemId kem_id, const std::vector<HpkeSymmetricSuite>& cipher_suites,
|
||||
const std::string& public_name, uint16_t max_name_len, DataBuffer& record,
|
||||
ScopedSECKEYPublicKey& pubKey, ScopedSECKEYPrivateKey& privKey) {
|
||||
bool gen_keys = !pubKey && !privKey;
|
||||
|
||||
SECKEYPublicKey* pub = nullptr;
|
||||
SECKEYPrivateKey* priv = nullptr;
|
||||
|
||||
if (gen_keys) {
|
||||
ScopedSECItem ecParams = MakeEcKeyParams(ssl_grp_ec_curve25519);
|
||||
priv = SECKEY_CreateECPrivateKey(ecParams.get(), &pub, nullptr);
|
||||
} else {
|
||||
priv = privKey.get();
|
||||
pub = pubKey.get();
|
||||
}
|
||||
ASSERT_NE(nullptr, priv);
|
||||
PRUint8 encoded[1024];
|
||||
unsigned int encoded_len = 0;
|
||||
SECStatus rv = SSL_EncodeEchConfigId(
|
||||
77, public_name.c_str(), max_name_len, kem_id, pub, cipher_suites.data(),
|
||||
cipher_suites.size(), encoded, &encoded_len, sizeof(encoded));
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
EXPECT_GT(encoded_len, 0U);
|
||||
|
||||
if (gen_keys) {
|
||||
pubKey.reset(pub);
|
||||
privKey.reset(priv);
|
||||
}
|
||||
record.Truncate(0);
|
||||
record.Write(0, encoded, encoded_len);
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::SetupEch(std::shared_ptr<TlsAgent>& client,
|
||||
std::shared_ptr<TlsAgent>& server,
|
||||
HpkeKemId kem_id, bool expect_ech,
|
||||
bool set_client_config,
|
||||
bool set_server_config, int max_name_len) {
|
||||
EXPECT_TRUE(set_server_config || set_client_config);
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
DataBuffer record;
|
||||
static const std::vector<HpkeSymmetricSuite> kDefaultSuites = {
|
||||
{HpkeKdfHkdfSha256, HpkeAeadChaCha20Poly1305},
|
||||
{HpkeKdfHkdfSha256, HpkeAeadAes128Gcm}};
|
||||
|
||||
GenerateEchConfig(kem_id, kDefaultSuites, "public.name", max_name_len, record,
|
||||
pub, priv);
|
||||
ASSERT_NE(0U, record.len());
|
||||
SECStatus rv;
|
||||
if (set_server_config) {
|
||||
rv = SSL_SetServerEchConfigs(server->ssl_fd(), pub.get(), priv.get(),
|
||||
record.data(), record.len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
}
|
||||
if (set_client_config) {
|
||||
rv = SSL_SetClientEchConfigs(client->ssl_fd(), record.data(), record.len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
}
|
||||
|
||||
/* Filter expect_ech, which typically defaults to true. Parameterized tests
|
||||
* running DTLS or TLS < 1.3 should expect only a non-ECH result. */
|
||||
bool expect = expect_ech && variant_ != ssl_variant_datagram &&
|
||||
version_ >= SSL_LIBRARY_VERSION_TLS_1_3 && set_client_config &&
|
||||
set_server_config;
|
||||
client->ExpectEch(expect);
|
||||
server->ExpectEch(expect);
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::Reset() {
|
||||
// Take a copy of the names because they are about to disappear.
|
||||
std::string server_name = server_->name();
|
||||
|
|
@ -294,10 +392,10 @@ void TlsConnectTestBase::ExpectResumption(SessionResumptionMode expected,
|
|||
}
|
||||
|
||||
void TlsConnectTestBase::EnsureTlsSetup() {
|
||||
EXPECT_TRUE(server_->EnsureTlsSetup(server_model_ ? server_model_->ssl_fd()
|
||||
: nullptr));
|
||||
EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd()
|
||||
: nullptr));
|
||||
EXPECT_TRUE(server_->EnsureTlsSetup(
|
||||
server_model_ ? server_model_->ssl_fd().get() : nullptr));
|
||||
EXPECT_TRUE(client_->EnsureTlsSetup(
|
||||
client_model_ ? client_model_->ssl_fd().get() : nullptr));
|
||||
server_->SetAntiReplayContext(anti_replay_);
|
||||
EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(client_->ssl_fd(),
|
||||
TlsConnectTestBase::TimeFunc, &now_));
|
||||
|
|
@ -374,10 +472,8 @@ void TlsConnectTestBase::CheckConnected() {
|
|||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
|
||||
uint16_t cipher_suite1, cipher_suite2;
|
||||
bool ret = client_->cipher_suite(&cipher_suite1);
|
||||
EXPECT_TRUE(ret);
|
||||
ret = server_->cipher_suite(&cipher_suite2);
|
||||
EXPECT_TRUE(ret);
|
||||
ASSERT_TRUE(client_->cipher_suite(&cipher_suite1));
|
||||
ASSERT_TRUE(server_->cipher_suite(&cipher_suite2));
|
||||
EXPECT_EQ(cipher_suite1, cipher_suite2);
|
||||
|
||||
std::cerr << "Connected with version " << client_->version()
|
||||
|
|
@ -400,6 +496,15 @@ void TlsConnectTestBase::CheckConnected() {
|
|||
server_->CheckSecretsDestroyed();
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::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));
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
|
||||
SSLAuthType auth_type,
|
||||
SSLSignatureScheme sig_scheme) const {
|
||||
|
|
@ -519,6 +624,14 @@ void TlsConnectTestBase::SetExpectedVersion(uint16_t version) {
|
|||
server_->SetExpectedVersion(version);
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::AddPsk(const ScopedPK11SymKey& psk, std::string label,
|
||||
SSLHashType hash, uint16_t zeroRttSuite) {
|
||||
client_->AddPsk(psk, label, hash, zeroRttSuite);
|
||||
server_->AddPsk(psk, label, hash, zeroRttSuite);
|
||||
client_->ExpectPsk();
|
||||
server_->ExpectPsk();
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::DisableAllCiphers() {
|
||||
EnsureTlsSetup();
|
||||
client_->DisableAllCiphers();
|
||||
|
|
@ -755,7 +868,7 @@ void TlsConnectTestBase::ZeroRttSendReceive(
|
|||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
}
|
||||
|
||||
// Do a second read. this should fail.
|
||||
// Do a second read. This should fail.
|
||||
rv = PR_Read(server_->ssl_fd(), buf.data(), k0RttDataLen);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
|
|
@ -787,8 +900,8 @@ void TlsConnectTestBase::CheckEarlyDataAccepted() {
|
|||
server_->CheckEarlyDataAccepted(expect_early_data_accepted_);
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::DisableECDHEServerKeyReuse() {
|
||||
server_->DisableECDHEServerKeyReuse();
|
||||
void TlsConnectTestBase::EnableECDHEServerKeyReuse() {
|
||||
server_->EnableECDHEServerKeyReuse();
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::SkipVersionChecks() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -10,6 +11,7 @@
|
|||
|
||||
#include "sslproto.h"
|
||||
#include "sslt.h"
|
||||
#include "nss.h"
|
||||
|
||||
#include "tls_agent.h"
|
||||
#include "tls_filter.h"
|
||||
|
|
@ -79,6 +81,8 @@ class TlsConnectTestBase : public ::testing::Test {
|
|||
void ConnectExpectAlert(std::shared_ptr<TlsAgent>& sender, uint8_t alert);
|
||||
void ConnectExpectFailOneSide(TlsAgent::Role failingSide);
|
||||
void ConnectWithCipherSuite(uint16_t cipher_suite);
|
||||
void CheckEarlyDataLimit(const std::shared_ptr<TlsAgent>& agent,
|
||||
size_t expected_size);
|
||||
// Check that the keys used in the handshake match expectations.
|
||||
void CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
|
||||
SSLAuthType auth_type, SSLSignatureScheme sig_scheme) const;
|
||||
|
|
@ -119,6 +123,9 @@ class TlsConnectTestBase : public ::testing::Test {
|
|||
void EnableSrtp();
|
||||
void CheckSrtp() const;
|
||||
void SendReceive(size_t total = 50);
|
||||
void AddPsk(const ScopedPK11SymKey& psk, std::string label, SSLHashType hash,
|
||||
uint16_t zeroRttSuite = TLS_NULL_WITH_NULL_NULL);
|
||||
void RemovePsk(std::string label);
|
||||
void SetupForZeroRtt();
|
||||
void SetupForResume();
|
||||
void ZeroRttSendReceive(
|
||||
|
|
@ -127,7 +134,7 @@ class TlsConnectTestBase : public ::testing::Test {
|
|||
void Receive(size_t amount);
|
||||
void ExpectExtendedMasterSecret(bool expected);
|
||||
void ExpectEarlyDataAccepted(bool expected);
|
||||
void DisableECDHEServerKeyReuse();
|
||||
void EnableECDHEServerKeyReuse();
|
||||
void SkipVersionChecks();
|
||||
|
||||
// Move the DTLS timers for both endpoints to pop the next timer.
|
||||
|
|
@ -140,6 +147,17 @@ class TlsConnectTestBase : public ::testing::Test {
|
|||
void SaveAlgorithmPolicy();
|
||||
void RestoreAlgorithmPolicy();
|
||||
|
||||
static ScopedSECItem MakeEcKeyParams(SSLNamedGroup group);
|
||||
static void GenerateEchConfig(
|
||||
HpkeKemId kem_id, const std::vector<HpkeSymmetricSuite>& cipher_suites,
|
||||
const std::string& public_name, uint16_t max_name_len, DataBuffer& record,
|
||||
ScopedSECKEYPublicKey& pubKey, ScopedSECKEYPrivateKey& privKey);
|
||||
void SetupEch(std::shared_ptr<TlsAgent>& client,
|
||||
std::shared_ptr<TlsAgent>& server,
|
||||
HpkeKemId kem_id = HpkeDhKemX25519Sha256,
|
||||
bool expect_ech = true, bool set_client_config = true,
|
||||
bool set_server_config = true, int maxConfigSize = 100);
|
||||
|
||||
protected:
|
||||
SSLProtocolVariant variant_;
|
||||
std::shared_ptr<TlsAgent> client_;
|
||||
|
|
@ -165,6 +183,10 @@ class TlsConnectTestBase : public ::testing::Test {
|
|||
SEC_OID_ANSIX9_DSA_SIGNATURE,
|
||||
SEC_OID_CURVE25519, SEC_OID_SHA1};
|
||||
std::vector<std::tuple<SECOidTag, uint32_t>> saved_policies_;
|
||||
const std::vector<PRInt32> options_ = {
|
||||
NSS_RSA_MIN_KEY_SIZE, NSS_DH_MIN_KEY_SIZE, NSS_DSA_MIN_KEY_SIZE,
|
||||
NSS_TLS_VERSION_MIN_POLICY, NSS_TLS_VERSION_MAX_POLICY};
|
||||
std::vector<std::tuple<PRInt32, uint32_t>> saved_options_;
|
||||
|
||||
private:
|
||||
void CheckResumption(SessionResumptionMode expected);
|
||||
|
|
|
|||
2913
security/nss/gtests/ssl_gtest/tls_ech_unittest.cc
Normal file
2913
security/nss/gtests/ssl_gtest/tls_ech_unittest.cc
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,493 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "gtest_utils.h"
|
||||
#include "tls_agent.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
static const char* kDummySni("dummy.invalid");
|
||||
|
||||
std::vector<uint16_t> kDefaultSuites = {TLS_AES_256_GCM_SHA384,
|
||||
TLS_AES_128_GCM_SHA256};
|
||||
std::vector<uint16_t> kChaChaSuite = {TLS_CHACHA20_POLY1305_SHA256};
|
||||
std::vector<uint16_t> kBogusSuites = {0};
|
||||
std::vector<uint16_t> kTls12Suites = {
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256};
|
||||
|
||||
static void NamedGroup2ECParams(SSLNamedGroup group, SECItem* params) {
|
||||
auto groupDef = ssl_LookupNamedGroup(group);
|
||||
ASSERT_NE(nullptr, groupDef);
|
||||
|
||||
auto oidData = SECOID_FindOIDByTag(groupDef->oidTag);
|
||||
ASSERT_NE(nullptr, oidData);
|
||||
ASSERT_NE(nullptr,
|
||||
SECITEM_AllocItem(nullptr, params, (2 + oidData->oid.len)));
|
||||
|
||||
/*
|
||||
* params->data needs to contain the ASN encoding of an object ID (OID)
|
||||
* representing the named curve. The actual OID is in
|
||||
* oidData->oid.data so we simply prepend 0x06 and OID length
|
||||
*/
|
||||
params->data[0] = SEC_ASN1_OBJECT_ID;
|
||||
params->data[1] = oidData->oid.len;
|
||||
memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
|
||||
}
|
||||
|
||||
/* Checksum is a 4-byte array. */
|
||||
static void UpdateEsniKeysChecksum(DataBuffer* buf) {
|
||||
SECStatus rv;
|
||||
PRUint8 sha256[32];
|
||||
|
||||
/* Stomp the checksum. */
|
||||
PORT_Memset(buf->data() + 2, 0, 4);
|
||||
|
||||
rv = PK11_HashBuf(ssl3_HashTypeToOID(ssl_hash_sha256), sha256, buf->data(),
|
||||
buf->len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
buf->Write(2, sha256, 4);
|
||||
}
|
||||
|
||||
static void GenerateEsniKey(PRTime now, SSLNamedGroup group,
|
||||
std::vector<uint16_t>& cipher_suites,
|
||||
DataBuffer* record,
|
||||
ScopedSECKEYPublicKey* pubKey = nullptr,
|
||||
ScopedSECKEYPrivateKey* privKey = nullptr) {
|
||||
SECKEYECParams ecParams = {siBuffer, NULL, 0};
|
||||
NamedGroup2ECParams(group, &ecParams);
|
||||
|
||||
SECKEYPublicKey* pub = nullptr;
|
||||
SECKEYPrivateKey* priv = SECKEY_CreateECPrivateKey(&ecParams, &pub, nullptr);
|
||||
ASSERT_NE(nullptr, priv);
|
||||
SECITEM_FreeItem(&ecParams, PR_FALSE);
|
||||
PRUint8 encoded[1024];
|
||||
unsigned int encoded_len = 0;
|
||||
|
||||
SECStatus rv = SSL_EncodeESNIKeys(
|
||||
&cipher_suites[0], cipher_suites.size(), group, pub, 100,
|
||||
(now / PR_USEC_PER_SEC) - 1, (now / PR_USEC_PER_SEC) + 10, encoded,
|
||||
&encoded_len, sizeof(encoded));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_GT(encoded_len, 0U);
|
||||
|
||||
if (pubKey) {
|
||||
pubKey->reset(pub);
|
||||
} else {
|
||||
SECKEY_DestroyPublicKey(pub);
|
||||
}
|
||||
if (privKey) {
|
||||
privKey->reset(priv);
|
||||
} else {
|
||||
SECKEY_DestroyPrivateKey(priv);
|
||||
}
|
||||
record->Truncate(0);
|
||||
record->Write(0, encoded, encoded_len);
|
||||
}
|
||||
|
||||
static void SetupEsni(PRTime now, const std::shared_ptr<TlsAgent>& client,
|
||||
const std::shared_ptr<TlsAgent>& server,
|
||||
SSLNamedGroup group = ssl_grp_ec_curve25519) {
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
DataBuffer record;
|
||||
|
||||
GenerateEsniKey(now, ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
|
||||
&priv);
|
||||
SECStatus rv = SSL_SetESNIKeyPair(server->ssl_fd(), priv.get(), record.data(),
|
||||
record.len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = SSL_EnableESNI(client->ssl_fd(), record.data(), record.len(), kDummySni);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
}
|
||||
|
||||
static void CheckSniExtension(const DataBuffer& data) {
|
||||
TlsParser parser(data.data(), data.len());
|
||||
uint32_t tmp;
|
||||
ASSERT_TRUE(parser.Read(&tmp, 2));
|
||||
ASSERT_EQ(parser.remaining(), tmp);
|
||||
ASSERT_TRUE(parser.Read(&tmp, 1));
|
||||
ASSERT_EQ(0U, tmp); /* sni_nametype_hostname */
|
||||
DataBuffer name;
|
||||
ASSERT_TRUE(parser.ReadVariable(&name, 2));
|
||||
ASSERT_EQ(0U, parser.remaining());
|
||||
DataBuffer expected(reinterpret_cast<const uint8_t*>(kDummySni),
|
||||
strlen(kDummySni));
|
||||
ASSERT_EQ(expected, name);
|
||||
}
|
||||
|
||||
class TlsAgentEsniTest : public TlsAgentTestClient13 {
|
||||
public:
|
||||
void SetUp() override { now_ = PR_Now(); }
|
||||
|
||||
protected:
|
||||
PRTime now() const { return now_; }
|
||||
|
||||
void InstallEsni(const DataBuffer& record, PRErrorCode err = 0) {
|
||||
SECStatus rv = SSL_EnableESNI(agent_->ssl_fd(), record.data(), record.len(),
|
||||
kDummySni);
|
||||
if (err == 0) {
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
} else {
|
||||
ASSERT_EQ(SECFailure, rv);
|
||||
ASSERT_EQ(err, PORT_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PRTime now_ = 0;
|
||||
};
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniInstall) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
InstallEsni(record);
|
||||
}
|
||||
|
||||
// The next set of tests fail at setup time.
|
||||
TEST_P(TlsAgentEsniTest, EsniInvalidHash) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.data()[2]++;
|
||||
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniInvalidVersion) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.Write(0, 0xffff, 2);
|
||||
InstallEsni(record, SSL_ERROR_UNSUPPORTED_VERSION);
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniShort) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.Truncate(record.len() - 1);
|
||||
UpdateEsniKeysChecksum(&record);
|
||||
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniLong) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.Write(record.len(), 1, 1);
|
||||
UpdateEsniKeysChecksum(&record);
|
||||
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniExtensionMismatch) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.Write(record.len() - 1, 1, 1);
|
||||
UpdateEsniKeysChecksum(&record);
|
||||
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
|
||||
}
|
||||
|
||||
// The following tests fail by ignoring the Esni block.
|
||||
TEST_P(TlsAgentEsniTest, EsniUnknownGroup) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
record.Write(8, 0xffff, 2); // Fake group
|
||||
UpdateEsniKeysChecksum(&record);
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniUnknownCS) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kBogusSuites, &record);
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniInvalidCS) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kTls12Suites, &record);
|
||||
UpdateEsniKeysChecksum(&record);
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_EQ(TlsAgent::STATE_CONNECTING, agent_->state());
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniNotReady) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now() + 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, EsniExpired) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now() - 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsAgentEsniTest, NoSniSoNoEsni) {
|
||||
EnsureInit();
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
SSL_SetURL(agent_->ssl_fd(), "");
|
||||
InstallEsni(record, 0);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
|
||||
agent_->Handshake();
|
||||
ASSERT_TRUE(!filter->captured());
|
||||
}
|
||||
|
||||
static int32_t SniCallback(TlsAgent* agent, const SECItem* srvNameAddr,
|
||||
PRUint32 srvNameArrSize) {
|
||||
EXPECT_EQ(1U, srvNameArrSize);
|
||||
SECItem expected = {
|
||||
siBuffer, reinterpret_cast<unsigned char*>(const_cast<char*>("server")),
|
||||
6};
|
||||
EXPECT_TRUE(!SECITEM_CompareItem(&expected, &srvNameAddr[0]));
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectEsni) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
auto cFilterSni =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
|
||||
auto cFilterEsni =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_encrypted_sni_xtn);
|
||||
client_->SetFilter(std::make_shared<ChainedPacketFilter>(
|
||||
ChainedPacketFilterInit({cFilterSni, cFilterEsni})));
|
||||
auto sfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_server_name_xtn);
|
||||
sfilter->EnableDecryption();
|
||||
server_->SetSniCallback(SniCallback);
|
||||
Connect();
|
||||
CheckSniExtension(cFilterSni->extension());
|
||||
ASSERT_TRUE(cFilterEsni->captured());
|
||||
// Check that our most preferred suite got chosen.
|
||||
uint32_t suite;
|
||||
ASSERT_TRUE(cFilterEsni->extension().Read(0, 2, &suite));
|
||||
ASSERT_EQ(TLS_AES_128_GCM_SHA256, static_cast<PRUint16>(suite));
|
||||
ASSERT_TRUE(!sfilter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectEsniHrr) {
|
||||
EnsureTlsSetup();
|
||||
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
|
||||
server_->ConfigNamedGroups(groups);
|
||||
SetupEsni(now(), client_, server_);
|
||||
auto hrr_capture = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeHelloRetryRequest);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
|
||||
auto filter2 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn, true);
|
||||
auto efilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_encrypted_sni_xtn);
|
||||
auto efilter2 = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_encrypted_sni_xtn, true);
|
||||
|
||||
client_->SetFilter(std::make_shared<ChainedPacketFilter>(
|
||||
ChainedPacketFilterInit({filter, filter2, efilter, efilter2})));
|
||||
server_->SetSniCallback(SniCallback);
|
||||
Connect();
|
||||
CheckSniExtension(filter->extension());
|
||||
CheckSniExtension(filter2->extension());
|
||||
ASSERT_TRUE(efilter->captured());
|
||||
ASSERT_TRUE(efilter2->captured());
|
||||
ASSERT_NE(efilter->extension(), efilter2->extension());
|
||||
EXPECT_NE(0UL, hrr_capture->buffer().len());
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectEsniNoDummy) {
|
||||
EnsureTlsSetup();
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
DataBuffer record;
|
||||
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
|
||||
&priv);
|
||||
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
|
||||
record.data(), record.len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), "");
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
auto cfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
|
||||
auto sfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_server_name_xtn);
|
||||
server_->SetSniCallback(SniCallback);
|
||||
Connect();
|
||||
ASSERT_TRUE(!cfilter->captured());
|
||||
ASSERT_TRUE(!sfilter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectEsniNullDummy) {
|
||||
EnsureTlsSetup();
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
DataBuffer record;
|
||||
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
|
||||
&priv);
|
||||
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
|
||||
record.data(), record.len());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), nullptr);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
auto cfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
|
||||
auto sfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_server_name_xtn);
|
||||
server_->SetSniCallback(SniCallback);
|
||||
Connect();
|
||||
ASSERT_TRUE(!cfilter->captured());
|
||||
ASSERT_TRUE(!sfilter->captured());
|
||||
}
|
||||
|
||||
/* Tell the client that it supports AES but the server that it supports ChaCha
|
||||
*/
|
||||
TEST_P(TlsConnectTls13, ConnectEsniCSMismatch) {
|
||||
EnsureTlsSetup();
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
DataBuffer record;
|
||||
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
|
||||
&priv);
|
||||
PRUint8 encoded[1024];
|
||||
unsigned int encoded_len = 0;
|
||||
|
||||
SECStatus rv = SSL_EncodeESNIKeys(
|
||||
&kChaChaSuite[0], kChaChaSuite.size(), ssl_grp_ec_curve25519, pub.get(),
|
||||
100, (now() / PR_USEC_PER_SEC) - 1, (now() / PR_USEC_PER_SEC) + 10,
|
||||
encoded, &encoded_len, sizeof(encoded));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_LT(0U, encoded_len);
|
||||
rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(), encoded, encoded_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), "");
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ConnectExpectAlert(server_, illegal_parameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectEsniP256) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_, ssl_grp_ec_secp256r1);
|
||||
auto cfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
|
||||
auto sfilter =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_server_name_xtn);
|
||||
server_->SetSniCallback(SniCallback);
|
||||
Connect();
|
||||
CheckSniExtension(cfilter->extension());
|
||||
ASSERT_TRUE(!sfilter->captured());
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectMismatchedEsniKeys) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
// Now install a new set of keys on the client, so we have a mismatch.
|
||||
DataBuffer record;
|
||||
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
|
||||
|
||||
SECStatus rv =
|
||||
SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), kDummySni);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ConnectExpectAlert(server_, illegal_parameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectDamagedEsniExtensionCH) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
auto filter = MakeTlsFilter<TlsExtensionDamager>(
|
||||
client_, ssl_tls13_encrypted_sni_xtn, 50); // in the ciphertext
|
||||
ConnectExpectAlert(server_, illegal_parameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectRemoveEsniExtensionEE) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_encrypted_sni_xtn);
|
||||
filter->EnableDecryption();
|
||||
ConnectExpectAlert(client_, missing_extension);
|
||||
client_->CheckErrorCode(SSL_ERROR_MISSING_ESNI_EXTENSION);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectShortEsniExtensionEE) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
DataBuffer shortNonce;
|
||||
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_tls13_encrypted_sni_xtn, shortNonce);
|
||||
filter->EnableDecryption();
|
||||
ConnectExpectAlert(client_, illegal_parameter);
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ConnectBogusEsniExtensionEE) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
const uint8_t bogusNonceBuf[16] = {0};
|
||||
DataBuffer bogusNonce(bogusNonceBuf, sizeof(bogusNonceBuf));
|
||||
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_tls13_encrypted_sni_xtn, bogusNonce);
|
||||
filter->EnableDecryption();
|
||||
ConnectExpectAlert(client_, illegal_parameter);
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION);
|
||||
}
|
||||
|
||||
// ESNI is a commitment to doing TLS 1.3 or above.
|
||||
// The TLS 1.2 server ignores ESNI and processes the dummy SNI.
|
||||
// The client then aborts when it sees the server did TLS 1.2.
|
||||
TEST_P(TlsConnectTls13, EsniButTLS12Server) {
|
||||
EnsureTlsSetup();
|
||||
SetupEsni(now(), client_, server_);
|
||||
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);
|
||||
ConnectExpectAlert(client_, kTlsAlertProtocolVersion);
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
|
||||
server_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
|
||||
ASSERT_FALSE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
|
||||
ssl_tls13_encrypted_sni_xtn));
|
||||
}
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -16,6 +17,7 @@ extern "C" {
|
|||
#include "gtest_utils.h"
|
||||
#include "tls_agent.h"
|
||||
#include "tls_filter.h"
|
||||
#include "tls_parser.h"
|
||||
#include "tls_protect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
|
@ -100,13 +102,16 @@ void TlsRecordFilter::SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
|||
SSL_GetCipherSuiteInfo(suite, &cipherinfo, sizeof(cipherinfo)));
|
||||
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);
|
||||
|
||||
bool is_dtls = self->agent()->variant() == ssl_variant_datagram;
|
||||
self->cipher_specs_.emplace_back(is_dtls, epoch);
|
||||
self->cipher_specs_.emplace_back(self->is_dtls_agent(), epoch);
|
||||
EXPECT_TRUE(self->cipher_specs_.back().SetKeys(&cipherinfo, secret));
|
||||
}
|
||||
|
||||
bool TlsRecordFilter::is_dtls_agent() const {
|
||||
return agent()->variant() == ssl_variant_datagram;
|
||||
}
|
||||
|
||||
bool TlsRecordFilter::is_dtls13() const {
|
||||
if (agent()->variant() != ssl_variant_datagram) {
|
||||
if (!is_dtls_agent()) {
|
||||
return false;
|
||||
}
|
||||
if (agent()->state() == TlsAgent::STATE_CONNECTED) {
|
||||
|
|
@ -119,6 +124,10 @@ bool TlsRecordFilter::is_dtls13() const {
|
|||
info.canSendEarlyData;
|
||||
}
|
||||
|
||||
bool TlsRecordFilter::is_dtls13_ciphertext(uint8_t ct) const {
|
||||
return is_dtls13() && (ct & kCtDtlsCiphertextMask) == kCtDtlsCiphertext;
|
||||
}
|
||||
|
||||
// Gets the cipher spec that matches the specified epoch.
|
||||
TlsCipherSpec& TlsRecordFilter::spec(uint16_t write_epoch) {
|
||||
for (auto& sp : cipher_specs_) {
|
||||
|
|
@ -131,8 +140,7 @@ TlsCipherSpec& TlsRecordFilter::spec(uint16_t write_epoch) {
|
|||
// count sequence numbers.
|
||||
EXPECT_FALSE(decrypting_) << "No spec available for epoch " << write_epoch;
|
||||
;
|
||||
bool is_dtls = agent()->variant() == ssl_variant_datagram;
|
||||
cipher_specs_.emplace_back(is_dtls, write_epoch);
|
||||
cipher_specs_.emplace_back(is_dtls_agent(), write_epoch);
|
||||
return cipher_specs_.back();
|
||||
}
|
||||
|
||||
|
|
@ -195,23 +203,24 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
uint16_t protection_epoch = 0;
|
||||
TlsRecordHeader out_header(header);
|
||||
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext)) {
|
||||
&plaintext, &out_header)) {
|
||||
std::cerr << agent()->role_str() << ": unprotect failed: " << header << ":"
|
||||
<< record << std::endl;
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
auto& protection_spec = spec(protection_epoch);
|
||||
TlsRecordHeader real_header(header.variant(), header.version(),
|
||||
inner_content_type, header.sequence_number());
|
||||
TlsRecordHeader real_header(out_header.variant(), out_header.version(),
|
||||
inner_content_type, out_header.sequence_number());
|
||||
|
||||
PacketFilter::Action action = FilterRecord(real_header, plaintext, &filtered);
|
||||
// In stream mode, even if something doesn't change we need to re-encrypt if
|
||||
// previous packets were dropped.
|
||||
if (action == KEEP) {
|
||||
if (header.is_dtls() || !protection_spec.record_dropped()) {
|
||||
if (out_header.is_dtls() || !protection_spec.record_dropped()) {
|
||||
// Count every outgoing packet.
|
||||
protection_spec.RecordProtected();
|
||||
return KEEP;
|
||||
|
|
@ -220,7 +229,7 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
}
|
||||
|
||||
if (action == DROP) {
|
||||
std::cerr << "record drop: " << header << ":" << record << std::endl;
|
||||
std::cerr << "record drop: " << out_header << ":" << record << std::endl;
|
||||
protection_spec.RecordDropped();
|
||||
return DROP;
|
||||
}
|
||||
|
|
@ -232,17 +241,15 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
}
|
||||
|
||||
uint64_t seq_num = protection_spec.next_out_seqno();
|
||||
if (!decrypting_ && header.is_dtls()) {
|
||||
if (!decrypting_ && out_header.is_dtls()) {
|
||||
// Copy over the epoch, which isn't tracked when not decrypting.
|
||||
seq_num |= header.sequence_number() & (0xffffULL << 48);
|
||||
seq_num |= out_header.sequence_number() & (0xffffULL << 48);
|
||||
}
|
||||
|
||||
TlsRecordHeader out_header(header.variant(), header.version(),
|
||||
header.content_type(), seq_num);
|
||||
out_header.sequence_number(seq_num);
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool rv = Protect(protection_spec, out_header, inner_content_type, filtered,
|
||||
&ciphertext);
|
||||
&ciphertext, &out_header);
|
||||
if (!rv) {
|
||||
return KEEP;
|
||||
}
|
||||
|
|
@ -261,19 +268,72 @@ size_t TlsRecordHeader::header_length() const {
|
|||
return WriteHeader(&buf, 0, 0);
|
||||
}
|
||||
|
||||
uint64_t TlsRecordHeader::RecoverSequenceNumber(uint64_t expected,
|
||||
bool TlsRecordHeader::MaskSequenceNumber() {
|
||||
return MaskSequenceNumber(sn_mask());
|
||||
}
|
||||
|
||||
bool TlsRecordHeader::MaskSequenceNumber(const DataBuffer& mask_buf) {
|
||||
if (mask_buf.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataBuffer mask;
|
||||
if (is_dtls13_ciphertext()) {
|
||||
uint64_t seqno = sequence_number();
|
||||
uint8_t len = content_type() & kCtDtlsCiphertext16bSeqno ? 2 : 1;
|
||||
uint16_t seqno_bitmask = (1 << len * 8) - 1;
|
||||
DataBuffer val;
|
||||
if (val.Write(0, seqno & seqno_bitmask, len) != len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef UNSAFE_FUZZER_MODE
|
||||
// Use a null mask.
|
||||
mask.Allocate(mask_buf.len());
|
||||
#endif
|
||||
mask.Append(mask_buf);
|
||||
val.data()[0] ^= mask.data()[0];
|
||||
if (len == 2 && mask.len() > 1) {
|
||||
val.data()[1] ^= mask.data()[1];
|
||||
}
|
||||
uint32_t tmp;
|
||||
if (!val.Read(0, len, &tmp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
seqno = (seqno & ~seqno_bitmask) | tmp;
|
||||
seqno_is_masked_ = !seqno_is_masked_;
|
||||
if (!seqno_is_masked_) {
|
||||
seqno = ParseSequenceNumber(guess_seqno_, seqno, len * 8, 2);
|
||||
}
|
||||
sequence_number_ = seqno;
|
||||
|
||||
// Now update the header bytes
|
||||
if (header_.len() > 1) {
|
||||
header_.data()[1] ^= mask.data()[0];
|
||||
if ((content_type() & kCtDtlsCiphertext16bSeqno) && header().len() > 2) {
|
||||
header_.data()[2] ^= mask.data()[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sn_mask_ = mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t TlsRecordHeader::RecoverSequenceNumber(uint64_t guess_seqno,
|
||||
uint32_t partial,
|
||||
size_t partial_bits) {
|
||||
EXPECT_GE(32U, partial_bits);
|
||||
uint64_t mask = (1ULL << partial_bits) - 1;
|
||||
// First we determine the highest possible value. This is half the
|
||||
// expressible range above the expected value, less 1.
|
||||
// expressible range above the expected value (|guess_seqno|), less 1.
|
||||
//
|
||||
// We subtract the extra 1 from the cap so that when given a choice between
|
||||
// the equidistant expected+N and expected-N we want to chose the lower. With
|
||||
// 0-RTT, we sometimes have to recover an epoch of 1 when we expect an epoch
|
||||
// of 3 and with 2 partial bits, the alternative result of 5 is wrong.
|
||||
uint64_t cap = expected + (1ULL << (partial_bits - 1)) - 1;
|
||||
uint64_t cap = guess_seqno + (1ULL << (partial_bits - 1)) - 1;
|
||||
// Add the partial piece in. e.g., xxxx789a and 1234 becomes xxxx1234.
|
||||
uint64_t seq_no = (cap & ~mask) | partial;
|
||||
// If the partial value is higher than the same partial piece from the cap,
|
||||
|
|
@ -285,15 +345,18 @@ uint64_t TlsRecordHeader::RecoverSequenceNumber(uint64_t expected,
|
|||
}
|
||||
|
||||
// Determine the full epoch and sequence number from an expected and raw value.
|
||||
// The expected and output values are packed as they are in DTLS 1.2 and
|
||||
// earlier: with 16 bits of epoch and 48 bits of sequence number.
|
||||
uint64_t TlsRecordHeader::ParseSequenceNumber(uint64_t expected, uint32_t raw,
|
||||
// The expected, raw, and output values are packed as they are in DTLS 1.2 and
|
||||
// earlier: with 16 bits of epoch and 48 bits of sequence number. The raw value
|
||||
// is packed this way (even before recovery) so that we don't need to track a
|
||||
// moving value between two calls (one to recover the epoch, and one after
|
||||
// unmasking to recover the sequence number).
|
||||
uint64_t TlsRecordHeader::ParseSequenceNumber(uint64_t expected, uint64_t raw,
|
||||
size_t seq_no_bits,
|
||||
size_t epoch_bits) {
|
||||
uint64_t epoch_mask = (1ULL << epoch_bits) - 1;
|
||||
uint64_t epoch = RecoverSequenceNumber(
|
||||
expected >> 48, (raw >> seq_no_bits) & epoch_mask, epoch_bits);
|
||||
if (epoch > (expected >> 48)) {
|
||||
uint64_t ep = RecoverSequenceNumber(expected >> 48, (raw >> 48) & epoch_mask,
|
||||
epoch_bits);
|
||||
if (ep > (expected >> 48)) {
|
||||
// If the epoch has changed, reset the expected sequence number.
|
||||
expected = 0;
|
||||
} else {
|
||||
|
|
@ -301,9 +364,12 @@ uint64_t TlsRecordHeader::ParseSequenceNumber(uint64_t expected, uint32_t raw,
|
|||
expected &= (1ULL << 48) - 1;
|
||||
}
|
||||
uint64_t seq_no_mask = (1ULL << seq_no_bits) - 1;
|
||||
uint64_t seq_no =
|
||||
RecoverSequenceNumber(expected, raw & seq_no_mask, seq_no_bits);
|
||||
return (epoch << 48) | seq_no;
|
||||
uint64_t seq_no = (raw & seq_no_mask);
|
||||
if (!seqno_is_masked_) {
|
||||
seq_no = RecoverSequenceNumber(expected, seq_no, seq_no_bits);
|
||||
}
|
||||
|
||||
return (ep << 48) | seq_no;
|
||||
}
|
||||
|
||||
bool TlsRecordHeader::Parse(bool is_dtls13, uint64_t seqno, TlsParser* parser,
|
||||
|
|
@ -319,38 +385,47 @@ bool TlsRecordHeader::Parse(bool is_dtls13, uint64_t seqno, TlsParser* parser,
|
|||
version_ = SSL_LIBRARY_VERSION_TLS_1_3;
|
||||
|
||||
#ifndef UNSAFE_FUZZER_MODE
|
||||
// Deal with the 7 octet header.
|
||||
if (content_type_ == ssl_ct_application_data) {
|
||||
// Deal with the DTLSCipherText header.
|
||||
if (is_dtls13_ciphertext()) {
|
||||
uint8_t seq_no_bytes =
|
||||
(content_type_ & kCtDtlsCiphertext16bSeqno) ? 2 : 1;
|
||||
uint32_t tmp;
|
||||
if (!parser->Read(&tmp, 4)) {
|
||||
return false;
|
||||
}
|
||||
sequence_number_ = ParseSequenceNumber(seqno, tmp, 30, 2);
|
||||
if (!parser->ReadFromMark(&header_, parser->consumed() + 2 - mark,
|
||||
mark)) {
|
||||
return false;
|
||||
}
|
||||
return parser->ReadVariable(body, 2);
|
||||
}
|
||||
|
||||
// The short, 2 octet header.
|
||||
if ((content_type_ & 0xe0) == 0x20) {
|
||||
uint32_t tmp;
|
||||
if (!parser->Read(&tmp, 1)) {
|
||||
if (!parser->Read(&tmp, seq_no_bytes)) {
|
||||
return false;
|
||||
}
|
||||
// Need to use the low 5 bits of the first octet too.
|
||||
tmp |= (content_type_ & 0x1f) << 8;
|
||||
content_type_ = ssl_ct_application_data;
|
||||
sequence_number_ = ParseSequenceNumber(seqno, tmp, 12, 1);
|
||||
|
||||
// Store the guess if masked. If and when seqno_bytesenceNumber is called,
|
||||
// the value will be unmasked and recovered. This assumes we only call
|
||||
// Parse() on headers containing masked values.
|
||||
seqno_is_masked_ = true;
|
||||
guess_seqno_ = seqno;
|
||||
uint64_t ep = content_type_ & 0x03;
|
||||
sequence_number_ = (ep << 48) | tmp;
|
||||
|
||||
// Recover the full epoch. Note the sequence number portion holds the
|
||||
// masked value until a call to Mask() reveals it (as indicated by
|
||||
// |seqno_is_masked_|).
|
||||
sequence_number_ =
|
||||
ParseSequenceNumber(seqno, sequence_number_, seq_no_bytes * 8, 2);
|
||||
|
||||
uint32_t len_bytes =
|
||||
(content_type_ & kCtDtlsCiphertextLengthPresent) ? 2 : 0;
|
||||
if (len_bytes) {
|
||||
if (!parser->Read(&tmp, 2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parser->ReadFromMark(&header_, parser->consumed() - mark, mark)) {
|
||||
return false;
|
||||
}
|
||||
return parser->Read(body, parser->remaining());
|
||||
|
||||
return len_bytes ? parser->Read(body, tmp)
|
||||
: parser->Read(body, parser->remaining());
|
||||
}
|
||||
|
||||
// The full 13 octet header can only be used for a few types.
|
||||
// The full DTLSPlainText header can only be used for a few types.
|
||||
EXPECT_TRUE(content_type_ == ssl_ct_alert ||
|
||||
content_type_ == ssl_ct_handshake ||
|
||||
content_type_ == ssl_ct_ack);
|
||||
|
|
@ -388,15 +463,20 @@ bool TlsRecordHeader::Parse(bool is_dtls13, uint64_t seqno, TlsParser* parser,
|
|||
|
||||
size_t TlsRecordHeader::WriteHeader(DataBuffer* buffer, size_t offset,
|
||||
size_t body_len) const {
|
||||
offset = buffer->Write(offset, content_type_, 1);
|
||||
if (is_dtls() && version_ >= SSL_LIBRARY_VERSION_TLS_1_3 &&
|
||||
content_type() == ssl_ct_application_data) {
|
||||
if (is_dtls13_ciphertext()) {
|
||||
uint8_t seq_no_bytes = (content_type_ & kCtDtlsCiphertext16bSeqno) ? 2 : 1;
|
||||
// application_data records in TLS 1.3 have a different header format.
|
||||
// Always use the long header here for simplicity.
|
||||
uint32_t e = (sequence_number_ >> 48) & 0x3;
|
||||
uint32_t seqno = sequence_number_ & ((1ULL << 30) - 1);
|
||||
offset = buffer->Write(offset, (e << 30) | seqno, 4);
|
||||
uint32_t seqno = sequence_number_ & ((1ULL << seq_no_bytes * 8) - 1);
|
||||
uint8_t new_content_type_ = content_type_ | e;
|
||||
offset = buffer->Write(offset, new_content_type_, 1);
|
||||
offset = buffer->Write(offset, seqno, seq_no_bytes);
|
||||
|
||||
if (content_type_ & kCtDtlsCiphertextLengthPresent) {
|
||||
offset = buffer->Write(offset, body_len, 2);
|
||||
}
|
||||
} else {
|
||||
offset = buffer->Write(offset, content_type_, 1);
|
||||
uint16_t v = is_dtls() ? TlsVersionToDtlsVersion(version_) : version_;
|
||||
offset = buffer->Write(offset, v, 2);
|
||||
if (is_dtls()) {
|
||||
|
|
@ -404,8 +484,9 @@ size_t TlsRecordHeader::WriteHeader(DataBuffer* buffer, size_t offset,
|
|||
offset = buffer->Write(offset, sequence_number_ >> 32, 4);
|
||||
offset = buffer->Write(offset, sequence_number_ & 0xffffffff, 4);
|
||||
}
|
||||
offset = buffer->Write(offset, body_len, 2);
|
||||
}
|
||||
offset = buffer->Write(offset, body_len, 2);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
|
@ -420,11 +501,12 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
|||
const DataBuffer& ciphertext,
|
||||
uint16_t* protection_epoch,
|
||||
uint8_t* inner_content_type,
|
||||
DataBuffer* plaintext) {
|
||||
if (!decrypting_ || header.content_type() != ssl_ct_application_data) {
|
||||
DataBuffer* plaintext,
|
||||
TlsRecordHeader* out_header) {
|
||||
if (!decrypting_ || !header.is_protected()) {
|
||||
// Maintain the epoch and sequence number for plaintext records.
|
||||
uint16_t ep = 0;
|
||||
if (agent()->variant() == ssl_variant_datagram) {
|
||||
if (is_dtls_agent()) {
|
||||
ep = static_cast<uint16_t>(header.sequence_number() >> 48);
|
||||
}
|
||||
spec(ep).RecordUnprotected(header.sequence_number());
|
||||
|
|
@ -435,9 +517,9 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
|||
}
|
||||
|
||||
uint16_t ep = 0;
|
||||
if (agent()->variant() == ssl_variant_datagram) {
|
||||
if (is_dtls_agent()) {
|
||||
ep = static_cast<uint16_t>(header.sequence_number() >> 48);
|
||||
if (!spec(ep).Unprotect(header, ciphertext, plaintext)) {
|
||||
if (!spec(ep).Unprotect(header, ciphertext, plaintext, out_header)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -445,7 +527,8 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
|||
// can't just use the newest keys because the same flight of messages can
|
||||
// contain multiple epochs. So... trial decrypt!
|
||||
for (size_t i = cipher_specs_.size() - 1; i > 0; --i) {
|
||||
if (cipher_specs_[i].Unprotect(header, ciphertext, plaintext)) {
|
||||
if (cipher_specs_[i].Unprotect(header, ciphertext, plaintext,
|
||||
out_header)) {
|
||||
ep = cipher_specs_[i].epoch();
|
||||
break;
|
||||
}
|
||||
|
|
@ -480,7 +563,8 @@ bool TlsRecordFilter::Protect(TlsCipherSpec& protection_spec,
|
|||
const TlsRecordHeader& header,
|
||||
uint8_t inner_content_type,
|
||||
const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext, size_t padding) {
|
||||
DataBuffer* ciphertext,
|
||||
TlsRecordHeader* out_header, size_t padding) {
|
||||
if (!protection_spec.is_protected()) {
|
||||
// Not protected, just keep the sequence numbers updated.
|
||||
protection_spec.RecordProtected();
|
||||
|
|
@ -493,7 +577,7 @@ bool TlsRecordFilter::Protect(TlsCipherSpec& protection_spec,
|
|||
size_t offset = padded.Write(0, plaintext.data(), plaintext.len());
|
||||
padded.Write(offset, inner_content_type, 1);
|
||||
|
||||
bool ok = protection_spec.Protect(header, padded, ciphertext);
|
||||
bool ok = protection_spec.Protect(header, padded, ciphertext, out_header);
|
||||
if (!ok) {
|
||||
ADD_FAILURE() << "protect fail";
|
||||
} else if (g_ssl_gtest_verbose) {
|
||||
|
|
@ -931,6 +1015,12 @@ PacketFilter::Action TlsExtensionFilter::FilterExtensions(
|
|||
return KEEP;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsExtensionOrderCapture::FilterExtension(
|
||||
uint16_t extension_type, const DataBuffer& input, DataBuffer* output) {
|
||||
order.push_back(extension_type);
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsExtensionCapture::FilterExtension(
|
||||
uint16_t extension_type, const DataBuffer& input, DataBuffer* output) {
|
||||
if (extension_type == extension_ && (last_ || !captured_)) {
|
||||
|
|
@ -950,6 +1040,69 @@ PacketFilter::Action TlsExtensionReplacer::FilterExtension(
|
|||
return CHANGE;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsExtensionResizer::FilterExtension(
|
||||
uint16_t extension_type, const DataBuffer& input, DataBuffer* output) {
|
||||
if (extension_type != extension_) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
if (input.len() <= length_) {
|
||||
DataBuffer buf(length_ - input.len());
|
||||
output->Append(buf);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
output->Assign(input.data(), length_);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsExtensionAppender::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
TlsParser parser(input);
|
||||
if (!TlsExtensionFilter::FindExtensions(&parser, header)) {
|
||||
return KEEP;
|
||||
}
|
||||
*output = input;
|
||||
|
||||
// Increase the length of the extensions block.
|
||||
if (!UpdateLength(output, parser.consumed(), 2)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
// Extensions in Certificate are nested twice. Increase the size of the
|
||||
// certificate list.
|
||||
if (header.handshake_type() == kTlsHandshakeCertificate) {
|
||||
TlsParser p2(input);
|
||||
if (!p2.SkipVariable(1)) {
|
||||
ADD_FAILURE();
|
||||
return KEEP;
|
||||
}
|
||||
if (!UpdateLength(output, p2.consumed(), 3)) {
|
||||
return KEEP;
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset = output->len();
|
||||
offset = output->Write(offset, extension_, 2);
|
||||
WriteVariable(output, offset, data_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
bool TlsExtensionAppender::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;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsExtensionDropper::FilterExtension(
|
||||
uint16_t extension_type, const DataBuffer& input, DataBuffer* output) {
|
||||
if (extension_type == extension_) {
|
||||
|
|
@ -1052,15 +1205,7 @@ PacketFilter::Action SelectiveRecordDropFilter::FilterRecord(
|
|||
return pattern;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsClientHelloVersionSetter::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
output->Write(0, version_, 2);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsServerHelloVersionSetter::FilterHandshake(
|
||||
PacketFilter::Action TlsMessageVersionSetter::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
|
|
@ -1074,15 +1219,75 @@ PacketFilter::Action SelectedCipherSuiteReplacer::FilterHandshake(
|
|||
*output = input;
|
||||
uint32_t temp = 0;
|
||||
EXPECT_TRUE(input.Read(0, 2, &temp));
|
||||
// Cipher suite is after version(2) and random(32).
|
||||
EXPECT_EQ(header.version(), NormalizeTlsVersion(temp));
|
||||
// Cipher suite is after version(2), random(32)
|
||||
// and [legacy_]session_id(<0..32>).
|
||||
size_t pos = 34;
|
||||
if (temp < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// In old versions, we have to skip a session_id too.
|
||||
EXPECT_TRUE(input.Read(pos, 1, &temp));
|
||||
pos += 1 + temp;
|
||||
}
|
||||
EXPECT_TRUE(input.Read(pos, 1, &temp));
|
||||
pos += 1 + temp;
|
||||
|
||||
output->Write(pos, static_cast<uint32_t>(cipher_suite_), 2);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
PacketFilter::Action ServerHelloRandomChanger::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
uint32_t temp = 0;
|
||||
size_t pos = 30;
|
||||
EXPECT_TRUE(input.Read(pos, 2, &temp));
|
||||
output->Write(pos, (temp ^ 0xffff), 2);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
PacketFilter::Action ClientHelloPreambleCapture::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
EXPECT_TRUE(header.handshake_type() == kTlsHandshakeClientHello);
|
||||
|
||||
if (captured_) {
|
||||
return KEEP;
|
||||
}
|
||||
captured_ = true;
|
||||
|
||||
DataBuffer temp;
|
||||
TlsParser parser(input);
|
||||
EXPECT_TRUE(parser.Read(&temp, 2 + 32)); // Version + Random
|
||||
EXPECT_TRUE(parser.ReadVariable(&temp, 1)); // Session ID
|
||||
if (is_dtls_agent()) {
|
||||
EXPECT_TRUE(parser.ReadVariable(&temp, 1)); // Cookie
|
||||
}
|
||||
EXPECT_TRUE(parser.ReadVariable(&temp, 2)); // Ciphersuites
|
||||
EXPECT_TRUE(parser.ReadVariable(&temp, 1)); // Compression
|
||||
|
||||
// Copy the preamble into a new buffer
|
||||
data_ = input;
|
||||
data_.Truncate(parser.consumed());
|
||||
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
PacketFilter::Action ClientHelloCiphersuiteCapture::FilterHandshake(
|
||||
const HandshakeHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
EXPECT_TRUE(header.handshake_type() == kTlsHandshakeClientHello);
|
||||
|
||||
if (captured_) {
|
||||
return KEEP;
|
||||
}
|
||||
captured_ = true;
|
||||
|
||||
TlsParser parser(input);
|
||||
EXPECT_TRUE(parser.Skip(2 + 32)); // Version + Random
|
||||
EXPECT_TRUE(parser.SkipVariable(1)); // Session ID
|
||||
if (is_dtls_agent()) {
|
||||
EXPECT_TRUE(parser.SkipVariable(1)); // Cookie
|
||||
}
|
||||
|
||||
EXPECT_TRUE(parser.ReadVariable(&data_, 2)); // Ciphersuites
|
||||
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -10,7 +11,9 @@
|
|||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "pk11pub.h"
|
||||
#include "sslt.h"
|
||||
#include "sslproto.h"
|
||||
#include "test_io.h"
|
||||
#include "tls_agent.h"
|
||||
#include "tls_parser.h"
|
||||
|
|
@ -24,6 +27,59 @@ namespace nss_test {
|
|||
|
||||
class TlsCipherSpec;
|
||||
|
||||
class TlsSendCipherSpecCapturer {
|
||||
public:
|
||||
TlsSendCipherSpecCapturer(const std::shared_ptr<TlsAgent>& agent)
|
||||
: agent_(agent), send_cipher_specs_() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_SecretCallback(agent_->ssl_fd(), SecretCallback, this));
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsCipherSpec> spec(size_t i) {
|
||||
if (i >= send_cipher_specs_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return send_cipher_specs_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
static void SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLSecretDirection dir, PK11SymKey* secret,
|
||||
void* arg) {
|
||||
auto self = static_cast<TlsSendCipherSpecCapturer*>(arg);
|
||||
std::cerr << self->agent_->role_str() << ": capture " << dir
|
||||
<< " secret for epoch " << epoch << std::endl;
|
||||
|
||||
if (dir == ssl_secret_read) {
|
||||
return;
|
||||
}
|
||||
|
||||
SSLPreliminaryChannelInfo preinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetPreliminaryChannelInfo(self->agent_->ssl_fd(), &preinfo,
|
||||
sizeof(preinfo)));
|
||||
EXPECT_EQ(sizeof(preinfo), preinfo.length);
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
|
||||
|
||||
// Check the version:
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_version);
|
||||
ASSERT_GE(SSL_LIBRARY_VERSION_TLS_1_3, preinfo.protocolVersion);
|
||||
|
||||
SSLCipherSuiteInfo cipherinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetCipherSuiteInfo(preinfo.cipherSuite, &cipherinfo,
|
||||
sizeof(cipherinfo)));
|
||||
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);
|
||||
|
||||
auto spec = std::make_shared<TlsCipherSpec>(true, epoch);
|
||||
EXPECT_TRUE(spec->SetKeys(&cipherinfo, secret));
|
||||
self->send_cipher_specs_.push_back(spec);
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent> agent_;
|
||||
std::vector<std::shared_ptr<TlsCipherSpec>> send_cipher_specs_;
|
||||
};
|
||||
|
||||
class TlsVersioned {
|
||||
public:
|
||||
TlsVersioned() : variant_(ssl_variant_stream), version_(0) {}
|
||||
|
|
@ -44,22 +100,57 @@ class TlsVersioned {
|
|||
class TlsRecordHeader : public TlsVersioned {
|
||||
public:
|
||||
TlsRecordHeader()
|
||||
: TlsVersioned(), content_type_(0), sequence_number_(0), header_() {}
|
||||
: TlsVersioned(),
|
||||
content_type_(0),
|
||||
guess_seqno_(0),
|
||||
seqno_is_masked_(false),
|
||||
sequence_number_(0),
|
||||
header_() {}
|
||||
TlsRecordHeader(SSLProtocolVariant var, uint16_t ver, uint8_t ct,
|
||||
uint64_t seqno)
|
||||
: TlsVersioned(var, ver),
|
||||
content_type_(ct),
|
||||
guess_seqno_(0),
|
||||
seqno_is_masked_(false),
|
||||
sequence_number_(seqno),
|
||||
header_() {}
|
||||
header_(),
|
||||
sn_mask_() {}
|
||||
|
||||
bool is_protected() const {
|
||||
// *TLS < 1.3
|
||||
if (version() < SSL_LIBRARY_VERSION_TLS_1_3 &&
|
||||
content_type() == ssl_ct_application_data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TLS 1.3
|
||||
if (!is_dtls() && version() >= SSL_LIBRARY_VERSION_TLS_1_3 &&
|
||||
content_type() == ssl_ct_application_data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// DTLS 1.3
|
||||
return is_dtls13_ciphertext();
|
||||
}
|
||||
|
||||
uint8_t content_type() const { return content_type_; }
|
||||
uint64_t sequence_number() const { return sequence_number_; }
|
||||
uint16_t epoch() const {
|
||||
return static_cast<uint16_t>(sequence_number_ >> 48);
|
||||
}
|
||||
uint64_t sequence_number() const { return sequence_number_; }
|
||||
void sequence_number(uint64_t seqno) { sequence_number_ = seqno; }
|
||||
const DataBuffer& sn_mask() const { return sn_mask_; }
|
||||
bool is_dtls13_ciphertext() const {
|
||||
return is_dtls() && (version() >= SSL_LIBRARY_VERSION_TLS_1_3) &&
|
||||
(content_type() & kCtDtlsCiphertextMask) == kCtDtlsCiphertext;
|
||||
}
|
||||
|
||||
size_t header_length() const;
|
||||
const DataBuffer& header() const { return header_; }
|
||||
|
||||
bool MaskSequenceNumber();
|
||||
bool MaskSequenceNumber(const DataBuffer& mask_buf);
|
||||
|
||||
// Parse the header; return true if successful; body in an outparam if OK.
|
||||
bool Parse(bool is_dtls13, uint64_t sequence_number, TlsParser* parser,
|
||||
DataBuffer* body);
|
||||
|
|
@ -69,14 +160,17 @@ class TlsRecordHeader : public TlsVersioned {
|
|||
size_t WriteHeader(DataBuffer* buffer, size_t offset, size_t body_len) const;
|
||||
|
||||
private:
|
||||
static uint64_t RecoverSequenceNumber(uint64_t expected, uint32_t partial,
|
||||
static uint64_t RecoverSequenceNumber(uint64_t guess_seqno, uint32_t partial,
|
||||
size_t partial_bits);
|
||||
static uint64_t ParseSequenceNumber(uint64_t expected, uint32_t raw,
|
||||
size_t seq_no_bits, size_t epoch_bits);
|
||||
uint64_t ParseSequenceNumber(uint64_t expected, uint64_t raw,
|
||||
size_t seq_no_bits, size_t epoch_bits);
|
||||
|
||||
uint8_t content_type_;
|
||||
uint64_t guess_seqno_;
|
||||
bool seqno_is_masked_;
|
||||
uint64_t sequence_number_;
|
||||
DataBuffer header_;
|
||||
DataBuffer sn_mask_;
|
||||
};
|
||||
|
||||
struct TlsRecord {
|
||||
|
|
@ -110,12 +204,14 @@ class TlsRecordFilter : public PacketFilter {
|
|||
// Enabling it for lower version tests will cause undefined
|
||||
// behavior.
|
||||
void EnableDecryption();
|
||||
bool decrypting() const { return decrypting_; };
|
||||
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
|
||||
uint16_t* protection_epoch, uint8_t* inner_content_type,
|
||||
DataBuffer* plaintext);
|
||||
DataBuffer* plaintext, TlsRecordHeader* out_header);
|
||||
bool Protect(TlsCipherSpec& protection_spec, const TlsRecordHeader& header,
|
||||
uint8_t inner_content_type, const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext, size_t padding = 0);
|
||||
DataBuffer* ciphertext, TlsRecordHeader* out_header,
|
||||
size_t padding = 0);
|
||||
|
||||
protected:
|
||||
// There are two filter functions which can be overriden. Both are
|
||||
|
|
@ -139,7 +235,9 @@ class TlsRecordFilter : public PacketFilter {
|
|||
return KEEP;
|
||||
}
|
||||
|
||||
bool is_dtls_agent() const;
|
||||
bool is_dtls13() const;
|
||||
bool is_dtls13_ciphertext(uint8_t ct) const;
|
||||
TlsCipherSpec& spec(uint16_t epoch);
|
||||
|
||||
private:
|
||||
|
|
@ -390,6 +488,19 @@ class TlsExtensionFilter : public TlsHandshakeFilter {
|
|||
DataBuffer* output);
|
||||
};
|
||||
|
||||
class TlsExtensionOrderCapture : public TlsExtensionFilter {
|
||||
public:
|
||||
TlsExtensionOrderCapture(const std::shared_ptr<TlsAgent>& a, uint8_t message)
|
||||
: TlsExtensionFilter(a, {message}){};
|
||||
|
||||
std::vector<uint16_t> order;
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterExtension(uint16_t extension_type,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) override;
|
||||
};
|
||||
|
||||
class TlsExtensionCapture : public TlsExtensionFilter {
|
||||
public:
|
||||
TlsExtensionCapture(const std::shared_ptr<TlsAgent>& a, uint16_t ext,
|
||||
|
|
@ -429,6 +540,37 @@ class TlsExtensionReplacer : public TlsExtensionFilter {
|
|||
const DataBuffer data_;
|
||||
};
|
||||
|
||||
class TlsExtensionResizer : public TlsExtensionFilter {
|
||||
public:
|
||||
TlsExtensionResizer(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
|
||||
size_t length)
|
||||
: TlsExtensionFilter(a), extension_(extension), length_(length) {}
|
||||
PacketFilter::Action FilterExtension(uint16_t extension_type,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) override;
|
||||
|
||||
private:
|
||||
uint16_t extension_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
class TlsExtensionAppender : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsExtensionAppender(const std::shared_ptr<TlsAgent>& a,
|
||||
uint8_t handshake_type, uint16_t ext, DataBuffer& data)
|
||||
: TlsHandshakeFilter(a, {handshake_type}), extension_(ext), data_(data) {}
|
||||
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output);
|
||||
|
||||
private:
|
||||
bool UpdateLength(DataBuffer* output, size_t offset, size_t size);
|
||||
|
||||
const uint16_t extension_;
|
||||
const DataBuffer data_;
|
||||
};
|
||||
|
||||
class TlsExtensionDropper : public TlsExtensionFilter {
|
||||
public:
|
||||
TlsExtensionDropper(const std::shared_ptr<TlsAgent>& a, uint16_t extension)
|
||||
|
|
@ -470,8 +612,9 @@ class TlsEncryptedHandshakeMessageReplacer : public TlsRecordFilter {
|
|||
uint16_t protection_epoch = 0;
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
TlsRecordHeader out_header;
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext) ||
|
||||
&plaintext, &out_header) ||
|
||||
!plaintext.len()) {
|
||||
return KEEP;
|
||||
}
|
||||
|
|
@ -500,12 +643,12 @@ class TlsEncryptedHandshakeMessageReplacer : public TlsRecordFilter {
|
|||
}
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool ok = Protect(spec(protection_epoch), header, inner_content_type,
|
||||
plaintext, &ciphertext, 0);
|
||||
bool ok = Protect(spec(protection_epoch), out_header, inner_content_type,
|
||||
plaintext, &ciphertext, &out_header);
|
||||
if (!ok) {
|
||||
return KEEP;
|
||||
}
|
||||
*offset = header.Write(output, *offset, ciphertext);
|
||||
*offset = out_header.Write(output, *offset, ciphertext);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
|
|
@ -654,27 +797,16 @@ class SelectiveRecordDropFilter : public TlsRecordFilter {
|
|||
uint8_t counter_;
|
||||
};
|
||||
|
||||
// Set the version number in the ClientHello.
|
||||
class TlsClientHelloVersionSetter : public TlsHandshakeFilter {
|
||||
// Set the version value in the ClientHello, ServerHello or HelloRetryRequest
|
||||
class TlsMessageVersionSetter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsClientHelloVersionSetter(const std::shared_ptr<TlsAgent>& a,
|
||||
uint16_t version)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeClientHello}), version_(version) {}
|
||||
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output);
|
||||
|
||||
private:
|
||||
uint16_t version_;
|
||||
};
|
||||
|
||||
// Set the version number in the ServerHello.
|
||||
class TlsServerHelloVersionSetter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsServerHelloVersionSetter(const std::shared_ptr<TlsAgent>& a,
|
||||
uint16_t version)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeServerHello}), version_(version) {}
|
||||
TlsMessageVersionSetter(const std::shared_ptr<TlsAgent>& a, uint8_t message,
|
||||
uint16_t version)
|
||||
: TlsHandshakeFilter(a, {message}), version_(version) {
|
||||
PR_ASSERT(message == kTlsHandshakeClientHello ||
|
||||
message == kTlsHandshakeServerHello ||
|
||||
message == kTlsHandshakeHelloRetryRequest);
|
||||
}
|
||||
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
|
|
@ -722,6 +854,160 @@ class SelectedCipherSuiteReplacer : public TlsHandshakeFilter {
|
|||
uint16_t cipher_suite_;
|
||||
};
|
||||
|
||||
class ClientHelloPreambleCapture : public TlsHandshakeFilter {
|
||||
public:
|
||||
ClientHelloPreambleCapture(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeClientHello}),
|
||||
captured_(false),
|
||||
data_() {}
|
||||
|
||||
const DataBuffer& contents() const { return data_; }
|
||||
bool captured() const { return captured_; }
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) override;
|
||||
|
||||
private:
|
||||
bool captured_;
|
||||
DataBuffer data_;
|
||||
};
|
||||
|
||||
class ClientHelloCiphersuiteCapture : public TlsHandshakeFilter {
|
||||
public:
|
||||
ClientHelloCiphersuiteCapture(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeClientHello}),
|
||||
captured_(false),
|
||||
data_() {}
|
||||
|
||||
const DataBuffer& contents() const { return data_; }
|
||||
bool captured() const { return captured_; }
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) override;
|
||||
|
||||
private:
|
||||
bool captured_;
|
||||
DataBuffer data_;
|
||||
};
|
||||
|
||||
class ServerHelloRandomChanger : public TlsHandshakeFilter {
|
||||
public:
|
||||
ServerHelloRandomChanger(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeServerHello}) {}
|
||||
|
||||
protected:
|
||||
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) override;
|
||||
};
|
||||
|
||||
// Replace SignatureAndHashAlgorithm of a SKE.
|
||||
class DHEServerKEXSigAlgReplacer : public TlsHandshakeFilter {
|
||||
public:
|
||||
DHEServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent>& server,
|
||||
uint16_t sig_scheme)
|
||||
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
||||
sig_scheme_(sig_scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
|
||||
uint32_t len;
|
||||
uint32_t idx = 0;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
EXPECT_TRUE(output->Read(idx, 2, &len));
|
||||
idx += 2 + len;
|
||||
output->Write(idx, sig_scheme_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t sig_scheme_;
|
||||
};
|
||||
|
||||
// Replace SignatureAndHashAlgorithm of a SKE.
|
||||
class ECCServerKEXSigAlgReplacer : public TlsHandshakeFilter {
|
||||
public:
|
||||
ECCServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent>& server,
|
||||
uint16_t sig_scheme)
|
||||
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
||||
sig_scheme_(sig_scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
|
||||
uint32_t point_len;
|
||||
EXPECT_TRUE(output->Read(3, 1, &point_len));
|
||||
output->Write(4 + point_len, sig_scheme_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t sig_scheme_;
|
||||
};
|
||||
|
||||
// Replace NamedCurve of a ECDHE SKE.
|
||||
class ECCServerKEXNamedCurveReplacer : public TlsHandshakeFilter {
|
||||
public:
|
||||
ECCServerKEXNamedCurveReplacer(const std::shared_ptr<TlsAgent>& server,
|
||||
uint16_t curve_name)
|
||||
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
||||
curve_name_(curve_name) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
|
||||
uint32_t curve_type;
|
||||
EXPECT_TRUE(output->Read(0, 1, &curve_type));
|
||||
EXPECT_EQ(curve_type, ec_type_named);
|
||||
output->Write(1, curve_name_, 2);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t curve_name_;
|
||||
};
|
||||
|
||||
// Replaces the signature scheme in a CertificateVerify message.
|
||||
class TlsReplaceSignatureSchemeFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsReplaceSignatureSchemeFilter(const std::shared_ptr<TlsAgent>& a,
|
||||
uint16_t scheme)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}),
|
||||
scheme_(scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
output->Write(0, scheme_, 2);
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t scheme_;
|
||||
};
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
#endif
|
||||
|
|
|
|||
878
security/nss/gtests/ssl_gtest/tls_grease_unittest.cc
Normal file
878
security/nss/gtests/ssl_gtest/tls_grease_unittest.cc
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
/* -*- 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 "gtest_utils.h"
|
||||
#include "tls_connect.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
const uint8_t kTlsGreaseExtensionMessages[] = {kTlsHandshakeEncryptedExtensions,
|
||||
kTlsHandshakeCertificate};
|
||||
|
||||
const uint16_t kTlsGreaseValues[] = {
|
||||
0x0a0a, 0x1a1a, 0x2a2a, 0x3a3a, 0x4a4a, 0x5a5a, 0x6a6a, 0x7a7a,
|
||||
0x8a8a, 0x9a9a, 0xaaaa, 0xbaba, 0xcaca, 0xdada, 0xeaea, 0xfafa};
|
||||
|
||||
const uint8_t kTlsGreasePskValues[] = {0x0B, 0x2A, 0x49, 0x68,
|
||||
0x87, 0xA6, 0xC5, 0xE4};
|
||||
|
||||
size_t countGreaseInBuffer(const DataBuffer& list) {
|
||||
if (!list.len()) {
|
||||
return 0;
|
||||
}
|
||||
size_t occurrence = 0;
|
||||
for (uint16_t greaseVal : kTlsGreaseValues) {
|
||||
for (size_t i = 0; i < (list.len() - 1); i += 2) {
|
||||
uint16_t sample = list.data()[i + 1] + (list.data()[i] << 8);
|
||||
if (greaseVal == sample) {
|
||||
occurrence++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return occurrence;
|
||||
}
|
||||
|
||||
class GreasePresenceAbsenceTestBase : public TlsConnectTestBase {
|
||||
public:
|
||||
GreasePresenceAbsenceTestBase(SSLProtocolVariant variant, uint16_t version,
|
||||
bool shouldGrease)
|
||||
: TlsConnectTestBase(variant, version), set_grease_(shouldGrease){};
|
||||
|
||||
void SetupGrease() {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_),
|
||||
SECSuccess);
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, set_grease_),
|
||||
SECSuccess);
|
||||
}
|
||||
|
||||
bool expectGrease() {
|
||||
return set_grease_ && version_ >= SSL_LIBRARY_VERSION_TLS_1_3;
|
||||
}
|
||||
|
||||
void checkGreasePresence(const int ifEnabled, const int ifDisabled,
|
||||
const DataBuffer& buffer) {
|
||||
size_t expected = expectGrease() ? size_t(ifEnabled) : size_t(ifDisabled);
|
||||
EXPECT_EQ(expected, countGreaseInBuffer(buffer));
|
||||
}
|
||||
|
||||
private:
|
||||
bool set_grease_;
|
||||
};
|
||||
|
||||
class GreasePresenceAbsenceTestAllVersions
|
||||
: public GreasePresenceAbsenceTestBase,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<SSLProtocolVariant, uint16_t, bool>> {
|
||||
public:
|
||||
GreasePresenceAbsenceTestAllVersions()
|
||||
: GreasePresenceAbsenceTestBase(std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()),
|
||||
std::get<2>(GetParam())){};
|
||||
};
|
||||
|
||||
// Varies stream/datagram, TLS Version and whether GREASE is enabled
|
||||
INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestAllVersions,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11Plus,
|
||||
::testing::Values(true, false)));
|
||||
|
||||
// Varies whether GREASE is enabled for TLS13 only
|
||||
class GreasePresenceAbsenceTestTlsStream13
|
||||
: public GreasePresenceAbsenceTestBase,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
public:
|
||||
GreasePresenceAbsenceTestTlsStream13()
|
||||
: GreasePresenceAbsenceTestBase(
|
||||
ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3, GetParam()){};
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GreaseTests, GreasePresenceAbsenceTestTlsStream13,
|
||||
::testing::Values(true, false));
|
||||
|
||||
// These tests check for the presence / absence of GREASE values in the various
|
||||
// positions that we are permitted to add them. For positions which existed in
|
||||
// prior versions of TLS, we check that enabling GREASE is only effective when
|
||||
// negotiating TLS1.3 or higher and that disabling GREASE results in the absence
|
||||
// of any GREASE values.
|
||||
// For positions that specific to TLS1.3, we only check that enabling/disabling
|
||||
// GREASE results in the correct presence/absence of the GREASE value.
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseCiphersuites) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 = MakeTlsFilter<ClientHelloCiphersuiteCapture>(client_);
|
||||
Connect();
|
||||
EXPECT_TRUE(ch1->captured());
|
||||
|
||||
checkGreasePresence(1, 0, ch1->contents());
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseNamedGroups) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_supported_groups_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE(ch1->captured());
|
||||
|
||||
checkGreasePresence(1, 0, ch1->extension());
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseKeyShare) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_tls13_key_share_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured());
|
||||
|
||||
checkGreasePresence(1, 0, ch1->extension());
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSigAlg) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_2) == ch1->captured());
|
||||
|
||||
checkGreasePresence(1, 0, ch1->extension());
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseSupportedVersions) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_supported_versions_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) == ch1->captured());
|
||||
|
||||
// Supported Versions have a 1 byte length field.
|
||||
TlsParser extParser(ch1->extension());
|
||||
DataBuffer versions;
|
||||
extParser.ReadVariable(&versions, 1);
|
||||
|
||||
checkGreasePresence(1, 0, versions);
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestTlsStream13, ClientGreasePskExchange) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_tls13_psk_key_exchange_modes_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE(ch1->captured());
|
||||
|
||||
// PSK Exchange Modes have a 1 byte length field
|
||||
TlsParser extParser(ch1->extension());
|
||||
DataBuffer modes;
|
||||
extParser.ReadVariable(&modes, 1);
|
||||
|
||||
// Scan for single byte GREASE PSK Values
|
||||
size_t numGrease = 0;
|
||||
for (uint8_t greaseVal : kTlsGreasePskValues) {
|
||||
for (unsigned long i = 0; i < modes.len(); i++) {
|
||||
if (greaseVal == modes.data()[i]) {
|
||||
numGrease++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), numGrease);
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, ClientGreaseAlpn) {
|
||||
SetupGrease();
|
||||
EnableAlpn();
|
||||
|
||||
auto ch1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_app_layer_protocol_xtn);
|
||||
Connect();
|
||||
EXPECT_TRUE((version_ >= SSL_LIBRARY_VERSION_TLS_1_1) == ch1->captured());
|
||||
|
||||
// ALPN Xtns have a redundant two-byte length
|
||||
TlsParser alpnParser(ch1->extension());
|
||||
alpnParser.Skip(2); // Skip the length
|
||||
DataBuffer alpnEntry;
|
||||
|
||||
// Each ALPN entry has a single byte length prefixed.
|
||||
size_t greaseAlpnEntrys = 0;
|
||||
while (alpnParser.remaining()) {
|
||||
alpnParser.ReadVariable(&alpnEntry, 1);
|
||||
if (alpnEntry.len() == 2) {
|
||||
greaseAlpnEntrys += countGreaseInBuffer(alpnEntry);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expectGrease() ? size_t(1) : size_t(0), greaseAlpnEntrys);
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestAllVersions, GreaseClientHelloExtension) {
|
||||
SetupGrease();
|
||||
|
||||
auto ch1 =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(client_, kTlsHandshakeClientHello);
|
||||
Connect();
|
||||
EXPECT_TRUE(ch1->buffer().len() > 0);
|
||||
|
||||
TlsParser extParser(ch1->buffer());
|
||||
EXPECT_TRUE(extParser.Skip(2 + 32)); // Version + Random
|
||||
EXPECT_TRUE(extParser.SkipVariable(1)); // Session ID
|
||||
if (variant_ == ssl_variant_datagram) {
|
||||
EXPECT_TRUE(extParser.SkipVariable(1)); // Cookie
|
||||
}
|
||||
EXPECT_TRUE(extParser.SkipVariable(2)); // Ciphersuites
|
||||
EXPECT_TRUE(extParser.SkipVariable(1)); // Compression Methods
|
||||
EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths
|
||||
|
||||
// Scan for a 1-byte and a 0-byte extension.
|
||||
uint32_t extType;
|
||||
DataBuffer extBuf;
|
||||
bool foundSmall = false;
|
||||
bool foundLarge = false;
|
||||
size_t numFound = 0;
|
||||
while (extParser.remaining()) {
|
||||
extParser.Read(&extType, 2);
|
||||
extParser.ReadVariable(&extBuf, 2);
|
||||
for (uint16_t greaseVal : kTlsGreaseValues) {
|
||||
if (greaseVal == extType) {
|
||||
numFound++;
|
||||
foundSmall |= extBuf.len() == 0;
|
||||
foundLarge |= extBuf.len() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(foundSmall, expectGrease());
|
||||
EXPECT_EQ(foundLarge, expectGrease());
|
||||
EXPECT_EQ(numFound, expectGrease() ? size_t(2) : size_t(0));
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseCertificateRequestSigAlg) {
|
||||
SetupGrease();
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
|
||||
auto cr =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_signature_algorithms_xtn);
|
||||
cr->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
|
||||
cr->EnableDecryption();
|
||||
Connect();
|
||||
EXPECT_TRUE(cr->captured());
|
||||
|
||||
checkGreasePresence(1, 0, cr->extension());
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestTlsStream13,
|
||||
GreaseCertificateRequestExtension) {
|
||||
SetupGrease();
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
|
||||
auto cr = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeCertificateRequest);
|
||||
cr->EnableDecryption();
|
||||
Connect();
|
||||
EXPECT_TRUE(cr->buffer().len() > 0);
|
||||
|
||||
TlsParser extParser(cr->buffer());
|
||||
EXPECT_TRUE(extParser.SkipVariable(1)); // Context
|
||||
EXPECT_TRUE(extParser.Skip(2)); // Extension Lengths
|
||||
|
||||
uint32_t extType;
|
||||
DataBuffer extBuf;
|
||||
bool found = false;
|
||||
// Scan for a single, empty extension
|
||||
while (extParser.remaining()) {
|
||||
extParser.Read(&extType, 2);
|
||||
extParser.ReadVariable(&extBuf, 2);
|
||||
for (uint16_t greaseVal : kTlsGreaseValues) {
|
||||
if (greaseVal == extType) {
|
||||
EXPECT_TRUE(!found);
|
||||
EXPECT_EQ(extBuf.len(), size_t(0));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expectGrease(), found);
|
||||
}
|
||||
|
||||
TEST_P(GreasePresenceAbsenceTestTlsStream13, GreaseNewSessionTicketExtension) {
|
||||
SetupGrease();
|
||||
|
||||
auto nst = MakeTlsFilter<TlsHandshakeRecorder>(server_,
|
||||
kTlsHandshakeNewSessionTicket);
|
||||
nst->EnableDecryption();
|
||||
Connect();
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
|
||||
EXPECT_TRUE(nst->buffer().len() > 0);
|
||||
|
||||
TlsParser extParser(nst->buffer());
|
||||
EXPECT_TRUE(extParser.Skip(4)); // lifetime
|
||||
EXPECT_TRUE(extParser.Skip(4)); // age
|
||||
EXPECT_TRUE(extParser.SkipVariable(1)); // Nonce
|
||||
EXPECT_TRUE(extParser.SkipVariable(2)); // Ticket
|
||||
EXPECT_TRUE(extParser.Skip(2)); // Extension Length
|
||||
|
||||
uint32_t extType;
|
||||
DataBuffer extBuf;
|
||||
bool found = false;
|
||||
// Scan for a single, empty extension
|
||||
while (extParser.remaining()) {
|
||||
extParser.Read(&extType, 2);
|
||||
extParser.ReadVariable(&extBuf, 2);
|
||||
for (uint16_t greaseVal : kTlsGreaseValues) {
|
||||
if (greaseVal == extType) {
|
||||
EXPECT_TRUE(!found);
|
||||
EXPECT_EQ(extBuf.len(), size_t(0));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expectGrease(), found);
|
||||
}
|
||||
|
||||
// Generic Client GREASE test
|
||||
TEST_P(TlsConnectGeneric, ClientGrease) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Generic Server GREASE test
|
||||
TEST_P(TlsConnectGeneric, ServerGrease) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Generic GREASE test
|
||||
TEST_P(TlsConnectGeneric, Grease) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Check that GREASE values can be correctly reconstructed after HRR.
|
||||
TEST_P(TlsConnectGeneric, GreaseHRR) {
|
||||
EnsureTlsSetup();
|
||||
const std::vector<SSLNamedGroup> client_groups = {
|
||||
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1};
|
||||
const std::vector<SSLNamedGroup> server_groups = {
|
||||
ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
||||
client_->ConfigNamedGroups(client_groups);
|
||||
server_->ConfigNamedGroups(server_groups);
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Check that GREASE additions interact correctly with psk-only handshake.
|
||||
TEST_F(TlsConnectStreamTls13, GreasePsk) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
SECItem psk_item;
|
||||
psk_item.type = siBuffer;
|
||||
psk_item.len = sizeof(kPskDummyVal_);
|
||||
psk_item.data = const_cast<uint8_t*>(kPskDummyVal_);
|
||||
PK11SymKey* key =
|
||||
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &psk_item, NULL);
|
||||
|
||||
ScopedPK11SymKey scoped_psk_(key);
|
||||
const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
|
||||
const SSLHashType kPskHash_ = ssl_hash_sha384;
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
// Test that ECH and GREASE work together successfully
|
||||
TEST_F(TlsConnectStreamTls13, GreaseAndECH) {
|
||||
EnsureTlsSetup();
|
||||
SetupEch(client_, server_);
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Test that TLS12 Server handles Client GREASE correctly
|
||||
TEST_F(TlsConnectTest, GreaseTLS12Server) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2);
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Test that TLS12 Client handles Server GREASE correctly
|
||||
TEST_F(TlsConnectTest, GreaseTLS12Client) {
|
||||
EnsureTlsSetup();
|
||||
ASSERT_EQ(SSL_OptionSet(server_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE),
|
||||
SECSuccess);
|
||||
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
|
||||
SSL_LIBRARY_VERSION_TLS_1_2);
|
||||
Connect();
|
||||
}
|
||||
|
||||
class GreaseOnlyTestStreamTls13 : public TlsConnectStreamTls13 {
|
||||
public:
|
||||
GreaseOnlyTestStreamTls13() : TlsConnectStreamTls13() {}
|
||||
|
||||
void ConnectWithCustomChExpectFail(const std::string& ch,
|
||||
uint8_t server_alert, uint32_t server_code,
|
||||
uint32_t client_code) {
|
||||
std::vector<uint8_t> ch_vec = hex_string_to_bytes(ch);
|
||||
DataBuffer ch_buf;
|
||||
EnsureTlsSetup();
|
||||
|
||||
TlsAgentTestBase::MakeRecord(variant_, ssl_ct_handshake,
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, ch_vec.data(),
|
||||
ch_vec.size(), &ch_buf, 0);
|
||||
StartConnect();
|
||||
client_->SendDirect(ch_buf);
|
||||
ExpectAlert(server_, server_alert);
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(server_code);
|
||||
client_->ExpectReceiveAlert(server_alert, kTlsAlertFatal);
|
||||
client_->Handshake();
|
||||
client_->CheckErrorCode(client_code);
|
||||
}
|
||||
};
|
||||
|
||||
// Client: Offer only GREASE CipherSuite value
|
||||
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientCipherSuite) {
|
||||
// 0xdada
|
||||
std::string ch =
|
||||
"010000b003038afacda2963358e98f464f3ff0680ed3a9d382a8c3eac5e5604f5721add9"
|
||||
"855c000002dada010000850000000b0009000006736572766572ff01000100000a001400"
|
||||
"12001d00170018001901000101010201030104003300260024001d0020683668992de470"
|
||||
"38660ee37bafc7392b05b8a94402ea1f3463ad3cfd7a694a46002b0003020304000d0018"
|
||||
"001604030503060302030804080508060401050106010201002d00020101001c0002400"
|
||||
"1";
|
||||
|
||||
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
||||
SSL_ERROR_NO_CYPHER_OVERLAP,
|
||||
SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
// Client: Offer only GREASE SupportedGroups value
|
||||
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedGroup) {
|
||||
// 0x3a3a
|
||||
std::string ch =
|
||||
"010000a40303484a4e14f547404da6115d7f73bbb0f1c9d65e66ac073dee6c4a62f72de9"
|
||||
"a36f000006130113031302010000750000000b0009000006736572766572ff0100010000"
|
||||
"0a000400023a3a003300260024001d0020e75cb8e217c95176954e8b5fb95843882462ce"
|
||||
"2cd3fcfe67cf31463a05ea3d57002b0003020304000d0018001604030503060302030804"
|
||||
"080508060401050106010201002d00020101001c00024001";
|
||||
|
||||
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
||||
SSL_ERROR_NO_CYPHER_OVERLAP,
|
||||
SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
// Client: Offer only GREASE SigAlgs value
|
||||
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSignatureAlgorithm) {
|
||||
// 0x8a8a
|
||||
std::string ch =
|
||||
"010000a00303dfd8e2438a8d1b9f48d921dfc08959108807bd1105238bb3da2a2a8e3db0"
|
||||
"6990000006130113031302010000710000000b0009000006736572766572ff0100010000"
|
||||
"0a00140012001d00170018001901000101010201030104003300260024001d002074bb2c"
|
||||
"94996d3ffc7ae5792f0c3c58676358a85ea304cd029fa3d6551013b333002b0003020304"
|
||||
"000d000400028a8a002d00020101001c00024001";
|
||||
|
||||
ConnectWithCustomChExpectFail(ch, kTlsAlertHandshakeFailure,
|
||||
SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM,
|
||||
SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
// Client: Offer only GREASE SupportedVersions value
|
||||
TEST_F(GreaseOnlyTestStreamTls13, GreaseOnlyClientSupportedVersion) {
|
||||
// 0xeaea
|
||||
std::string ch =
|
||||
"010000b203037e3618abae0dd0b3f06a504c47354551d1d5be36e9c3e1eac9c139c246b1"
|
||||
"66da000006130113031302010000830000000b0009000006736572766572ff0100010000"
|
||||
"0a00140012001d00170018001901000101010201030104003300260024001d00206b1816"
|
||||
"577ff2e69d4d2661419150eaefa0328ffd396425cf1733ec06536b4e55002b000100000d"
|
||||
"0018001604030503060302030804080508060401050106010201002d00020101001c0002"
|
||||
"4001";
|
||||
|
||||
ConnectWithCustomChExpectFail(ch, kTlsAlertIllegalParameter,
|
||||
SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
|
||||
SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
class GreaseTestStreamTls12
|
||||
: public TlsConnectStreamTls12,
|
||||
public ::testing::WithParamInterface<uint16_t /* GREASE */> {
|
||||
public:
|
||||
GreaseTestStreamTls12() : TlsConnectStreamTls12(), grease_(GetParam()){};
|
||||
|
||||
void ConnectExpectSigAlgFail() {
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint16_t grease_;
|
||||
};
|
||||
|
||||
class TlsCertificateRequestSigAlgSetterFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsCertificateRequestSigAlgSetterFilter(const std::shared_ptr<TlsAgent>& a,
|
||||
uint16_t sigAlg)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}),
|
||||
sigAlg_(sigAlg) {}
|
||||
virtual PacketFilter::Action FilterHandshake(
|
||||
const TlsHandshakeFilter::HandshakeHeader& header,
|
||||
const DataBuffer& input, DataBuffer* output) {
|
||||
TlsParser parser(input);
|
||||
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 signature algorithm.
|
||||
idx = output->Write(idx, sizeof(sigAlg_), 2);
|
||||
idx = output->Write(idx, sigAlg_, 2);
|
||||
|
||||
// Write certificate authorities.
|
||||
idx = output->Write(idx, cas.len(), 2);
|
||||
idx = output->Write(idx, cas);
|
||||
|
||||
return CHANGE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t sigAlg_;
|
||||
};
|
||||
|
||||
// Server: Offer only GREASE CertificateRequest SigAlg value
|
||||
TEST_P(GreaseTestStreamTls12, GreaseOnlyServerTLS12CertificateRequestSigAlg) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
MakeTlsFilter<TlsCertificateRequestSigAlgSetterFilter>(server_, grease_);
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertHandshakeFailure);
|
||||
server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
|
||||
ConnectExpectFail();
|
||||
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
// Illegally GREASE ServerKeyExchange ECC SignatureAlgorithm
|
||||
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEccSigAlg) {
|
||||
MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_, grease_);
|
||||
EnableSomeEcdhCiphers();
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Illegally GREASE ServerKeyExchange DHE SignatureAlgorithm
|
||||
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexDheSigAlg) {
|
||||
MakeTlsFilter<DHEServerKEXSigAlgReplacer>(server_, grease_);
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Illegally GREASE ServerKeyExchange ECDHE NamedCurve
|
||||
TEST_P(GreaseTestStreamTls12, GreasedTLS12ServerKexEcdheNamedCurve) {
|
||||
MakeTlsFilter<ECCServerKEXNamedCurveReplacer>(server_, grease_);
|
||||
EnableSomeEcdhCiphers();
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertHandshakeFailure);
|
||||
server_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
|
||||
ConnectExpectFail();
|
||||
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
|
||||
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
}
|
||||
|
||||
// Illegally GREASE TLS12 Client CertificateVerify SignatureAlgorithm
|
||||
TEST_P(GreaseTestStreamTls12, GreasedTLS12ClientCertificateVerifySigAlg) {
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_, grease_);
|
||||
|
||||
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
class GreaseTestStreamTls13
|
||||
: public TlsConnectStreamTls13,
|
||||
public ::testing::WithParamInterface<uint16_t /* GREASE */> {
|
||||
public:
|
||||
GreaseTestStreamTls13() : grease_(GetParam()){};
|
||||
|
||||
protected:
|
||||
uint16_t grease_;
|
||||
};
|
||||
|
||||
// Illegally GREASE TLS13 Client CertificateVerify SignatureAlgorithm
|
||||
TEST_P(GreaseTestStreamTls13, GreasedTLS13ClientCertificateVerifySigAlg) {
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_, grease_);
|
||||
filter->EnableDecryption();
|
||||
|
||||
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
|
||||
// Manually trigger handshake to avoid race conditions
|
||||
StartConnect();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
|
||||
client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Illegally GREASE TLS13 Server CertificateVerify SignatureAlgorithm
|
||||
TEST_P(GreaseTestStreamTls13, GreasedTLS13ServerCertificateVerifySigAlg) {
|
||||
EnsureTlsSetup();
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, grease_);
|
||||
filter->EnableDecryption();
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
|
||||
}
|
||||
|
||||
// Illegally GREASE HelloRetryRequest version value
|
||||
TEST_P(GreaseTestStreamTls13, GreasedHelloRetryRequestVersion) {
|
||||
EnsureTlsSetup();
|
||||
// Trigger HelloRetryRequest
|
||||
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_tls13_key_share_xtn);
|
||||
auto filter = MakeTlsFilter<TlsMessageVersionSetter>(
|
||||
server_, kTlsHandshakeHelloRetryRequest, grease_);
|
||||
filter->EnableDecryption();
|
||||
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
class GreaseTestStreamTls123
|
||||
: public TlsConnectTestBase,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<uint16_t /* version */, uint16_t /* GREASE */>> {
|
||||
public:
|
||||
GreaseTestStreamTls123()
|
||||
: TlsConnectTestBase(ssl_variant_stream, std::get<0>(GetParam())),
|
||||
grease_(std::get<1>(GetParam())){};
|
||||
|
||||
void ConnectExpectIllegalGreaseFail() {
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// Server expects handshake but receives encrypted alert.
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
} else {
|
||||
server_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
}
|
||||
ConnectExpectFail();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint16_t grease_;
|
||||
};
|
||||
|
||||
// Illegally GREASE TLS12 and TLS13 ServerHello version value
|
||||
TEST_P(GreaseTestStreamTls123, GreasedServerHelloVersion) {
|
||||
EnsureTlsSetup();
|
||||
auto filter = MakeTlsFilter<TlsMessageVersionSetter>(
|
||||
server_, kTlsHandshakeServerHello, grease_);
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
filter->EnableDecryption();
|
||||
}
|
||||
ConnectExpectIllegalGreaseFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
|
||||
}
|
||||
|
||||
// Illegally GREASE TLS12 and TLS13 selected CipherSuite value
|
||||
TEST_P(GreaseTestStreamTls123, GreasedServerHelloCipherSuite) {
|
||||
EnsureTlsSetup();
|
||||
auto filter = MakeTlsFilter<SelectedCipherSuiteReplacer>(server_, grease_);
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
filter->EnableDecryption();
|
||||
}
|
||||
ConnectExpectIllegalGreaseFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
class GreaseExtensionTestStreamTls13
|
||||
: public TlsConnectStreamTls13,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<uint8_t /* message */, uint16_t /* GREASE */>> {
|
||||
public:
|
||||
GreaseExtensionTestStreamTls13()
|
||||
: TlsConnectStreamTls13(),
|
||||
message_(std::get<0>(GetParam())),
|
||||
grease_(std::get<1>(GetParam())){};
|
||||
|
||||
protected:
|
||||
uint8_t message_;
|
||||
uint16_t grease_;
|
||||
};
|
||||
|
||||
// Illegally GREASE TLS13 Server EncryptedExtensions and Certificate Extensions
|
||||
// NSS currently allows offering unkown extensions in HelloRetryRequests!
|
||||
TEST_P(GreaseExtensionTestStreamTls13, GreasedServerExtensions) {
|
||||
EnsureTlsSetup();
|
||||
DataBuffer empty = DataBuffer(1);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsExtensionAppender>(server_, message_, grease_, empty);
|
||||
filter->EnableDecryption();
|
||||
|
||||
server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension);
|
||||
client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT);
|
||||
}
|
||||
|
||||
// Illegally GREASE TLS12 and TLS13 ServerHello Extensions
|
||||
TEST_P(GreaseTestStreamTls123, GreasedServerHelloExtensions) {
|
||||
EnsureTlsSetup();
|
||||
DataBuffer empty = DataBuffer(1);
|
||||
auto filter = MakeTlsFilter<TlsExtensionAppender>(
|
||||
server_, kTlsHandshakeServerHello, grease_, empty);
|
||||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
filter->EnableDecryption();
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
} else {
|
||||
server_->ExpectReceiveAlert(kTlsAlertUnsupportedExtension);
|
||||
}
|
||||
client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
|
||||
}
|
||||
|
||||
// Illegally GREASE TLS13 Client Certificate Extensions
|
||||
// Server ignores injected client extensions and fails on CertificateVerify
|
||||
TEST_P(GreaseTestStreamTls13, GreasedClientCertificateExtensions) {
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
DataBuffer empty = DataBuffer(1);
|
||||
auto filter = MakeTlsFilter<TlsExtensionAppender>(
|
||||
client_, kTlsHandshakeCertificate, grease_, empty);
|
||||
filter->EnableDecryption();
|
||||
|
||||
server_->ExpectSendAlert(kTlsAlertDecryptError);
|
||||
client_->ExpectReceiveAlert(kTlsAlertDecryptError);
|
||||
|
||||
// Manually trigger handshake to avoid race conditions
|
||||
StartConnect();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
|
||||
server_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
|
||||
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, GreaseClientHelloExtensionPermutation) {
|
||||
EnsureTlsSetup();
|
||||
PR_ASSERT(SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_CH_EXTENSION_PERMUTATION,
|
||||
PR_TRUE) == SECSuccess);
|
||||
PR_ASSERT(SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_GREASE, PR_TRUE) ==
|
||||
SECSuccess);
|
||||
Connect();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GreaseTestTls12, GreaseTestStreamTls12,
|
||||
::testing::ValuesIn(kTlsGreaseValues));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GreaseTestTls13, GreaseTestStreamTls13,
|
||||
::testing::ValuesIn(kTlsGreaseValues));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GreaseTestTls123, GreaseTestStreamTls123,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsV12Plus,
|
||||
::testing::ValuesIn(kTlsGreaseValues)));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GreaseExtensionTest, GreaseExtensionTestStreamTls13,
|
||||
testing::Combine(testing::ValuesIn(kTlsGreaseExtensionMessages),
|
||||
testing::ValuesIn(kTlsGreaseValues)));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -67,18 +68,6 @@ size_t GetHashLength(SSLHashType hash) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
CK_MECHANISM_TYPE GetHkdfMech(SSLHashType hash) {
|
||||
switch (hash) {
|
||||
case ssl_hash_sha256:
|
||||
return CKM_NSS_HKDF_SHA256;
|
||||
case ssl_hash_sha384:
|
||||
return CKM_NSS_HKDF_SHA384;
|
||||
default:
|
||||
ADD_FAILURE() << "Unknown hash: " << hash;
|
||||
}
|
||||
return CKM_INVALID_MECHANISM;
|
||||
}
|
||||
|
||||
PRUint16 GetSomeCipherSuiteForHash(SSLHashType hash) {
|
||||
switch (hash) {
|
||||
case ssl_hash_sha256:
|
||||
|
|
@ -172,7 +161,7 @@ class TlsHkdfTest : public ::testing::Test,
|
|||
ScopedPK11SymKey prkk(prk);
|
||||
|
||||
DumpKey("Output", prkk);
|
||||
VerifyKey(prkk, GetHkdfMech(base_hash), expected);
|
||||
VerifyKey(prkk, CKM_HKDF_DERIVE, expected);
|
||||
|
||||
// Now test the public wrapper.
|
||||
PRUint16 cs = GetSomeCipherSuiteForHash(base_hash);
|
||||
|
|
@ -180,20 +169,21 @@ class TlsHkdfTest : public ::testing::Test,
|
|||
ikmk2.get(), &prk);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_NE(nullptr, prk);
|
||||
VerifyKey(ScopedPK11SymKey(prk), GetHkdfMech(base_hash), expected);
|
||||
VerifyKey(ScopedPK11SymKey(prk), CKM_HKDF_DERIVE, expected);
|
||||
}
|
||||
|
||||
void HkdfExpandLabel(ScopedPK11SymKey* prk, SSLHashType base_hash,
|
||||
const uint8_t* session_hash, size_t session_hash_len,
|
||||
const char* label, size_t label_len,
|
||||
const DataBuffer& expected) {
|
||||
ASSERT_NE(nullptr, prk);
|
||||
std::cerr << "Hash = " << kHashName[base_hash] << std::endl;
|
||||
|
||||
std::vector<uint8_t> output(expected.len());
|
||||
|
||||
SECStatus rv = tls13_HkdfExpandLabelRaw(prk->get(), base_hash, session_hash,
|
||||
session_hash_len, label, label_len,
|
||||
&output[0], output.size());
|
||||
SECStatus rv = tls13_HkdfExpandLabelRaw(
|
||||
prk->get(), base_hash, session_hash, session_hash_len, label, label_len,
|
||||
ssl_variant_stream, &output[0], output.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
DumpData("Output", &output[0], output.size());
|
||||
EXPECT_EQ(0, memcmp(expected.data(), &output[0], expected.len()));
|
||||
|
|
@ -205,15 +195,15 @@ class TlsHkdfTest : public ::testing::Test,
|
|||
session_hash, session_hash_len, label, label_len,
|
||||
&secret);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
ASSERT_NE(nullptr, prk);
|
||||
VerifyKey(ScopedPK11SymKey(secret), GetHkdfMech(base_hash), expected);
|
||||
ASSERT_NE(nullptr, secret);
|
||||
VerifyKey(ScopedPK11SymKey(secret), CKM_HKDF_DERIVE, expected);
|
||||
|
||||
// Verify that a key can be created with a different key type and size.
|
||||
rv = SSL_HkdfExpandLabelWithMech(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, cs, prk->get(), session_hash,
|
||||
session_hash_len, label, label_len, CKM_DES3_CBC_PAD, 24, &secret);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
ASSERT_NE(nullptr, prk);
|
||||
ASSERT_NE(nullptr, secret);
|
||||
ScopedPK11SymKey with_mech(secret);
|
||||
EXPECT_EQ(static_cast<CK_MECHANISM_TYPE>(CKM_DES3_CBC_PAD),
|
||||
PK11_GetMechanism(with_mech.get()));
|
||||
|
|
@ -437,7 +427,7 @@ TEST_P(TlsHkdfTest, BadExpandLabelWrapperInput) {
|
|||
}
|
||||
|
||||
static const SSLHashType kHashTypes[] = {ssl_hash_sha256, ssl_hash_sha384};
|
||||
INSTANTIATE_TEST_CASE_P(AllHashFuncs, TlsHkdfTest,
|
||||
::testing::ValuesIn(kHashTypes));
|
||||
INSTANTIATE_TEST_SUITE_P(AllHashFuncs, TlsHkdfTest,
|
||||
::testing::ValuesIn(kHashTypes));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -24,39 +25,68 @@ TlsCipherSpec::TlsCipherSpec(bool dtls, uint16_t epoc)
|
|||
|
||||
bool TlsCipherSpec::SetKeys(SSLCipherSuiteInfo* cipherinfo,
|
||||
PK11SymKey* secret) {
|
||||
SSLAeadContext* ctx;
|
||||
SECStatus rv = SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3,
|
||||
cipherinfo->cipherSuite, secret, "",
|
||||
0, // Use the default labels.
|
||||
&ctx);
|
||||
SSLAeadContext* aead_ctx;
|
||||
SSLProtocolVariant variant =
|
||||
dtls_ ? ssl_variant_datagram : ssl_variant_stream;
|
||||
SECStatus rv =
|
||||
SSL_MakeVariantAead(SSL_LIBRARY_VERSION_TLS_1_3, cipherinfo->cipherSuite,
|
||||
variant, secret, "", 0, // Use the default labels.
|
||||
&aead_ctx);
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
aead_.reset(ctx);
|
||||
aead_.reset(aead_ctx);
|
||||
|
||||
SSLMaskingContext* mask_ctx;
|
||||
const char kHkdfPurposeSn[] = "sn";
|
||||
rv = SSL_CreateVariantMaskingContext(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3, cipherinfo->cipherSuite, variant, secret,
|
||||
kHkdfPurposeSn, strlen(kHkdfPurposeSn), &mask_ctx);
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
mask_.reset(mask_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
|
||||
const DataBuffer& ciphertext,
|
||||
DataBuffer* plaintext) {
|
||||
if (aead_ == nullptr) {
|
||||
DataBuffer* plaintext,
|
||||
TlsRecordHeader* out_header) {
|
||||
if (!aead_ || !out_header) {
|
||||
return false;
|
||||
}
|
||||
*out_header = header;
|
||||
|
||||
// Make space.
|
||||
plaintext->Allocate(ciphertext.len());
|
||||
|
||||
auto header_bytes = header.header();
|
||||
unsigned int len;
|
||||
uint64_t seqno;
|
||||
if (dtls_) {
|
||||
seqno = header.sequence_number();
|
||||
} else {
|
||||
seqno = in_seqno_;
|
||||
uint64_t seqno = dtls_ ? header.sequence_number() : in_seqno_;
|
||||
SECStatus rv;
|
||||
|
||||
if (header.is_dtls13_ciphertext()) {
|
||||
if (!mask_ || !out_header) {
|
||||
return false;
|
||||
}
|
||||
PORT_Assert(ciphertext.len() >= 16);
|
||||
DataBuffer mask(2);
|
||||
rv = SSL_CreateMask(mask_.get(), ciphertext.data(), ciphertext.len(),
|
||||
mask.data(), mask.len());
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!out_header->MaskSequenceNumber(mask)) {
|
||||
return false;
|
||||
}
|
||||
seqno = out_header->sequence_number();
|
||||
}
|
||||
SECStatus rv =
|
||||
SSL_AeadDecrypt(aead_.get(), seqno, header_bytes.data(),
|
||||
header_bytes.len(), ciphertext.data(), ciphertext.len(),
|
||||
plaintext->data(), &len, plaintext->len());
|
||||
|
||||
auto header_bytes = out_header->header();
|
||||
rv = SSL_AeadDecrypt(aead_.get(), seqno, header_bytes.data(),
|
||||
header_bytes.len(), ciphertext.data(), ciphertext.len(),
|
||||
plaintext->data(), &len, plaintext->len());
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -68,11 +98,14 @@ bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
|
|||
}
|
||||
|
||||
bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
|
||||
const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext) {
|
||||
if (aead_ == nullptr) {
|
||||
const DataBuffer& plaintext, DataBuffer* ciphertext,
|
||||
TlsRecordHeader* out_header) {
|
||||
if (!aead_ || !out_header) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_header = header;
|
||||
|
||||
// Make a padded buffer.
|
||||
ciphertext->Allocate(plaintext.len() +
|
||||
32); // Room for any plausible auth tag
|
||||
|
|
@ -80,12 +113,7 @@ bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
|
|||
|
||||
DataBuffer header_bytes;
|
||||
(void)header.WriteHeader(&header_bytes, 0, plaintext.len() + 16);
|
||||
uint64_t seqno;
|
||||
if (dtls_) {
|
||||
seqno = header.sequence_number();
|
||||
} else {
|
||||
seqno = out_seqno_;
|
||||
}
|
||||
uint64_t seqno = dtls_ ? header.sequence_number() : out_seqno_;
|
||||
|
||||
SECStatus rv =
|
||||
SSL_AeadEncrypt(aead_.get(), seqno, header_bytes.data(),
|
||||
|
|
@ -95,6 +123,22 @@ bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (header.is_dtls13_ciphertext()) {
|
||||
if (!mask_ || !out_header) {
|
||||
return false;
|
||||
}
|
||||
PORT_Assert(ciphertext->len() >= 16);
|
||||
DataBuffer mask(2);
|
||||
rv = SSL_CreateMask(mask_.get(), ciphertext->data(), ciphertext->len(),
|
||||
mask.data(), mask.len());
|
||||
if (rv != SECSuccess) {
|
||||
return false;
|
||||
}
|
||||
if (!out_header->MaskSequenceNumber(mask)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RecordProtected();
|
||||
ciphertext->Truncate(len);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -26,9 +27,9 @@ class TlsCipherSpec {
|
|||
bool SetKeys(SSLCipherSuiteInfo* cipherinfo, PK11SymKey* secret);
|
||||
|
||||
bool Protect(const TlsRecordHeader& header, const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext);
|
||||
DataBuffer* ciphertext, TlsRecordHeader* out_header);
|
||||
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& ciphertext,
|
||||
DataBuffer* plaintext);
|
||||
DataBuffer* plaintext, TlsRecordHeader* out_header);
|
||||
|
||||
uint16_t epoch() const { return epoch_; }
|
||||
uint64_t next_in_seqno() const { return in_seqno_; }
|
||||
|
|
@ -51,6 +52,7 @@ class TlsCipherSpec {
|
|||
uint64_t out_seqno_;
|
||||
bool record_dropped_ = false;
|
||||
ScopedSSLAeadContext aead_;
|
||||
ScopedSSLMaskingContext mask_;
|
||||
};
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
515
security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
Normal file
515
security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
/* -*- 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 "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Tls13PskTest : public TlsConnectTestBase,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<SSLProtocolVariant, uint16_t>> {
|
||||
public:
|
||||
Tls13PskTest()
|
||||
: TlsConnectTestBase(std::get<0>(GetParam()),
|
||||
SSL_LIBRARY_VERSION_TLS_1_3),
|
||||
suite_(std::get<1>(GetParam())) {}
|
||||
|
||||
void SetUp() override {
|
||||
TlsConnectTestBase::SetUp();
|
||||
scoped_psk_.reset(GetPsk());
|
||||
ASSERT_TRUE(!!scoped_psk_);
|
||||
}
|
||||
|
||||
private:
|
||||
PK11SymKey* GetPsk() {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
ADD_FAILURE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SECItem psk_item;
|
||||
psk_item.type = siBuffer;
|
||||
psk_item.len = sizeof(kPskDummyVal_);
|
||||
psk_item.data = const_cast<uint8_t*>(kPskDummyVal_);
|
||||
|
||||
PK11SymKey* key =
|
||||
PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &psk_item, NULL);
|
||||
if (!key) {
|
||||
ADD_FAILURE();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
protected:
|
||||
ScopedPK11SymKey scoped_psk_;
|
||||
const uint16_t suite_;
|
||||
const uint8_t kPskDummyVal_[16] = {0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
const std::string kPskDummyLabel_ = "NSS PSK GTEST label";
|
||||
const SSLHashType kPskHash_ = ssl_hash_sha384;
|
||||
};
|
||||
|
||||
// TLS 1.3 PSK connection test.
|
||||
TEST_P(Tls13PskTest, NormalExternal) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
client_->RemovePsk(kPskDummyLabel_);
|
||||
server_->RemovePsk(kPskDummyLabel_);
|
||||
|
||||
// Removing it again should fail.
|
||||
EXPECT_EQ(SECFailure, SSL_RemoveExternalPsk(client_->ssl_fd(),
|
||||
reinterpret_cast<const uint8_t*>(
|
||||
kPskDummyLabel_.data()),
|
||||
kPskDummyLabel_.length()));
|
||||
EXPECT_EQ(SECFailure, SSL_RemoveExternalPsk(server_->ssl_fd(),
|
||||
reinterpret_cast<const uint8_t*>(
|
||||
kPskDummyLabel_.data()),
|
||||
kPskDummyLabel_.length()));
|
||||
}
|
||||
|
||||
TEST_P(Tls13PskTest, KeyTooLarge) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(!!slot);
|
||||
ScopedPK11SymKey scoped_psk(PK11_KeyGen(
|
||||
slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 128, nullptr));
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
// Attempt to use a PSK with the wrong PRF hash.
|
||||
// "Clients MUST verify that...the server selected a cipher suite
|
||||
// indicating a Hash associated with the PSK"
|
||||
TEST_P(Tls13PskTest, ClientVerifyHashType) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
MakeTlsFilter<SelectedCipherSuiteReplacer>(server_,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
ConnectExpectFail();
|
||||
EXPECT_EQ(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, server_->error_code());
|
||||
} else {
|
||||
ConnectExpectFailOneSide(TlsAgent::CLIENT);
|
||||
}
|
||||
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
|
||||
}
|
||||
|
||||
// Different EPSKs (by label) on each endpoint. Expect cert auth.
|
||||
TEST_P(Tls13PskTest, LabelMismatch) {
|
||||
client_->AddPsk(scoped_psk_, std::string("foo"), kPskHash_);
|
||||
server_->AddPsk(scoped_psk_, std::string("bar"), kPskHash_);
|
||||
Connect();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
|
||||
}
|
||||
|
||||
SSLHelloRetryRequestAction RetryFirstHello(
|
||||
PRBool firstHello, const PRUint8* clientToken, unsigned int clientTokenLen,
|
||||
PRUint8* appToken, unsigned int* appTokenLen, unsigned int appTokenMax,
|
||||
void* arg) {
|
||||
auto* called = reinterpret_cast<size_t*>(arg);
|
||||
++*called;
|
||||
EXPECT_EQ(0U, clientTokenLen);
|
||||
EXPECT_EQ(*called, firstHello ? 1U : 2U);
|
||||
return firstHello ? ssl_hello_retry_request : ssl_hello_retry_accept;
|
||||
}
|
||||
|
||||
// Test resumption PSK with HRR.
|
||||
TEST_P(Tls13PskTest, ResPskRetryStateless) {
|
||||
ConfigureSelfEncrypt();
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
Connect();
|
||||
SendReceive(); // Need to read so that we absorb the session ticket.
|
||||
CheckKeys();
|
||||
|
||||
Reset();
|
||||
StartConnect();
|
||||
size_t cb_called = 0;
|
||||
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
|
||||
server_->ssl_fd(), RetryFirstHello, &cb_called));
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
Handshake();
|
||||
CheckConnected();
|
||||
EXPECT_EQ(2U, cb_called);
|
||||
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
// Test external PSK with HRR.
|
||||
TEST_P(Tls13PskTest, ExtPskRetryStateless) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
size_t cb_called = 0;
|
||||
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(
|
||||
server_->ssl_fd(), RetryFirstHello, &cb_called));
|
||||
StartConnect();
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
EXPECT_EQ(1U, cb_called);
|
||||
auto replacement = std::make_shared<TlsAgent>(
|
||||
server_->name(), TlsAgent::SERVER, server_->variant());
|
||||
server_ = replacement;
|
||||
server_->SetVersionRange(version_, version_);
|
||||
client_->SetPeer(server_);
|
||||
server_->SetPeer(client_);
|
||||
server_->AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
server_->ExpectPsk();
|
||||
server_->StartConnect();
|
||||
Handshake();
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
// Server not configured with PSK and sends a certificate instead of
|
||||
// a selected_identity. Client should attempt certificate authentication.
|
||||
TEST_P(Tls13PskTest, ClientOnly) {
|
||||
client_->AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
Connect();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
|
||||
}
|
||||
|
||||
// Set a PSK, remove psk_key_exchange_modes.
|
||||
TEST_P(Tls13PskTest, DropKexModes) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
StartConnect();
|
||||
MakeTlsFilter<TlsExtensionDropper>(client_,
|
||||
ssl_tls13_psk_key_exchange_modes_xtn);
|
||||
ConnectExpectAlert(server_, kTlsAlertMissingExtension);
|
||||
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES);
|
||||
}
|
||||
|
||||
// "Clients MUST verify that...a server "key_share" extension is present
|
||||
// if required by the ClientHello "psk_key_exchange_modes" extension."
|
||||
// As we don't support PSK without DH, it is always required.
|
||||
TEST_P(Tls13PskTest, DropRequiredKeyShare) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
StartConnect();
|
||||
MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_key_share_xtn);
|
||||
client_->ExpectSendAlert(kTlsAlertMissingExtension);
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
ConnectExpectFail();
|
||||
} else {
|
||||
ConnectExpectFailOneSide(TlsAgent::CLIENT);
|
||||
}
|
||||
client_->CheckErrorCode(SSL_ERROR_MISSING_KEY_SHARE);
|
||||
}
|
||||
|
||||
// "Clients MUST verify that...the server's selected_identity is
|
||||
// within the range supplied by the client". We send one OfferedPsk.
|
||||
TEST_P(Tls13PskTest, InvalidSelectedIdentity) {
|
||||
static const uint8_t selected_identity[] = {0x00, 0x01};
|
||||
DataBuffer buf(selected_identity, sizeof(selected_identity));
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
StartConnect();
|
||||
MakeTlsFilter<TlsExtensionReplacer>(server_, ssl_tls13_pre_shared_key_xtn,
|
||||
buf);
|
||||
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
|
||||
ConnectExpectFail();
|
||||
} else {
|
||||
ConnectExpectFailOneSide(TlsAgent::CLIENT);
|
||||
}
|
||||
client_->CheckErrorCode(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
|
||||
}
|
||||
|
||||
// Resume-eligible reconnect with an EPSK configured.
|
||||
// Expect the EPSK to be used.
|
||||
TEST_P(Tls13PskTest, PreferEpsk) {
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
Connect();
|
||||
SendReceive(); // Need to read so that we absorb the session ticket.
|
||||
CheckKeys();
|
||||
|
||||
Reset();
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
ExpectResumption(RESUME_NONE);
|
||||
StartConnect();
|
||||
Handshake();
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
// Enable resumption, but connect (initially) with an EPSK.
|
||||
// Expect no session ticket.
|
||||
TEST_P(Tls13PskTest, SuppressNewSessionTicket) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
auto nst_capture =
|
||||
MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_new_session_ticket);
|
||||
nst_capture->EnableDecryption();
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
|
||||
EXPECT_EQ(0U, nst_capture->buffer().len());
|
||||
if (variant_ == ssl_variant_stream) {
|
||||
EXPECT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
|
||||
} else {
|
||||
EXPECT_EQ(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, PORT_GetError());
|
||||
}
|
||||
|
||||
Reset();
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
ExpectResumption(RESUME_NONE);
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
TEST_P(Tls13PskTest, BadConfigValues) {
|
||||
EXPECT_TRUE(client_->EnsureTlsSetup());
|
||||
std::vector<uint8_t> label{'L', 'A', 'B', 'E', 'L'};
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_AddExternalPsk(client_->ssl_fd(), nullptr, label.data(),
|
||||
label.size(), kPskHash_));
|
||||
EXPECT_EQ(SECFailure, SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
|
||||
nullptr, label.size(), kPskHash_));
|
||||
|
||||
EXPECT_EQ(SECFailure, SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
|
||||
label.data(), 0, kPskHash_));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_AddExternalPsk(client_->ssl_fd(), scoped_psk_.get(),
|
||||
label.data(), label.size(), ssl_hash_sha256));
|
||||
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RemoveExternalPsk(client_->ssl_fd(), nullptr, label.size()));
|
||||
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RemoveExternalPsk(client_->ssl_fd(), label.data(), 0));
|
||||
|
||||
EXPECT_EQ(SECSuccess, SSL_RemoveExternalPsk(client_->ssl_fd(), label.data(),
|
||||
label.size()));
|
||||
}
|
||||
|
||||
// If the server has an EPSK configured with a ciphersuite not supported
|
||||
// by the client, it should use certificate authentication.
|
||||
TEST_P(Tls13PskTest, FallbackUnsupportedCiphersuite) {
|
||||
client_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
|
||||
TLS_AES_128_GCM_SHA256);
|
||||
server_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
|
||||
client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
|
||||
}
|
||||
|
||||
// That fallback should not occur if there is no cipher overlap.
|
||||
TEST_P(Tls13PskTest, ExplicitSuiteNoOverlap) {
|
||||
client_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
|
||||
TLS_AES_128_GCM_SHA256);
|
||||
server_->AddPsk(scoped_psk_, kPskDummyLabel_, ssl_hash_sha256,
|
||||
TLS_CHACHA20_POLY1305_SHA256);
|
||||
|
||||
client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
|
||||
server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
TEST_P(Tls13PskTest, SuppressHandshakeCertReq) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
server_->SetOption(SSL_REQUEST_CERTIFICATE, PR_TRUE);
|
||||
server_->SetOption(SSL_REQUIRE_CERTIFICATE, PR_TRUE);
|
||||
const std::set<uint8_t> hs_types = {ssl_hs_certificate,
|
||||
ssl_hs_certificate_request};
|
||||
auto cr_cert_capture = MakeTlsFilter<TlsHandshakeRecorder>(server_, hs_types);
|
||||
cr_cert_capture->EnableDecryption();
|
||||
|
||||
Connect();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
EXPECT_EQ(0U, cr_cert_capture->buffer().len());
|
||||
}
|
||||
|
||||
TEST_P(Tls13PskTest, DisallowClientConfigWithoutServerCert) {
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
|
||||
server_->SetOption(SSL_REQUEST_CERTIFICATE, PR_TRUE);
|
||||
server_->SetOption(SSL_REQUIRE_CERTIFICATE, PR_TRUE);
|
||||
const std::set<uint8_t> hs_types = {ssl_hs_certificate,
|
||||
ssl_hs_certificate_request};
|
||||
auto cr_cert_capture = MakeTlsFilter<TlsHandshakeRecorder>(server_, hs_types);
|
||||
cr_cert_capture->EnableDecryption();
|
||||
|
||||
EXPECT_EQ(SECSuccess, SSLInt_RemoveServerCertificates(server_->ssl_fd()));
|
||||
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
EXPECT_EQ(0U, cr_cert_capture->buffer().len());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ClientRejectHandshakeCertReq) {
|
||||
// Stream only, as the filter doesn't support DTLS 1.3 yet.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(!!slot);
|
||||
ScopedPK11SymKey scoped_psk(PK11_KeyGen(
|
||||
slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 32, nullptr));
|
||||
AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256);
|
||||
// Inject a CR after EE. This would be legal if not for ssl_auth_psk.
|
||||
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
|
||||
server_, kTlsHandshakeFinished, kTlsHandshakeCertificateRequest);
|
||||
filter->EnableDecryption();
|
||||
|
||||
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
|
||||
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, RejectPha) {
|
||||
// Stream only, as the filter doesn't support DTLS 1.3 yet.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(!!slot);
|
||||
ScopedPK11SymKey scoped_psk(PK11_KeyGen(
|
||||
slot.get(), CKM_GENERIC_SECRET_KEY_GEN, nullptr, 32, nullptr));
|
||||
AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256);
|
||||
server_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
|
||||
auto kuToCr = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
|
||||
server_, kTlsHandshakeKeyUpdate, kTlsHandshakeCertificateRequest);
|
||||
kuToCr->EnableDecryption();
|
||||
Connect();
|
||||
|
||||
// Make sure the direct path is blocked.
|
||||
EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
|
||||
EXPECT_EQ(SSL_ERROR_FEATURE_DISABLED, PORT_GetError());
|
||||
|
||||
// Inject a PHA CR. Since this is not allowed, send KeyUpdate
|
||||
// and change the message type.
|
||||
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
|
||||
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
|
||||
client_->Handshake(); // Eat the CR.
|
||||
server_->Handshake();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
|
||||
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
|
||||
}
|
||||
|
||||
class Tls13PskTestWithCiphers : public Tls13PskTest {};
|
||||
|
||||
TEST_P(Tls13PskTestWithCiphers, 0RttCiphers) {
|
||||
RolloverAntiReplay();
|
||||
AddPsk(scoped_psk_, kPskDummyLabel_, tls13_GetHashForCipherSuite(suite_),
|
||||
suite_);
|
||||
StartConnect();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
|
||||
}
|
||||
|
||||
TEST_P(Tls13PskTestWithCiphers, 0RttMaxEarlyData) {
|
||||
EnsureTlsSetup();
|
||||
RolloverAntiReplay();
|
||||
const char* big_message = "0123456789abcdef";
|
||||
const size_t short_size = strlen(big_message) - 1;
|
||||
const PRInt32 short_length = static_cast<PRInt32>(short_size);
|
||||
|
||||
// Set up the PSK
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_AddExternalPsk0Rtt(
|
||||
client_->ssl_fd(), scoped_psk_.get(),
|
||||
reinterpret_cast<const uint8_t*>(kPskDummyLabel_.data()),
|
||||
kPskDummyLabel_.length(), tls13_GetHashForCipherSuite(suite_),
|
||||
suite_, short_length));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_AddExternalPsk0Rtt(
|
||||
server_->ssl_fd(), scoped_psk_.get(),
|
||||
reinterpret_cast<const uint8_t*>(kPskDummyLabel_.data()),
|
||||
kPskDummyLabel_.length(), tls13_GetHashForCipherSuite(suite_),
|
||||
suite_, short_length));
|
||||
client_->ExpectPsk();
|
||||
server_->ExpectPsk();
|
||||
client_->expected_cipher_suite(suite_);
|
||||
server_->expected_cipher_suite(suite_);
|
||||
StartConnect();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
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();
|
||||
}
|
||||
|
||||
static const uint16_t k0RttCipherDefs[] = {TLS_CHACHA20_POLY1305_SHA256,
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_AES_256_GCM_SHA384};
|
||||
|
||||
static const uint16_t kDefaultSuite[] = {TLS_CHACHA20_POLY1305_SHA256};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Tls13PskTest, Tls13PskTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
::testing::ValuesIn(kDefaultSuite)));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Tls13PskTestWithCiphers, Tls13PskTestWithCiphers,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
::testing::ValuesIn(k0RttCipherDefs)));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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/. */
|
||||
|
|
@ -8,6 +9,8 @@
|
|||
#include "prtime.h"
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "nss.h"
|
||||
#include "blapit.h"
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "tls_agent.h"
|
||||
|
|
@ -17,9 +20,10 @@ namespace nss_test {
|
|||
|
||||
const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256;
|
||||
const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048;
|
||||
const std::string kPssDelegatorId = TlsAgent::kDelegatorRsaPss2048;
|
||||
const std::string kDCId = TlsAgent::kServerEcdsa256;
|
||||
const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
|
||||
const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
|
||||
const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds) */;
|
||||
|
||||
static void CheckPreliminaryPeerDelegCred(
|
||||
const std::shared_ptr<TlsAgent>& client, bool expected,
|
||||
|
|
@ -121,6 +125,23 @@ TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
|
|||
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with ECDSA-P384.
|
||||
TEST_P(TlsConnectTls13, DCConnectEcdsaP483) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa384,
|
||||
ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor,
|
||||
now());
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, true, 384);
|
||||
EXPECT_EQ(ssl_sig_ecdsa_secp384r1_sha384, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with ECDSA-P521.
|
||||
TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
|
|
@ -139,46 +160,8 @@ TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
|
|||
EXPECT_EQ(ssl_sig_ecdsa_secp521r1_sha512, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with RSA-PSS, using an RSAE DC SPKI.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(
|
||||
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now());
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, true, 1024);
|
||||
EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with RSA-PSS, using a RSAE Delegator SPKI.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
|
||||
Reset(kRsaeDelegatorId);
|
||||
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(
|
||||
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, true, 1024);
|
||||
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with RSA-PSS, using a PSS SPKI.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
|
||||
// Connected with RSA-PSS, using a PSS SPKI and ECDSA delegation cert.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaPssEcdsa) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
|
||||
// Need to enable PSS-PSS, which is not on by default.
|
||||
|
|
@ -200,6 +183,166 @@ TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
|
|||
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with RSA-PSS, using a PSS SPKI and PSS delegation cert.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaPssRsaPss) {
|
||||
Reset(kPssDelegatorId);
|
||||
|
||||
// Need to enable PSS-PSS, which is not on by default.
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(
|
||||
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, true, 1024);
|
||||
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Connected with ECDSA-P256 using a PSS delegation cert.
|
||||
TEST_P(TlsConnectTls13, DCConnectEcdsaP256RsaPss) {
|
||||
Reset(kPssDelegatorId);
|
||||
|
||||
// Need to enable PSS-PSS, which is not on by default.
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
|
||||
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
|
||||
now());
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, true, 256);
|
||||
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
|
||||
}
|
||||
|
||||
// Simulate the client receiving a DC containing algorithms not advertised.
|
||||
// Do this by tweaking the client's supported sigSchemes after the CH.
|
||||
TEST_P(TlsConnectTls13, DCReceiveUnadvertisedScheme) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
static const SSLSignatureScheme kClientSchemes[] = {
|
||||
ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384};
|
||||
static const SSLSignatureScheme kServerSchemes[] = {
|
||||
ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_ecdsa_secp256r1_sha256};
|
||||
static const SSLSignatureScheme kEcdsaP256Only[] = {
|
||||
ssl_sig_ecdsa_secp256r1_sha256};
|
||||
client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
|
||||
server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes));
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa384,
|
||||
ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor,
|
||||
now());
|
||||
StartConnect();
|
||||
client_->Handshake(); // CH with P256/P384.
|
||||
server_->Handshake(); // Respond with P384 DC.
|
||||
// Tell the client it only advertised P256.
|
||||
SECStatus rv = SSLInt_SetDCAdvertisedSigSchemes(
|
||||
client_->ssl_fd(), kEcdsaP256Only, PR_ARRAY_SIZE(kEcdsaP256Only));
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
ExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
Handshake();
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Server schemes includes only RSAE schemes. Connection should succeed
|
||||
// without delegation.
|
||||
TEST_P(TlsConnectTls13, DCConnectServerRsaeOnly) {
|
||||
Reset(kRsaeDelegatorId);
|
||||
static const SSLSignatureScheme kClientSchemes[] = {
|
||||
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_pss_sha256};
|
||||
static const SSLSignatureScheme kServerSchemes[] = {
|
||||
ssl_sig_rsa_pss_rsae_sha256};
|
||||
client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
|
||||
server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes));
|
||||
client_->EnableDelegatedCredentials();
|
||||
Connect();
|
||||
|
||||
CheckPeerDelegCred(client_, false);
|
||||
}
|
||||
|
||||
// Connect with an RSA-PSS DC SPKI, and an RSAE Delegator SPKI.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
|
||||
Reset(kRsaeDelegatorId);
|
||||
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(
|
||||
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
// Client schemes includes only RSAE schemes. Connection should succeed
|
||||
// without delegation, and no DC extension should be present in the CH.
|
||||
TEST_P(TlsConnectTls13, DCConnectClientRsaeOnly) {
|
||||
Reset(kRsaeDelegatorId);
|
||||
static const SSLSignatureScheme kClientSchemes[] = {
|
||||
ssl_sig_rsa_pss_rsae_sha256};
|
||||
static const SSLSignatureScheme kServerSchemes[] = {
|
||||
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
|
||||
server_->SetSignatureSchemes(kServerSchemes, PR_ARRAY_SIZE(kServerSchemes));
|
||||
client_->EnableDelegatedCredentials();
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
EXPECT_FALSE(cfilter->captured());
|
||||
CheckPeerDelegCred(client_, false);
|
||||
}
|
||||
|
||||
// Test fallback. DC extension will not advertise RSAE schemes.
|
||||
// The server will attempt to set one, but decline to after seeing
|
||||
// the client-advertised schemes does not include it. Expect non-
|
||||
// delegated success.
|
||||
TEST_P(TlsConnectTls13, DCConnectRsaeDcSpki) {
|
||||
Reset(kRsaeDelegatorId);
|
||||
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
client_->EnableDelegatedCredentials();
|
||||
|
||||
EnsureTlsSetup();
|
||||
ScopedSECKEYPublicKey pub;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
EXPECT_TRUE(
|
||||
TlsAgent::LoadKeyPairFromCert(TlsAgent::kDelegatorRsae2048, &pub, &priv));
|
||||
|
||||
StackSECItem dc;
|
||||
server_->DelegateCredential(server_->name(), pub, ssl_sig_rsa_pss_rsae_sha256,
|
||||
kDCValidFor, now(), &dc);
|
||||
|
||||
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
|
||||
nullptr, &dc, priv.get()};
|
||||
EXPECT_TRUE(server_->ConfigServerCert(server_->name(), true, &extra_data));
|
||||
auto sfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
server_, ssl_delegated_credentials_xtn);
|
||||
Connect();
|
||||
EXPECT_FALSE(sfilter->captured());
|
||||
CheckPeerDelegCred(client_, false);
|
||||
}
|
||||
|
||||
// Generate a weak key. We can't do this in the fixture because certutil
|
||||
// won't sign with such a tiny key. That's OK, because this is fast(ish).
|
||||
static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
|
||||
|
|
@ -207,44 +350,44 @@ static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
|
|||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_TRUE(slot);
|
||||
PK11RSAGenParams rsaparams;
|
||||
// The absolute minimum size of RSA key that we can use with SHA-256 is
|
||||
// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528.
|
||||
// The absolute minimum size of RSA key that we can use with SHA-256 is
|
||||
// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528.
|
||||
#define RSA_WEAK_KEY 528
|
||||
#if RSA_MIN_MODULUS_BITS < RSA_WEAK_KEY
|
||||
rsaparams.keySizeInBits = 528;
|
||||
#else
|
||||
rsaparams.keySizeInBits = RSA_MIN_MODULUS_BITS + 1;
|
||||
#endif
|
||||
rsaparams.pe = 65537;
|
||||
|
||||
// Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
|
||||
// entropy to generate a random key. We can fake some.
|
||||
for (int retry = 0; retry < 10; ++retry) {
|
||||
SECKEYPublicKey* p_pub = nullptr;
|
||||
priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
|
||||
&rsaparams, &p_pub, false, false, nullptr));
|
||||
pub.reset(p_pub);
|
||||
if (priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_FALSE(pub);
|
||||
if (PORT_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
|
||||
break;
|
||||
}
|
||||
|
||||
// https://xkcd.com/221/
|
||||
static const uint8_t FRESH_ENTROPY[16] = {4};
|
||||
ASSERT_EQ(
|
||||
SECSuccess,
|
||||
PK11_RandomUpdate(
|
||||
const_cast<void*>(reinterpret_cast<const void*>(FRESH_ENTROPY)),
|
||||
sizeof(FRESH_ENTROPY)));
|
||||
break;
|
||||
}
|
||||
ADD_FAILURE() << "Unable to generate an RSA key: "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
SECKEYPublicKey* p_pub = nullptr;
|
||||
priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
|
||||
&rsaparams, &p_pub, false, false, nullptr));
|
||||
pub.reset(p_pub);
|
||||
PR_ASSERT(priv);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fail to connect with a weak RSA key.
|
||||
TEST_P(TlsConnectTls13, DCWeakKey) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
Reset(kPssDelegatorId);
|
||||
EnsureTlsSetup();
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY
|
||||
// save the MIN POLICY length.
|
||||
PRInt32 minRsa;
|
||||
|
||||
ASSERT_EQ(SECSuccess, NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minRsa));
|
||||
#if RSA_MIN_MODULUS_BITS >= 2048
|
||||
ASSERT_EQ(SECSuccess,
|
||||
NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, RSA_MIN_MODULUS_BITS + 1024));
|
||||
#else
|
||||
ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 2048));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ScopedSECKEYPrivateKey dc_priv;
|
||||
ScopedSECKEYPublicKey dc_pub;
|
||||
|
|
@ -253,20 +396,23 @@ TEST_P(TlsConnectTls13, DCWeakKey) {
|
|||
|
||||
// Construct a DC.
|
||||
StackSECItem dc;
|
||||
TlsAgent::DelegateCredential(kEcdsaDelegatorId, dc_pub,
|
||||
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now(),
|
||||
TlsAgent::DelegateCredential(kPssDelegatorId, dc_pub,
|
||||
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now(),
|
||||
&dc);
|
||||
|
||||
// Configure the DC on the server.
|
||||
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
|
||||
nullptr, &dc, dc_priv.get()};
|
||||
EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
|
||||
EXPECT_TRUE(server_->ConfigServerCert(kPssDelegatorId, true, &extra_data));
|
||||
|
||||
client_->EnableDelegatedCredentials();
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
client_, ssl_delegated_credentials_xtn);
|
||||
ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity);
|
||||
#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY
|
||||
ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, minRsa));
|
||||
#endif
|
||||
}
|
||||
|
||||
class ReplaceDCSigScheme : public TlsHandshakeFilter {
|
||||
|
|
@ -313,8 +459,8 @@ TEST_P(TlsConnectTls13, DCAbortBadSignature) {
|
|||
now(), &dc);
|
||||
ASSERT_TRUE(dc.data != nullptr);
|
||||
|
||||
// Flip the first bit of the DC so that the signature is invalid.
|
||||
dc.data[0] ^= 0x01;
|
||||
// Flip the last bit of the DC so that the signature is invalid.
|
||||
dc.data[dc.len - 1] ^= 0x01;
|
||||
|
||||
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
|
||||
nullptr, &dc, priv.get()};
|
||||
|
|
@ -338,6 +484,17 @@ TEST_P(TlsConnectTls13, DCAbortExpired) {
|
|||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Aborted due to remaining TTL > max validity period.
|
||||
TEST_P(TlsConnectTls13, DCAbortExcessiveTTL) {
|
||||
Reset(kEcdsaDelegatorId);
|
||||
server_->AddDelegatedCredential(kDCId, kDCScheme,
|
||||
kDCValidFor + 1 /* seconds */, now());
|
||||
client_->EnableDelegatedCredentials();
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
client_->CheckErrorCode(SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
}
|
||||
|
||||
// Aborted because of invalid key usage.
|
||||
TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) {
|
||||
// The sever does not have the delegationUsage extension.
|
||||
|
|
@ -528,19 +685,18 @@ TEST_F(DCDelegation, DCDelegations) {
|
|||
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
|
||||
|
||||
// Using different PSS hashes should be OK.
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(),
|
||||
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
|
||||
now, &dc));
|
||||
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
|
||||
cert.get(), priv.get(), pub_rsa.get(),
|
||||
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
|
||||
// Make sure to reset |dc| after each success.
|
||||
dc.Reset();
|
||||
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
|
||||
cert.get(), priv.get(), pub_rsa.get(),
|
||||
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
|
||||
ssl_sig_rsa_pss_pss_sha384, kDCValidFor, now, &dc));
|
||||
dc.Reset();
|
||||
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
|
||||
cert.get(), priv.get(), pub_rsa.get(),
|
||||
ssl_sig_rsa_pss_pss_sha384, kDCValidFor, now, &dc));
|
||||
ssl_sig_rsa_pss_pss_sha512, kDCValidFor, now, &dc));
|
||||
dc.Reset();
|
||||
|
||||
ScopedSECKEYPublicKey pub_ecdsa;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue