summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/ssl_gtest')
-rw-r--r--security/nss/gtests/ssl_gtest/bloomfilter_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/gtest_utils.h1
-rw-r--r--security/nss/gtests/ssl_gtest/libssl_internals.c110
-rw-r--r--security/nss/gtests/ssl_gtest/libssl_internals.h6
-rw-r--r--security/nss/gtests/ssl_gtest/manifest.mn4
-rw-r--r--security/nss/gtests/ssl_gtest/rsa8193.h1
-rw-r--r--security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc185
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_aead_unittest.cc (renamed from security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc)7
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc186
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc30
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc72
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc38
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc89
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gtest.gyp16
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc144
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_keyupdate_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc350
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_misc_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_record_unittest.cc64
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc107
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc37
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_renegotiation_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc87
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc95
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_version_unittest.cc134
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.h1
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.cc86
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.h17
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.cc22
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.h6
-rw-r--r--security/nss/gtests/ssl_gtest/tls_esni_unittest.cc11
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.cc208
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.h121
-rw-r--r--security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc25
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.cc98
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.h6
-rw-r--r--security/nss/gtests/ssl_gtest/tls_psk_unittest.cc514
-rw-r--r--security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc209
57 files changed, 2818 insertions, 292 deletions
diff --git a/security/nss/gtests/ssl_gtest/bloomfilter_unittest.cc b/security/nss/gtests/ssl_gtest/bloomfilter_unittest.cc
index 553d47459..6efe06ec7 100644
--- a/security/nss/gtests/ssl_gtest/bloomfilter_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/bloomfilter_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/gtest_utils.h b/security/nss/gtests/ssl_gtest/gtest_utils.h
index 8e61228e6..2344c3cea 100644
--- a/security/nss/gtests/ssl_gtest/gtest_utils.h
+++ b/security/nss/gtests/ssl_gtest/gtest_utils.h
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.c b/security/nss/gtests/ssl_gtest/libssl_internals.c
index a986c6c83..854eca07f 100644
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -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,8 +9,56 @@
#include "nss.h"
#include "pk11pub.h"
+#include "pk11priv.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 +145,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 +354,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 +367,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 +422,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;
diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.h b/security/nss/gtests/ssl_gtest/libssl_internals.h
index 9cdd9ec72..4b076c2ee 100644
--- a/security/nss/gtests/ssl_gtest/libssl_internals.h
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.h
@@ -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,9 @@ 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);
#endif // ndef libssl_internals_h_
diff --git a/security/nss/gtests/ssl_gtest/manifest.mn b/security/nss/gtests/ssl_gtest/manifest.mn
index ed1128f7c..2cfa7cdd2 100644
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -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,6 +56,7 @@ CPPSRCS = \
tls_hkdf_unittest.cc \
tls_filter.cc \
tls_protect.cc \
+ tls_psk_unittest.cc \
tls_subcerts_unittest.cc \
tls_esni_unittest.cc \
$(SSLKEYLOGFILE_FILES) \
diff --git a/security/nss/gtests/ssl_gtest/rsa8193.h b/security/nss/gtests/ssl_gtest/rsa8193.h
index f3c79518f..1ac8503bc 100644
--- a/security/nss/gtests/ssl_gtest/rsa8193.h
+++ b/security/nss/gtests/ssl_gtest/rsa8193.h
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc b/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
index 82319b099..0c62c4cac 100644
--- a/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/selfencrypt_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
index 941df7020..f873d265b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -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,6 +1146,35 @@ 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);
diff --git a/security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_aead_unittest.cc
index 79509e558..d94683be3 100644
--- a/security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_aead_unittest.cc
@@ -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,
diff --git a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
index fd776f6e4..c3455d130 100644
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
index 0454db8cd..5c6eee7b6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -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,8 +214,7 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
MakeTlsFilter<TlsCertificateRequestContextRecorder>(
client_, kTlsHandshakeCertificate);
client_->SetupClientAuth();
- EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
- SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
+ client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
@@ -252,6 +252,47 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
+TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterResumption) {
+ 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);
+
+ client_->SetupClientAuth();
+ client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
+ Connect();
+ SendReceive();
+
+ size_t called = 0;
+ server_->SetAuthCertificateCallback(
+ [&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
+ called++;
+ return SECSuccess;
+ });
+ EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
+ << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
+ server_->SendData(50);
+ client_->ReadBytes(50);
+ client_->SendData(50);
+ server_->ReadBytes(50);
+ EXPECT_EQ(1U, called);
+
+ ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
+ ASSERT_NE(nullptr, cert1.get());
+ ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
+ ASSERT_NE(nullptr, cert2.get());
+ EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
+}
+
static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd,
CERTDistNames* caNames,
CERTCertificate** clientCert,
@@ -874,6 +915,104 @@ TEST_P(TlsConnectTls12, ClientAuthNoSigAlgs) {
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
}
+static SECStatus GetEcClientAuthDataHook(void* self, PRFileDesc* fd,
+ CERTDistNames* caNames,
+ CERTCertificate** clientCert,
+ SECKEYPrivateKey** clientKey) {
+ ScopedCERTCertificate cert;
+ ScopedSECKEYPrivateKey priv;
+ // use a different certificate than TlsAgent::kClient
+ if (!TlsAgent::LoadCertificate(TlsAgent::kServerEcdsa256, &cert, &priv)) {
+ return SECFailure;
+ }
+
+ *clientCert = cert.release();
+ *clientKey = priv.release();
+ return SECSuccess;
+}
+
+TEST_P(TlsConnectTls12Plus, ClientAuthDisjointSchemes) {
+ EnsureTlsSetup();
+ client_->SetupClientAuth();
+ server_->RequestClientAuth(true);
+
+ SSLSignatureScheme server_scheme = ssl_sig_rsa_pss_rsae_sha256;
+ std::vector<SSLSignatureScheme> client_schemes{
+ ssl_sig_rsa_pss_rsae_sha256, ssl_sig_ecdsa_secp256r1_sha256};
+ SECStatus rv =
+ SSL_SignatureSchemePrefSet(server_->ssl_fd(), &server_scheme, 1);
+ EXPECT_EQ(SECSuccess, rv);
+ rv = SSL_SignatureSchemePrefSet(
+ client_->ssl_fd(), client_schemes.data(),
+ static_cast<unsigned int>(client_schemes.size()));
+ EXPECT_EQ(SECSuccess, rv);
+
+ // Select an EC cert that's incompatible with server schemes.
+ EXPECT_EQ(SECSuccess,
+ SSL_GetClientAuthDataHook(client_->ssl_fd(),
+ GetEcClientAuthDataHook, nullptr));
+
+ StartConnect();
+ client_->Handshake(); // CH
+ server_->Handshake(); // SH
+ client_->Handshake();
+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+ ExpectAlert(server_, kTlsAlertCertificateRequired);
+ server_->Handshake(); // Alert
+ server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
+ client_->Handshake(); // Receive Alert
+ client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
+ } else {
+ ASSERT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
+ ExpectAlert(server_, kTlsAlertBadCertificate);
+ server_->Handshake(); // Alert
+ server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
+ client_->Handshake(); // Receive Alert
+ client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
+ }
+}
+
+TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDisjointSchemes) {
+ EnsureTlsSetup();
+ SSLSignatureScheme server_scheme = ssl_sig_rsa_pss_rsae_sha256;
+ std::vector<SSLSignatureScheme> client_schemes{
+ ssl_sig_rsa_pss_rsae_sha256, ssl_sig_ecdsa_secp256r1_sha256};
+ SECStatus rv =
+ SSL_SignatureSchemePrefSet(server_->ssl_fd(), &server_scheme, 1);
+ EXPECT_EQ(SECSuccess, rv);
+ rv = SSL_SignatureSchemePrefSet(
+ client_->ssl_fd(), client_schemes.data(),
+ static_cast<unsigned int>(client_schemes.size()));
+ EXPECT_EQ(SECSuccess, rv);
+
+ client_->SetupClientAuth();
+ client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
+
+ // Select an EC cert that's incompatible with server schemes.
+ EXPECT_EQ(SECSuccess,
+ SSL_GetClientAuthDataHook(client_->ssl_fd(),
+ GetEcClientAuthDataHook, nullptr));
+
+ Connect();
+
+ // Send CertificateRequest.
+ EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
+ << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
+
+ // Need to do a round-trip so that the post-handshake message is
+ // handled on both client and server.
+ server_->SendData(50);
+ client_->ReadBytes(50);
+ client_->SendData(50);
+ server_->ReadBytes(50);
+
+ ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
+ ASSERT_EQ(nullptr, cert1.get());
+ ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
+ ASSERT_EQ(nullptr, cert2.get());
+}
+
static const SSLSignatureScheme kSignatureSchemeEcdsaSha384[] = {
ssl_sig_ecdsa_secp384r1_sha384};
static const SSLSignatureScheme kSignatureSchemeEcdsaSha256[] = {
@@ -1191,7 +1330,7 @@ TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) {
// This test uses a simple AuthCertificateCallback. Due to the way that the
// entire server flight is processed, the call to SSL_AuthCertificateComplete
// will trigger after the Finished message is processed.
-TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) {
+TEST_P(TlsConnectTls13, AuthCompleteAfterFinished) {
SetDeferredAuthCertificateCallback(client_, 0); // 0 = success.
Connect();
}
@@ -1550,6 +1689,47 @@ TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedServer) {
capture->extension());
}
+TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedClient) {
+ EnsureTlsSetup();
+ static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
+ ssl_sig_rsa_pss_rsae_sha256};
+ client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+ auto capture =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+ Connect();
+ // We should only have the one signature algorithm advertised.
+ static const uint8_t kExpectedExt[] = {0,
+ 4,
+ ssl_sig_rsa_pss_rsae_sha256 >> 8,
+ ssl_sig_rsa_pss_rsae_sha256 & 0xff,
+ ssl_sig_rsa_pkcs1_sha256 >> 8,
+ ssl_sig_rsa_pkcs1_sha256 & 0xff};
+ ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
+ capture->extension());
+}
+
+TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedServer) {
+ EnsureTlsSetup();
+ static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
+ ssl_sig_rsa_pss_rsae_sha256};
+ server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+ auto capture = MakeTlsFilter<TlsExtensionCapture>(
+ server_, ssl_signature_algorithms_xtn, true);
+ capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
+ capture->EnableDecryption();
+ server_->RequestClientAuth(false); // So we get a CertificateRequest.
+ Connect();
+ // We should only have the one signature algorithm advertised.
+ static const uint8_t kExpectedExt[] = {0,
+ 4,
+ ssl_sig_rsa_pss_rsae_sha256 >> 8,
+ ssl_sig_rsa_pss_rsae_sha256 & 0xff,
+ ssl_sig_rsa_pkcs1_sha256 >> 8,
+ ssl_sig_rsa_pkcs1_sha256 & 0xff};
+ ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
+ capture->extension());
+}
+
// variant, version, certificate, auth type, signature scheme
typedef std::tuple<SSLProtocolVariant, uint16_t, std::string, SSLAuthType,
SSLSignatureScheme>
diff --git a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
index bd66e3465..26e5fb502 100644
--- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
index 46d934868..1e4f817e9 100644
--- a/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
index ba7b775f0..86cb02d73 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -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/. */
@@ -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();
diff --git a/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
index 8ee60defe..68c789a38 100644
--- a/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
index a146ffc2f..9cbe9566f 100644
--- a/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
index 48b813a2f..59ec3d393 100644
--- a/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
index 60ad017e3..0fe88ea88 100644
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
index 7e2f9aded..05b38e381 100644
--- a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
@@ -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)));
diff --git a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
index b2759ef5d..e62e002f3 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
index dc2b92881..39b2d5873 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
index ac75aa1b1..26ed6bc0e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
@@ -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
diff --git a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
index 87b8e4ace..fb995953f 100644
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -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,
@@ -188,8 +228,27 @@ 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) {
+#ifdef DTLS_1_3_DRAFT_VERSION
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ version = 0x7f00 | DTLS_1_3_DRAFT_VERSION;
+ break;
+#endif
+ 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>(
@@ -887,6 +946,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();
@@ -1226,6 +1305,14 @@ TEST_P(TlsConnectStream, IncludePadding) {
EXPECT_TRUE(capture->captured());
}
+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);
+}
+
INSTANTIATE_TEST_CASE_P(
ExtensionStream, TlsExtensionTestGeneric,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
diff --git a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
index 004d3fe9f..375281263 100644
--- a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
index 4ab5e1797..745432951 100644
--- a/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
index 6cff0fc9d..5491a0725 100644
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -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',
@@ -56,6 +57,7 @@
'tls_hkdf_unittest.cc',
'tls_esni_unittest.cc',
'tls_protect.cc',
+ 'tls_psk_unittest.cc',
'tls_subcerts_unittest.cc'
],
'dependencies': [
@@ -103,6 +105,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',
+ ],
+ }],
],
}
],
diff --git a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
index ec6c95d60..56b7a2bf0 100644
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -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/. */
@@ -1054,6 +1055,41 @@ TEST_F(TlsConnectTest, Select12AfterHelloRetryRequest) {
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
}
+// This class increments the low byte of the first Handshake.message_seq
+// field in every handshake record.
+class MessageSeqIncrementer : public TlsRecordFilter {
+ public:
+ MessageSeqIncrementer(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a) {}
+
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& data,
+ DataBuffer* changed) override {
+ if (header.content_type() != ssl_ct_handshake) {
+ return KEEP;
+ }
+
+ *changed = data;
+ // struct { uint8 msg_type; uint24 length; uint16 message_seq; ... }
+ // Handshake;
+ changed->data()[5]++;
+ EXPECT_NE(0, changed->data()[5]); // Check for overflow.
+ return CHANGE;
+ }
+};
+
+// A server that receives a ClientHello with message_seq == 1
+// assumes that this is after a stateless HelloRetryRequest.
+// However, it should reject the ClientHello if it lacks a cookie.
+TEST_F(TlsConnectDatagram13, MessageSeq1ClientHello) {
+ EnsureTlsSetup();
+ MakeTlsFilter<MessageSeqIncrementer>(client_);
+ ConnectExpectAlert(server_, kTlsAlertMissingExtension);
+ EXPECT_EQ(SSL_ERROR_MISSING_COOKIE_EXTENSION, server_->error_code());
+ EXPECT_EQ(SSL_ERROR_MISSING_EXTENSION_ALERT, client_->error_code());
+}
+
class HelloRetryRequestAgentTest : public TlsAgentTestClient {
protected:
void SetUp() override {
@@ -1177,6 +1213,114 @@ TEST_P(TlsConnectStreamPre13, HrrRandomOnTls10) {
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
+TEST_F(TlsConnectStreamTls13, HrrThenTls12) {
+ StartConnect();
+ size_t cb_called = 0;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
+ RetryHello, &cb_called));
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+
+ client_->Handshake(); // Send CH (1.3)
+ server_->Handshake(); // Send HRR.
+ EXPECT_EQ(1U, cb_called);
+
+ // Replace the client with a new TLS 1.2 client. Don't call Init(), since
+ // it will artifically limit the server's vrange.
+ client_.reset(
+ new TlsAgent(client_->name(), TlsAgent::CLIENT, ssl_variant_stream));
+ client_->SetPeer(server_);
+ server_->SetPeer(client_);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+
+ client_->StartConnect();
+ client_->Handshake(); // Send CH (1.2)
+ ExpectAlert(server_, kTlsAlertProtocolVersion);
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+ client_->Handshake();
+ client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+}
+
+TEST_F(TlsConnectStreamTls13, ZeroRttHrrThenTls12) {
+ SetupForZeroRtt();
+
+ client_->Set0RttEnabled(true);
+ size_t cb_called = 0;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
+ RetryHello, &cb_called));
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+
+ client_->Handshake(); // Send CH (1.3)
+ ZeroRttSendReceive(true, false);
+ server_->Handshake(); // Send HRR.
+ EXPECT_EQ(1U, cb_called);
+
+ // Replace the client with a new TLS 1.2 client. Don't call Init(), since
+ // it will artifically limit the server's vrange.
+ client_.reset(
+ new TlsAgent(client_->name(), TlsAgent::CLIENT, ssl_variant_stream));
+ client_->SetPeer(server_);
+ server_->SetPeer(client_);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+
+ client_->StartConnect();
+ client_->Handshake(); // Send CH (1.2)
+ ExpectAlert(server_, kTlsAlertProtocolVersion);
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+ client_->Handshake();
+ client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+
+ // Try to write something
+ server_->Handshake();
+ client_->ExpectReadWriteError();
+ client_->SendData(1);
+ uint8_t buf[1];
+ EXPECT_EQ(-1, PR_Read(server_->ssl_fd(), buf, sizeof(buf)));
+ EXPECT_EQ(SSL_ERROR_HANDSHAKE_FAILED, PR_GetError());
+}
+
+TEST_F(TlsConnectStreamTls13, HrrThenTls12SupportedVersions) {
+ SetupForZeroRtt();
+ client_->Set0RttEnabled(true);
+ size_t cb_called = 0;
+ EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
+ RetryHello, &cb_called));
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+
+ client_->Handshake(); // Send CH (1.3)
+ ZeroRttSendReceive(true, false);
+ server_->Handshake(); // Send HRR.
+ EXPECT_EQ(1U, cb_called);
+
+ // Replace the client with a new TLS 1.2 client. Don't call Init(), since
+ // it will artifically limit the server's vrange.
+ client_.reset(
+ new TlsAgent(client_->name(), TlsAgent::CLIENT, ssl_variant_stream));
+ client_->SetPeer(server_);
+ server_->SetPeer(client_);
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+ // Negotiate via supported_versions
+ static const uint8_t tls12[] = {0x02, 0x03, 0x03};
+ auto replacer = MakeTlsFilter<TlsExtensionInjector>(
+ client_, ssl_tls13_supported_versions_xtn,
+ DataBuffer(tls12, sizeof(tls12)));
+
+ client_->StartConnect();
+ client_->Handshake(); // Send CH (1.2)
+ ExpectAlert(server_, kTlsAlertProtocolVersion);
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
+ client_->Handshake();
+ client_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
+}
+
INSTANTIATE_TEST_CASE_P(HelloRetryRequestAgentTests, HelloRetryRequestAgentTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
diff --git a/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
index c07eec1da..4713e52a2 100644
--- a/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_keyupdate_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_keyupdate_unittest.cc
index e0af9a641..b921d2c1e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_keyupdate_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_keyupdate_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
index 214e53a21..12c2496a6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc
new file mode 100644
index 000000000..cf0553cbb
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_masking_unittest.cc
@@ -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_CASE_P(GenericMasking, SuiteTest, kMaskingCiphersuiteParams);
+
+INSTANTIATE_TEST_CASE_P(GenericMasking, VariantTest,
+ TlsConnectTestBase::kTlsVariantsAll);
+
+INSTANTIATE_TEST_CASE_P(GenericMasking, VariantSuiteTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ kMaskingCiphersuiteParams));
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_misc_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_misc_unittest.cc
index f9bc4f421..2b1b92dcd 100644
--- a/security/nss/gtests/ssl_gtest/ssl_misc_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_misc_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
index dab0812e0..7c0dbca3b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
@@ -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
diff --git a/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
index 4333f5c74..8051b58d0 100644
--- a/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
@@ -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
diff --git a/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
index 8989ee801..8926b5551 100644
--- a/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
@@ -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;
@@ -260,30 +276,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;
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_renegotiation_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_renegotiation_unittest.cc
index d1c718163..072a1836c 100644
--- a/security/nss/gtests/ssl_gtest/ssl_renegotiation_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_renegotiation_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
index 38b0a4e79..c41240d8e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -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/. */
@@ -836,8 +837,8 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNST) {
Connect();
// Clear the session ticket keys to invalidate the old ticket.
- SSLInt_ClearSelfEncryptKey();
- SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0);
+ ClearServerCache();
+ EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0));
SendReceive(); // Need to read so that we absorb the session tickets.
CheckKeys();
@@ -884,7 +885,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 +915,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 +943,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);
@@ -1004,7 +1048,8 @@ TEST_F(TlsConnectStreamTls13, ExternalResumptionUseSecondTicket) {
state->invoked++;
return SECSuccess;
};
- SSL_SetResumptionTokenCallback(client_->ssl_fd(), cb, &ticket_state);
+ EXPECT_EQ(SECSuccess, SSL_SetResumptionTokenCallback(client_->ssl_fd(), cb,
+ &ticket_state));
Connect();
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
@@ -1445,4 +1490,34 @@ TEST_F(TlsConnectStreamTls13, ExternalTokenAfterHrr) {
SendReceive();
}
+TEST_F(TlsConnectStreamTls13, ExternalTokenWithPeerId) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ EXPECT_EQ(SECSuccess, SSL_SetSockPeerID(client_->ssl_fd(), "testPeerId"));
+ std::vector<uint8_t> ticket_state;
+ auto cb = [](PRFileDesc* fd, const PRUint8* ticket, unsigned int ticket_len,
+ void* arg) -> SECStatus {
+ EXPECT_NE(0U, ticket_len);
+ EXPECT_NE(nullptr, ticket);
+ auto ticket_state_ = reinterpret_cast<std::vector<uint8_t>*>(arg);
+ ticket_state_->assign(ticket, ticket + ticket_len);
+ return SECSuccess;
+ };
+ EXPECT_EQ(SECSuccess, SSL_SetResumptionTokenCallback(client_->ssl_fd(), cb,
+ &ticket_state));
+
+ Connect();
+ SendReceive();
+ EXPECT_NE(0U, ticket_state.size());
+
+ Reset();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
+ EXPECT_EQ(SECSuccess, SSL_SetSockPeerID(client_->ssl_fd(), "testPeerId"));
+ client_->SetResumptionToken(ticket_state);
+ ASSERT_TRUE(client_->MaybeSetResumptionToken());
+ ExpectResumption(RESUME_TICKET);
+ Connect();
+ SendReceive();
+}
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
index 8ffc6f37f..3ed42e86b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
index b06c8d943..abddaa5b6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
index 769413cc9..645f84ff0 100644
--- a/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
@@ -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/. */
@@ -347,6 +348,85 @@ TEST_F(TlsConnectStreamTls13, ChangeCipherSpecBeforeClientHelloTwice) {
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
+// The server accepts a ChangeCipherSpec even if the client advertises
+// an empty session ID.
+TEST_F(TlsConnectStreamTls13, ChangeCipherSpecAfterClientHelloEmptySid) {
+ EnsureTlsSetup();
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ client_->SendDirect(DataBuffer(kCannedCcs, sizeof(kCannedCcs))); // Send CCS
+
+ Handshake();
+ CheckConnected();
+}
+
+// The server rejects multiple ChangeCipherSpec even if the client
+// indicates compatibility mode with non-empty session ID.
+TEST_F(Tls13CompatTest, ChangeCipherSpecAfterClientHelloTwice) {
+ EnsureTlsSetup();
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ EnableCompatMode();
+
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ // Send CCS twice in a row
+ client_->SendDirect(DataBuffer(kCannedCcs, sizeof(kCannedCcs)));
+ client_->SendDirect(DataBuffer(kCannedCcs, sizeof(kCannedCcs)));
+
+ server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ server_->Handshake(); // Consume ClientHello and CCS.
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+}
+
+// The client accepts a ChangeCipherSpec even if it advertises an empty
+// session ID.
+TEST_F(TlsConnectStreamTls13, ChangeCipherSpecAfterServerHelloEmptySid) {
+ EnsureTlsSetup();
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+
+ // To replace Finished with a CCS below
+ auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
+ filter->SetHandshakeTypes({kTlsHandshakeFinished});
+ filter->EnableDecryption();
+
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ server_->Handshake(); // Consume ClientHello, and
+ // send ServerHello..CertificateVerify
+ // Send CCS
+ server_->SendDirect(DataBuffer(kCannedCcs, sizeof(kCannedCcs)));
+
+ // No alert is sent from the client. As Finished is dropped, we
+ // can't use Handshake() and CheckConnected().
+ client_->Handshake();
+}
+
+// The client rejects multiple ChangeCipherSpec in a row even if the
+// client indicates compatibility mode with non-empty session ID.
+TEST_F(Tls13CompatTest, ChangeCipherSpecAfterServerHelloTwice) {
+ EnsureTlsSetup();
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+ EnableCompatMode();
+
+ // To replace Finished with a CCS below
+ auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
+ filter->SetHandshakeTypes({kTlsHandshakeFinished});
+ filter->EnableDecryption();
+
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ server_->Handshake(); // Consume ClientHello, and
+ // send ServerHello..CertificateVerify
+ // the ServerHello is followed by CCS
+ // Send another CCS
+ server_->SendDirect(DataBuffer(kCannedCcs, sizeof(kCannedCcs)));
+ client_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
+ client_->Handshake(); // Consume ClientHello and CCS
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+}
+
// If we negotiate 1.2, we abort.
TEST_F(TlsConnectStreamTls13, ChangeCipherSpecBeforeClientHello12) {
EnsureTlsSetup();
@@ -383,14 +463,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));
}
}
@@ -439,8 +521,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;
diff --git a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
index 657dd70e6..cafbcce68 100644
--- a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
index c473fcbcf..419a4052b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
@@ -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,6 +102,61 @@ TEST_F(TlsConnectTest, TestDisableDowngradeDetection) {
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
+typedef std::tuple<SSLProtocolVariant,
+ uint16_t, // client version
+ uint16_t> // server version
+ TlsDowngradeProfile;
+
+class TlsDowngradeTest
+ : public TlsConnectTestBase,
+ public ::testing::WithParamInterface<TlsDowngradeProfile> {
+ public:
+ TlsDowngradeTest()
+ : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())),
+ c_ver(std::get<1>(GetParam())),
+ s_ver(std::get<2>(GetParam())) {}
+
+ protected:
+ const uint16_t c_ver;
+ const uint16_t s_ver;
+};
+
+TEST_P(TlsDowngradeTest, TlsDowngradeSentinelTest) {
+ static const uint8_t tls12_downgrade_random[] = {0x44, 0x4F, 0x57, 0x4E,
+ 0x47, 0x52, 0x44, 0x01};
+ static const uint8_t tls1_downgrade_random[] = {0x44, 0x4F, 0x57, 0x4E,
+ 0x47, 0x52, 0x44, 0x00};
+ static const size_t kRandomLen = 32;
+
+ if (c_ver > s_ver) {
+ return;
+ }
+
+ client_->SetVersionRange(c_ver, c_ver);
+ server_->SetVersionRange(c_ver, s_ver);
+
+ auto sh = MakeTlsFilter<TlsHandshakeRecorder>(server_, ssl_hs_server_hello);
+ Connect();
+ ASSERT_TRUE(sh->buffer().len() > (kRandomLen + 2));
+
+ const uint8_t* downgrade_sentinel =
+ sh->buffer().data() + 2 + kRandomLen - sizeof(tls1_downgrade_random);
+ if (c_ver < s_ver) {
+ if (c_ver == SSL_LIBRARY_VERSION_TLS_1_2) {
+ EXPECT_EQ(0, memcmp(downgrade_sentinel, tls12_downgrade_random,
+ sizeof(tls12_downgrade_random)));
+ } else {
+ EXPECT_EQ(0, memcmp(downgrade_sentinel, tls1_downgrade_random,
+ sizeof(tls1_downgrade_random)));
+ }
+ } else {
+ EXPECT_NE(0, memcmp(downgrade_sentinel, tls12_downgrade_random,
+ sizeof(tls12_downgrade_random)));
+ EXPECT_NE(0, memcmp(downgrade_sentinel, tls1_downgrade_random,
+ sizeof(tls1_downgrade_random)));
+ }
+}
+
// TLS 1.1 clients do not check the random values, so we should
// instead get a handshake failure alert from the server.
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
@@ -279,4 +335,82 @@ TEST_F(TlsConnectStreamTls13, Ssl30ClientHelloWithSupportedVersions) {
ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
}
+// 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));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TlsDowngradeSentinelTest, TlsDowngradeTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+ TlsConnectTestBase::kTlsVAll,
+ TlsConnectTestBase::kTlsV12Plus));
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
index b3acdf9c8..44e685414 100644
--- a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/test_io.cc b/security/nss/gtests/ssl_gtest/test_io.cc
index c6de3dfe8..4a7f91459 100644
--- a/security/nss/gtests/ssl_gtest/test_io.cc
+++ b/security/nss/gtests/ssl_gtest/test_io.cc
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/test_io.h b/security/nss/gtests/ssl_gtest/test_io.h
index 97093e7f0..e262fb123 100644
--- a/security/nss/gtests/ssl_gtest/test_io.h
+++ b/security/nss/gtests/ssl_gtest/test_io.h
@@ -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/. */
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.cc b/security/nss/gtests/ssl_gtest/tls_agent.cc
index 2ea70cae3..2eafc5bcb 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -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,8 @@ 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_psk_(ssl_psk_none),
can_falsestart_hook_called_(false),
sni_hook_called_(false),
auth_certificate_hook_called_(false),
@@ -299,7 +301,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 +309,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;
}
}
@@ -632,7 +634,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 +687,31 @@ void TlsAgent::EnableFalseStart() {
SetOption(SSL_ENABLE_FALSE_START, PR_TRUE);
}
-void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
+void TlsAgent::ExpectPsk() { expect_psk_ = ssl_psk_external; }
+
+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;
@@ -819,22 +841,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_);
}
}
@@ -870,7 +892,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 +930,8 @@ 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);
// Preliminary values are exposed through callbacks during the handshake.
// If either expected values were set or the callbacks were called, check
@@ -1063,21 +1086,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 +1154,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());
@@ -1201,16 +1231,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);
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.h b/security/nss/gtests/ssl_gtest/tls_agent.h
index 5385a6173..f9bb26aee 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -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,7 @@
#include "prio.h"
#include "ssl.h"
+#include "sslproto.h"
#include <functional>
#include <iostream>
@@ -75,8 +77,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();
@@ -155,6 +158,7 @@ class TlsAgent : public PollTarget {
void SetServerKeyBits(uint16_t bits);
void ExpectReadWriteError();
void EnableFalseStart();
+ void ExpectPsk();
void ExpectResumption();
void SkipVersionChecks();
void SetSignatureSchemes(const SSLSignatureScheme* schemes, size_t count);
@@ -174,8 +178,11 @@ 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);
@@ -246,6 +253,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";
@@ -416,8 +425,8 @@ class TlsAgent : public PollTarget {
bool falsestart_enabled_;
uint16_t expected_version_;
uint16_t expected_cipher_suite_;
- bool expect_resumption_;
bool expect_client_auth_;
+ SSLPskType expect_psk_;
bool can_falsestart_hook_called_;
bool sni_hook_called_;
bool auth_certificate_hook_called_;
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.cc b/security/nss/gtests/ssl_gtest/tls_connect.cc
index 8da5b57ac..9b7f9b6d8 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -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,
@@ -400,6 +401,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 +529,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 +773,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());
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.h b/security/nss/gtests/ssl_gtest/tls_connect.h
index 55ba571ef..3a43d6bca 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -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/. */
@@ -79,6 +80,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 +122,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(
diff --git a/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc b/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
index dfc4f4e7f..0a02d0683 100644
--- a/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
@@ -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/. */
@@ -313,12 +314,20 @@ TEST_P(TlsConnectTls13, ConnectEsniHrr) {
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})));
+ 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());
}
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.cc b/security/nss/gtests/ssl_gtest/tls_filter.cc
index 8be2a70b7..074a8bf29 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -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/. */
@@ -119,6 +120,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_) {
@@ -195,23 +200,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 +226,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 +238,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 +265,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 +342,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 +361,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 +382,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)) {
+
+ if (!parser->Read(&tmp, seq_no_bytes)) {
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)) {
- return false;
+ // 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;
+ }
}
- // 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);
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 +460,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 +481,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,8 +498,9 @@ 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) {
@@ -437,7 +516,7 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
uint16_t ep = 0;
if (agent()->variant() == ssl_variant_datagram) {
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 +524,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 +560,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 +574,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) {
@@ -1066,15 +1147,14 @@ 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;
}
-
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.h b/security/nss/gtests/ssl_gtest/tls_filter.h
index 93e5bad02..5300075ea 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -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/. */
@@ -11,6 +12,7 @@
#include <set>
#include <vector>
#include "sslt.h"
+#include "sslproto.h"
#include "test_io.h"
#include "tls_agent.h"
#include "tls_parser.h"
@@ -24,6 +26,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 +99,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 +159,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 +203,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
@@ -140,6 +235,7 @@ class TlsRecordFilter : public PacketFilter {
}
bool is_dtls13() const;
+ bool is_dtls13_ciphertext(uint8_t ct) const;
TlsCipherSpec& spec(uint16_t epoch);
private:
@@ -470,8 +566,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 +597,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;
}
diff --git a/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc b/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
index 03db44dfb..6f55c9265 100644
--- a/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
@@ -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,7 +169,7 @@ 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,
@@ -191,9 +180,9 @@ class TlsHkdfTest : public ::testing::Test,
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()));
@@ -206,7 +195,7 @@ class TlsHkdfTest : public ::testing::Test,
&secret);
EXPECT_EQ(SECSuccess, rv);
ASSERT_NE(nullptr, prk);
- VerifyKey(ScopedPK11SymKey(secret), GetHkdfMech(base_hash), expected);
+ VerifyKey(ScopedPK11SymKey(secret), CKM_HKDF_DERIVE, expected);
// Verify that a key can be created with a different key type and size.
rv = SSL_HkdfExpandLabelWithMech(
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.cc b/security/nss/gtests/ssl_gtest/tls_protect.cc
index 6c87d0a05..6187660a5 100644
--- a/security/nss/gtests/ssl_gtest/tls_protect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_protect.cc
@@ -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(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;
}
- aead_.reset(ctx);
+ 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);
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.h b/security/nss/gtests/ssl_gtest/tls_protect.h
index 08b3483aa..d7ea2aa12 100644
--- a/security/nss/gtests/ssl_gtest/tls_protect.h
+++ b/security/nss/gtests/ssl_gtest/tls_protect.h
@@ -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
diff --git a/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc b/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
new file mode 100644
index 000000000..c75297bc8
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/tls_psk_unittest.cc
@@ -0,0 +1,514 @@
+/* -*- 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_CASE_P(Tls13PskTest, Tls13PskTest,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ ::testing::ValuesIn(kDefaultSuite)));
+
+INSTANTIATE_TEST_CASE_P(
+ Tls13PskTestWithCiphers, Tls13PskTestWithCiphers,
+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+ ::testing::ValuesIn(k0RttCipherDefs)));
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
index f0c65b852..77bb41a0b 100644
--- a/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
@@ -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/. */
@@ -17,9 +18,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 +123,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,12 +158,19 @@ 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) {
+// 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.
+ 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_rsae_sha256, kDCValidFor, now());
+ TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
@@ -152,14 +178,15 @@ TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
- EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, client_->info().signatureScheme);
+ EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
-// Connected with RSA-PSS, using a RSAE Delegator SPKI.
-TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
- Reset(kRsaeDelegatorId);
+// Connected with RSA-PSS, using a PSS SPKI and PSS delegation cert.
+TEST_P(TlsConnectTls13, DCConnectRsaPssRsaPss) {
+ Reset(kPssDelegatorId);
- static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
+ // 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));
@@ -177,9 +204,9 @@ TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
-// Connected with RSA-PSS, using a PSS SPKI.
-TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
- Reset(kEcdsaDelegatorId);
+// 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,
@@ -188,16 +215,130 @@ TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
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);
+}
- EXPECT_TRUE(cfilter->captured());
- CheckPeerDelegCred(client_, true, 1024);
- EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
+// 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
@@ -243,8 +384,12 @@ static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
// 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));
ScopedSECKEYPrivateKey dc_priv;
ScopedSECKEYPublicKey dc_pub;
@@ -253,14 +398,14 @@ 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();
@@ -313,8 +458,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 +483,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,20 +684,19 @@ 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));
- // 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));
+ // 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_sha384, kDCValidFor, now, &dc));
dc.Reset();
+ EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
+ cert.get(), priv.get(), pub_rsa.get(),
+ ssl_sig_rsa_pss_pss_sha512, kDCValidFor, now, &dc));
+ dc.Reset();
ScopedSECKEYPublicKey pub_ecdsa;
ScopedSECKEYPrivateKey priv_ecdsa;