--- a/external_tests/ssl_gtest/libssl_internals.c
+++ b/external_tests/ssl_gtest/libssl_internals.c
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- 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/. */
/* This file contains functions for frobbing the internals of libssl */
#include "libssl_internals.h"
@@ -217,8 +217,55 @@ PRBool SSLInt_SendAlert(PRFileDesc *fd,
return PR_FALSE;
}
SECStatus rv = SSL3_SendAlert(ss, level, type);
if (rv != SECSuccess) return PR_FALSE;
return PR_TRUE;
}
+
+SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
+ PRUint64 epoch;
+ sslSocket *ss;
+ ssl3CipherSpec *spec;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ if (to >= (1ULL << 48)) {
+ return SECFailure;
+ }
+ ssl_GetSpecWriteLock(ss);
+ spec = ss->ssl3.crSpec;
+ epoch = spec->read_seq_num >> 48;
+ spec->read_seq_num = (epoch << 48) | to;
+
+ /* For DTLS, we need to fix the record sequence number. For this, we can just
+ * scrub the entire structure on the assumption that the new sequence number
+ * is far enough past the last received sequence number. */
+ if (to <= spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
+ return SECFailure;
+ }
+ dtls_RecordSetRecvd(&spec->recvdRecords, to);
+
+ ssl_ReleaseSpecWriteLock(ss);
+ return SECSuccess;
+}
+
+SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
+ PRUint64 epoch;
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ if (to >= (1ULL << 48)) {
+ return SECFailure;
+ }
+ ssl_GetSpecWriteLock(ss);
+ epoch = ss->ssl3.cwSpec->write_seq_num >> 48;
+ ss->ssl3.cwSpec->write_seq_num = (epoch << 48) | to;
+ ssl_ReleaseSpecWriteLock(ss);
+ return SECSuccess;
+}
--- a/external_tests/ssl_gtest/libssl_internals.h
+++ b/external_tests/ssl_gtest/libssl_internals.h
@@ -28,10 +28,12 @@ PRInt32 SSLInt_CountTls13CipherSpecs(PRF
void SSLInt_ForceTimerExpiry(PRFileDesc *fd);
SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu);
PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd);
PRBool SSLInt_DamageHsTrafficSecret(PRFileDesc *fd);
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_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to);
+SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
#endif // ndef libssl_internals_h_
--- a/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -6,40 +6,51 @@
#include "ssl.h"
#include <functional>
#include <memory>
#include "secerr.h"
#include "sslerr.h"
#include "sslproto.h"
+extern "C" {
+// This is not something that should make you happy.
+#include "libssl_internals.h"
+}
+
#include "gtest_utils.h"
#include "tls_connect.h"
+#include "tls_parser.h"
namespace nss_test {
// mode, version, cipher suite
typedef std::tuple<std::string, uint16_t, uint16_t> CipherSuiteProfile;
class TlsCipherSuiteTestBase : public TlsConnectTestBase {
public:
TlsCipherSuiteTestBase(std::string mode, uint16_t version,
uint16_t cipher_suite)
: TlsConnectTestBase(TlsConnectTestBase::ToMode(mode), version),
- cipher_suite_(cipher_suite) {}
+ cipher_suite_(cipher_suite),
+ csinfo_({0}) {
+ SECStatus rv =
+ SSL_GetCipherSuiteInfo(cipher_suite_, &csinfo_, sizeof(csinfo_));
+ EXPECT_EQ(SECSuccess, rv);
+ if (rv == SECSuccess) {
+ std::cerr << "Cipher suite: " << csinfo_.cipherSuiteName << std::endl;
+ }
+ }
protected:
uint16_t cipher_suite_;
+ SSLCipherSuiteInfo csinfo_;
void SetupCertificate() {
- SSLCipherSuiteInfo csinfo;
- EXPECT_EQ(SECSuccess,
- SSL_GetCipherSuiteInfo(cipher_suite_, &csinfo, sizeof(csinfo)));
- std::cerr << "Cipher suite: " << csinfo.cipherSuiteName << std::endl;
- switch (csinfo.authType) {
+ switch (csinfo_.authType) {
case ssl_auth_rsa_sign:
Reset(TlsAgent::kServerRsaSign);
break;
case ssl_auth_rsa_decrypt:
Reset(TlsAgent::kServerRsaDecrypt);
break;
case ssl_auth_ecdsa:
Reset(TlsAgent::kServerEcdsa256);
@@ -96,72 +107,62 @@ class TlsResumptionTest
: public TlsCipherSuiteTestBase,
public ::testing::WithParamInterface<CipherSuiteProfile> {
public:
TlsResumptionTest()
: TlsCipherSuiteTestBase(std::get<0>(GetParam()), std::get<1>(GetParam()),
std::get<2>(GetParam())) {}
bool SkipIfCipherSuiteIsDSA() {
- SSLCipherSuiteInfo csinfo;
- SECStatus rv =
- SSL_GetCipherSuiteInfo(cipher_suite_, &csinfo, sizeof(csinfo));
- if (rv != SECSuccess) {
- EXPECT_TRUE(false) << "Can't get cipher suite info";
- return false;
- }
- bool isDSA = csinfo.authType == ssl_auth_dsa;
+ bool isDSA = csinfo_.authType == ssl_auth_dsa;
if (isDSA) {
- std::cerr << "Skipping DSA suite: " << csinfo.cipherSuiteName
+ std::cerr << "Skipping DSA suite: " << csinfo_.cipherSuiteName
<< std::endl;
}
return isDSA;
}
void EnablePskCipherSuite() {
- SSLCipherSuiteInfo targetInfo;
- ASSERT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(cipher_suite_, &targetInfo,
- sizeof(targetInfo)));
SSLKEAType targetKea;
- switch (targetInfo.keaType) {
+ switch (csinfo_.keaType) {
case ssl_kea_ecdh:
targetKea = ssl_kea_ecdh_psk;
break;
case ssl_kea_dh:
targetKea = ssl_kea_dh_psk;
break;
default:
EXPECT_TRUE(false) << "Unsupported KEA type for "
- << targetInfo.cipherSuiteName;
+ << csinfo_.cipherSuiteName;
return;
}
size_t count = SSL_GetNumImplementedCiphers();
const uint16_t *ciphers = SSL_GetImplementedCiphers();
bool found = false;
for (size_t i = 0; i < count; ++i) {
SSLCipherSuiteInfo candidateInfo;
ASSERT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(ciphers[i], &candidateInfo,
sizeof(candidateInfo)));
if (candidateInfo.authType == ssl_auth_psk &&
candidateInfo.keaType == targetKea &&
- candidateInfo.symCipher == targetInfo.symCipher &&
- candidateInfo.macAlgorithm == targetInfo.macAlgorithm) {
+ candidateInfo.symCipher == csinfo_.symCipher &&
+ candidateInfo.macAlgorithm == csinfo_.macAlgorithm) {
// We aren't able to check that the PRF hash is the same. This is OK
// because there are (currently) no suites that have different PRF
// hashes but also use the same symmetric cipher.
EXPECT_EQ(SECSuccess,
SSL_CipherPrefSet(client_->ssl_fd(), ciphers[i], PR_TRUE));
EXPECT_EQ(SECSuccess,
SSL_CipherPrefSet(server_->ssl_fd(), ciphers[i], PR_TRUE));
found = true;
}
}
EXPECT_TRUE(found) << "Can't find matching PSK cipher for "
- << targetInfo.cipherSuiteName;
+ << csinfo_.cipherSuiteName;
}
};
TEST_P(TlsResumptionTest, ResumeCipherSuite) {
if (SkipIfCipherSuiteIsDSA()) {
return; // Tickets don't work with DSA (bug 1174677).
}
@@ -182,30 +183,131 @@ TEST_P(TlsResumptionTest, ResumeCipherSu
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
EnablePskCipherSuite();
}
ExpectResumption(RESUME_TICKET);
ConnectAndCheckCipherSuite();
}
+class TlsCipherLimitTest
+ : public TlsCipherSuiteTestBase,
+ public ::testing::WithParamInterface<CipherSuiteProfile> {
+ public:
+ TlsCipherLimitTest()
+ : TlsCipherSuiteTestBase(std::get<0>(GetParam()), std::get<1>(GetParam()),
+ std::get<2>(GetParam())) {}
+
+ protected:
+ // Get the expected limit on the number of records that can be sent for the
+ // cipher suite.
+ uint64_t record_limit() const {
+ switch (csinfo_.symCipher) {
+ case ssl_calg_rc4:
+ case ssl_calg_3des:
+ return 1ULL << 20;
+ case ssl_calg_aes:
+ case ssl_calg_aes_gcm:
+ return 0x5aULL << 28;
+ case ssl_calg_null:
+ case ssl_calg_chacha20:
+ return (1ULL << 48) - 1;
+ case ssl_calg_rc2:
+ case ssl_calg_des:
+ case ssl_calg_idea:
+ case ssl_calg_fortezza:
+ case ssl_calg_camellia:
+ case ssl_calg_seed:
+ break;
+ }
+ EXPECT_TRUE(false) << "No limit for " << csinfo_.cipherSuiteName;
+ return 1ULL < 48;
+ }
+
+ uint64_t last_safe_write() const {
+ uint64_t limit = record_limit() - 1;
+ if (version_ < SSL_LIBRARY_VERSION_TLS_1_1 &&
+ (csinfo_.symCipher == ssl_calg_3des ||
+ csinfo_.symCipher == ssl_calg_aes)) {
+ // 1/n-1 record splitting needs space for two records.
+ limit--;
+ }
+ return limit;
+ }
+};
+
+// This only works for stream ciphers because we modify the sequence number -
+// which is included explicitly in the DTLS record header - and that trips a
+// different error code. Note that the message that the client sends would not
+// decrypt (the nonce/IV wouldn't match), but the record limit is hit before
+// attempting to decrypt a record.
+TEST_P(TlsCipherLimitTest, ReadLimit) {
+ SetupCertificate();
+ EnableSingleCipher();
+ ConnectAndCheckCipherSuite();
+ EXPECT_EQ(SECSuccess,
+ SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), last_safe_write()));
+ EXPECT_EQ(SECSuccess,
+ SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), last_safe_write()));
+
+ client_->SendData(10, 10);
+ server_->ReadBytes(); // This should be OK.
+
+ // The payload needs to be big enough to pass for encrypted. In the extreme
+ // case (TLS 1.3), this means 1 for payload, 1 for content type and 16 for
+ // authentication tag.
+ static const uint8_t payload[18] = {6};
+ DataBuffer record;
+ uint64_t epoch = 0;
+ if (mode_ == DGRAM) {
+ epoch++;
+ if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
+ epoch++;
+ }
+ }
+ TlsAgentTestBase::MakeRecord(mode_, kTlsApplicationDataType, version_,
+ payload, sizeof(payload), &record,
+ (epoch << 48) | record_limit());
+ server_->adapter()->PacketReceived(record);
+ server_->ExpectReadWriteError();
+ server_->ReadBytes();
+ EXPECT_EQ(SSL_ERROR_TOO_MANY_RECORDS, server_->error_code());
+}
+
+TEST_P(TlsCipherLimitTest, WriteLimit) {
+ SetupCertificate();
+ EnableSingleCipher();
+ ConnectAndCheckCipherSuite();
+ EXPECT_EQ(SECSuccess,
+ SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), last_safe_write()));
+ client_->SendData(10, 10);
+ client_->ExpectReadWriteError();
+ client_->SendData(10, 10);
+ EXPECT_EQ(SSL_ERROR_TOO_MANY_RECORDS, client_->error_code());
+}
+
// This awful macro makes the test instantiations easier to read.
#define INSTANTIATE_CIPHER_TEST_P(name, modes, versions, ...) \
static const uint16_t k##name##CiphersArr[] = {__VA_ARGS__}; \
static const ::testing::internal::ParamGenerator<uint16_t> \
k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr); \
INSTANTIATE_TEST_CASE_P( \
CipherSuite##name, TlsCipherSuiteTest, \
::testing::Combine(TlsConnectTestBase::kTlsModes##modes, \
TlsConnectTestBase::kTls##versions, \
k##name##Ciphers)); \
INSTANTIATE_TEST_CASE_P( \
Resume##name, TlsResumptionTest, \
::testing::Combine(TlsConnectTestBase::kTlsModes##modes, \
TlsConnectTestBase::kTls##versions, \
+ k##name##Ciphers)); \
+ INSTANTIATE_TEST_CASE_P( \
+ Limit##name, TlsCipherLimitTest, \
+ ::testing::Combine(TlsConnectTestBase::kTlsModes##modes, \
+ TlsConnectTestBase::kTls##versions, \
k##name##Ciphers))
INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12, TLS_RSA_WITH_RC4_128_SHA,
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
TLS_ECDH_RSA_WITH_RC4_128_SHA,
TLS_ECDHE_RSA_WITH_RC4_128_SHA);
INSTANTIATE_CIPHER_TEST_P(AEAD12, All, V12, TLS_RSA_WITH_AES_128_GCM_SHA256,
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -90,22 +90,21 @@ TEST_P(TlsConnectGeneric, ConnectSendRec
// The next two tests takes advantage of the fact that we
// automatically read the first 1024 bytes, so if
// we provide 1200 bytes, they overrun the read buffer
// provided by the calling test.
// DTLS should return an error.
TEST_P(TlsConnectDatagram, ShortRead) {
Connect();
- client_->SetExpectedReadError(true);
+ client_->ExpectReadWriteError();
server_->SendData(1200, 1200);
client_->WaitForErrorCode(SSL_ERROR_RX_SHORT_DTLS_READ, 2000);
// Now send and receive another packet.
- client_->SetExpectedReadError(false);
server_->ResetSentBytes(); // Reset the counter.
SendReceive();
}
// TLS should get the write in two chunks.
TEST_P(TlsConnectStream, ShortRead) {
// This test behaves oddly with TLS 1.0 because of 1/n+1 splitting,
// so skip in that case.
@@ -178,25 +177,25 @@ TEST_P(TlsConnectStreamPre13, ServerFini
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
}
TEST_P(TlsConnectTls13, UnknownAlert) {
Connect();
SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
0xff); // Unknown value.
- client_->SetExpectedReadError(true);
+ client_->ExpectReadWriteError();
client_->WaitForErrorCode(SSL_ERROR_RX_UNKNOWN_ALERT, 2000);
}
TEST_P(TlsConnectTls13, AlertWrongLevel) {
Connect();
SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
kTlsAlertUnexpectedMessage);
- client_->SetExpectedReadError(true);
+ client_->ExpectReadWriteError();
client_->WaitForErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, 2000);
}
INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric,
::testing::Combine(TlsConnectTestBase::kTlsModesStream,
TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGeneric,
--- a/external_tests/ssl_gtest/tls_agent.cc
+++ b/external_tests/ssl_gtest/tls_agent.cc
@@ -58,17 +58,17 @@ TlsAgent::TlsAgent(const std::string& na
expect_client_auth_(false),
can_falsestart_hook_called_(false),
sni_hook_called_(false),
auth_certificate_hook_called_(false),
handshake_callback_called_(false),
error_code_(0),
send_ctr_(0),
recv_ctr_(0),
- expected_read_error_(false),
+ expect_readwrite_error_(false),
handshake_callback_(),
auth_certificate_callback_(),
sni_callback_() {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
SECStatus rv = SSL_VersionRangeGetDefault(
mode_ == STREAM ? ssl_variant_stream : ssl_variant_datagram, &vrange_);
EXPECT_EQ(SECSuccess, rv);
@@ -335,17 +335,17 @@ void TlsAgent::GetVersionRange(uint16_t*
}
void TlsAgent::SetExpectedVersion(uint16_t version) {
expected_version_ = version;
}
void TlsAgent::SetServerKeyBits(uint16_t bits) { server_key_bits_ = bits; }
-void TlsAgent::SetExpectedReadError(bool err) { expected_read_error_ = err; }
+void TlsAgent::ExpectReadWriteError() { expect_readwrite_error_ = true; }
void TlsAgent::SetSignatureAlgorithms(const SSLSignatureAndHashAlg* algorithms,
size_t count) {
EXPECT_TRUE(EnsureTlsSetup());
EXPECT_LE(count, SSL_SignatureMaxCount());
EXPECT_EQ(SECSuccess, SSL_SignaturePrefSet(ssl_fd_, algorithms,
static_cast<unsigned int>(count)));
EXPECT_EQ(SECFailure, SSL_SignaturePrefSet(ssl_fd_, algorithms, 0))
@@ -482,26 +482,26 @@ void TlsAgent::CheckSrtp() const {
uint16_t actual;
EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd_, &actual));
EXPECT_EQ(SRTP_AES128_CM_HMAC_SHA1_80, actual);
}
void TlsAgent::CheckErrorCode(int32_t expected) const {
EXPECT_EQ(STATE_ERROR, state_);
EXPECT_EQ(expected, error_code_)
- << "Got error code " << PORT_ErrorToString(error_code_) << " expecting "
- << PORT_ErrorToString(expected) << std::endl;
+ << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
+ << PORT_ErrorToName(expected) << std::endl;
}
void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
ASSERT_EQ(0, error_code_);
WAIT_(error_code_ != 0, delay);
- EXPECT_EQ(expected, error_code_) << "Got error code " << error_code_
- << " expecting "
- << PORT_ErrorToString(expected) << std::endl;
+ EXPECT_EQ(expected, error_code_)
+ << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
+ << PORT_ErrorToName(expected) << std::endl;
}
void TlsAgent::CheckPreliminaryInfo() {
SSLPreliminaryChannelInfo info;
EXPECT_EQ(SECSuccess,
SSL_GetPreliminaryChannelInfo(ssl_fd_, &info, sizeof(info)));
EXPECT_EQ(sizeof(info), info.length);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_version);
@@ -682,59 +682,68 @@ void TlsAgent::StartRenegotiate() {
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SendDirect(const DataBuffer& buf) {
LOG("Send Direct " << buf);
adapter_->peer()->PacketReceived(buf);
}
+static bool ErrorIsNonFatal(PRErrorCode code) {
+ return code == PR_WOULD_BLOCK_ERROR || code == SSL_ERROR_RX_SHORT_DTLS_READ;
+}
+
void TlsAgent::SendData(size_t bytes, size_t blocksize) {
uint8_t block[4096];
ASSERT_LT(blocksize, sizeof(block));
while (bytes) {
size_t tosend = std::min(blocksize, bytes);
for (size_t i = 0; i < tosend; ++i) {
block[i] = 0xff & send_ctr_;
++send_ctr_;
}
LOGV("Writing " << tosend << " bytes");
int32_t rv = PR_Write(ssl_fd_, block, tosend);
- ASSERT_EQ(tosend, static_cast<size_t>(rv));
+ if (expect_readwrite_error_) {
+ EXPECT_GT(0, rv);
+ EXPECT_NE(PR_WOULD_BLOCK_ERROR, error_code_);
+ error_code_ = PR_GetError();
+ expect_readwrite_error_ = false;
+ } else {
+ ASSERT_EQ(tosend, static_cast<size_t>(rv));
+ }
bytes -= tosend;
}
}
-static bool ErrorIsNonFatal(PRErrorCode code) {
- return code == PR_WOULD_BLOCK_ERROR || code == SSL_ERROR_RX_SHORT_DTLS_READ;
-}
-
void TlsAgent::ReadBytes() {
uint8_t block[1024];
int32_t rv = PR_Read(ssl_fd_, block, sizeof(block));
LOGV("ReadBytes " << rv);
int32_t err;
if (rv >= 0) {
size_t count = static_cast<size_t>(rv);
for (size_t i = 0; i < count; ++i) {
ASSERT_EQ(recv_ctr_ & 0xff, block[i]);
recv_ctr_++;
}
} else {
err = PR_GetError();
- LOG("Read error " << err << ": " << PORT_ErrorToString(err));
- if (err != PR_WOULD_BLOCK_ERROR && expected_read_error_) {
+ LOG("Read error " << PORT_ErrorToName(err) << ": "
+ << PORT_ErrorToString(err));
+ if (err != PR_WOULD_BLOCK_ERROR && expect_readwrite_error_) {
error_code_ = err;
+ expect_readwrite_error_ = false;
}
}
// If closed, then don't bother waiting around.
if (rv > 0 || (rv < 0 && ErrorIsNonFatal(err))) {
LOGV("Re-arming");
Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
&TlsAgent::ReadableCallback);
@@ -799,42 +808,46 @@ void TlsAgentTestBase::ProcessMessage(co
ASSERT_EQ(expected_state, agent_->state());
if (expected_state == TlsAgent::STATE_ERROR) {
ASSERT_EQ(error_code, agent_->error_code());
}
}
-void TlsAgentTestBase::MakeRecord(uint8_t type, uint16_t version,
+void TlsAgentTestBase::MakeRecord(Mode mode, uint8_t type, uint16_t version,
const uint8_t* buf, size_t len,
- DataBuffer* out, uint32_t seq_num) {
+ DataBuffer* out, uint64_t seq_num) {
size_t index = 0;
index = out->Write(index, type, 1);
- ; // Content Type
index = out->Write(
- index, mode_ == STREAM ? version : TlsVersionToDtlsVersion(version),
- 2); // Version
- if (mode_ == DGRAM) {
- index = out->Write(index, 0U, 4);
- index = out->Write(index, seq_num, 4);
+ index, mode == STREAM ? version : TlsVersionToDtlsVersion(version), 2);
+ if (mode == DGRAM) {
+ index = out->Write(index, seq_num >> 32, 4);
+ index = out->Write(index, seq_num & PR_UINT32_MAX, 4);
}
- index = out->Write(index, len, 2); // Length
+ index = out->Write(index, len, 2);
out->Write(index, buf, len);
}
+void TlsAgentTestBase::MakeRecord(uint8_t type, uint16_t version,
+ const uint8_t* buf, size_t len,
+ DataBuffer* out, uint64_t seq_num) {
+ MakeRecord(mode_, type, version, buf, len, out, seq_num);
+}
+
void TlsAgentTestBase::MakeHandshakeMessage(uint8_t hs_type,
const uint8_t* data, size_t hs_len,
- DataBuffer* out, uint32_t seq_num) {
+ DataBuffer* out, uint64_t seq_num) {
return MakeHandshakeMessageFragment(hs_type, data, hs_len, out, seq_num, 0,
0);
}
void TlsAgentTestBase::MakeHandshakeMessageFragment(
uint8_t hs_type, const uint8_t* data, size_t hs_len, DataBuffer* out,
- uint32_t seq_num, uint32_t fragment_offset, uint32_t fragment_length) {
+ uint64_t seq_num, uint32_t fragment_offset, uint32_t fragment_length) {
size_t index = 0;
if (!fragment_length) fragment_length = hs_len;
index = out->Write(index, hs_type, 1); // Handshake record type.
index = out->Write(index, hs_len, 3); // Handshake length
if (mode_ == DGRAM) {
index = out->Write(index, seq_num, 2);
index = out->Write(index, fragment_offset, 3);
index = out->Write(index, fragment_length, 3);
--- a/external_tests/ssl_gtest/tls_agent.h
+++ b/external_tests/ssl_gtest/tls_agent.h
@@ -111,17 +111,17 @@ class TlsAgent : public PollTarget {
void SetSessionCacheEnabled(bool en);
void Set0RttEnabled(bool en);
void SetVersionRange(uint16_t minver, uint16_t maxver);
void GetVersionRange(uint16_t* minver, uint16_t* maxver);
void CheckPreliminaryInfo();
void ResetPreliminaryInfo();
void SetExpectedVersion(uint16_t version);
void SetServerKeyBits(uint16_t bits);
- void SetExpectedReadError(bool err);
+ void ExpectReadWriteError();
void EnableFalseStart();
void ExpectResumption();
void SetSignatureAlgorithms(const SSLSignatureAndHashAlg* algorithms,
size_t count);
void EnableAlpn(const uint8_t* val, size_t len);
void CheckAlpn(SSLNextProtoState expected_state,
const std::string& expected = "") const;
void EnableSrtp();
@@ -186,17 +186,17 @@ class TlsAgent : public PollTarget {
}
std::vector<uint8_t> session_id() const {
return std::vector<uint8_t>(info_.sessionID,
info_.sessionID + info_.sessionIDLength);
}
size_t received_bytes() const { return recv_ctr_; }
- int32_t error_code() const { return error_code_; }
+ PRErrorCode error_code() const { return error_code_; }
bool can_falsestart_hook_called() const {
return can_falsestart_hook_called_;
}
void SetHandshakeCallback(HandshakeCallbackFunction handshake_callback) {
handshake_callback_ = handshake_callback;
}
@@ -326,20 +326,20 @@ class TlsAgent : public PollTarget {
bool expect_client_auth_;
bool can_falsestart_hook_called_;
bool sni_hook_called_;
bool auth_certificate_hook_called_;
bool handshake_callback_called_;
SSLChannelInfo info_;
SSLCipherSuiteInfo csinfo_;
SSLVersionRange vrange_;
- int32_t error_code_;
+ PRErrorCode error_code_;
size_t send_ctr_;
size_t recv_ctr_;
- bool expected_read_error_;
+ bool expect_readwrite_error_;
HandshakeCallbackFunction handshake_callback_;
AuthCertificateCallbackFunction auth_certificate_callback_;
SniCallbackFunction sni_callback_;
};
class TlsAgentTestBase : public ::testing::Test {
public:
static ::testing::internal::ParamGenerator<std::string> kTlsRolesAll;
@@ -351,25 +351,28 @@ class TlsAgentTestBase : public ::testin
PR_Close(fd_);
}
}
void SetUp();
void TearDown();
void MakeRecord(uint8_t type, uint16_t version, const uint8_t* buf,
- size_t len, DataBuffer* out, uint32_t seq_num = 0);
+ size_t len, DataBuffer* out, uint64_t seq_num = 0);
+ static void MakeRecord(Mode mode, uint8_t type, uint16_t version,
+ const uint8_t* buf, size_t len, DataBuffer* out,
+ uint64_t seq_num = 0);
void MakeHandshakeMessage(uint8_t hs_type, const uint8_t* data, size_t hs_len,
- DataBuffer* out, uint32_t seq_num = 0);
+ DataBuffer* out, uint64_t seq_num = 0);
void MakeHandshakeMessageFragment(uint8_t hs_type, const uint8_t* data,
size_t hs_len, DataBuffer* out,
- uint32_t seq_num, uint32_t fragment_offset,
+ uint64_t seq_num, uint32_t fragment_offset,
uint32_t fragment_length);
- void MakeTrivialHandshakeRecord(uint8_t hs_type, size_t hs_len,
- DataBuffer* out);
+ static void MakeTrivialHandshakeRecord(uint8_t hs_type, size_t hs_len,
+ DataBuffer* out);
static inline TlsAgent::Role ToRole(const std::string& str) {
return str == "CLIENT" ? TlsAgent::CLIENT : TlsAgent::SERVER;
}
static inline Mode ToMode(const std::string& str) {
return str == "TLS" ? STREAM : DGRAM;
}
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -479,8 +479,11 @@ ER3(SSL_ERROR_END_OF_EARLY_DATA_ALERT, (
ER3(SSL_ERROR_MISSING_ALPN_EXTENSION, (SSL_ERROR_BASE + 150),
"SSL didn't receive an expected ALPN extension.")
ER3(SSL_ERROR_RX_UNEXPECTED_EXTENSION, (SSL_ERROR_BASE + 151),
"SSL received an unexpected extension.")
ER3(SSL_ERROR_MISSING_SUPPORTED_GROUPS, (SSL_ERROR_BASE + 152),
"SSL expected a supported groups extension.")
+
+ER3(SSL_ERROR_TOO_MANY_RECORDS, (SSL_ERROR_BASE + 153),
+ "SSL sent or received too many records with the same symmetric key.")
--- a/lib/ssl/dtlscon.c
+++ b/lib/ssl/dtlscon.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
/*
* DTLS Protocol
*/
@@ -1071,17 +1072,17 @@ dtls_InitRecvdRecords(DTLSRecvdRecords *
* Has this DTLS record been received? Return values are:
* -1 -- out of range to the left
* 0 -- not received yet
* 1 -- replay
*
* Called from: ssl3_HandleRecord()
*/
int
-dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq)
+dtls_RecordGetRecvd(const DTLSRecvdRecords *records, sslSequenceNumber seq)
{
PRUint64 offset;
/* Out of range to the left */
if (seq < records->left) {
return -1;
}
@@ -1096,27 +1097,27 @@ dtls_RecordGetRecvd(const DTLSRecvdRecor
return !!(records->data[offset / 8] & (1 << (offset % 8)));
}
/* Update the DTLS anti-replay window
*
* Called from ssl3_HandleRecord()
*/
void
-dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
+dtls_RecordSetRecvd(DTLSRecvdRecords *records, sslSequenceNumber seq)
{
PRUint64 offset;
if (seq < records->left)
return;
if (seq > records->right) {
- PRUint64 new_left;
- PRUint64 new_right;
- PRUint64 right;
+ sslSequenceNumber new_left;
+ sslSequenceNumber new_right;
+ sslSequenceNumber right;
/* Slide to the right; this is the tricky part
*
* 1. new_top is set to have room for seq, on the
* next byte boundary by setting the right 8
* bits of seq
* 2. new_left is set to compensate.
* 3. Zero all bits between top and new_top. Since
@@ -1180,31 +1181,30 @@ DTLS_GetHandshakeTimeout(PRFileDesc *soc
* consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1.
*
* If the packet is not relevant, this function returns PR_FALSE.
* If the packet is relevant, this function returns PR_TRUE
* and sets |*seqNum| to the packet sequence number.
*/
PRBool
dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec,
- const SSL3Ciphertext *cText, PRUint64 *seqNum)
+ const SSL3Ciphertext *cText, sslSequenceNumber *seqNum)
{
- DTLSEpoch epoch = cText->seq_num.high >> 16;
- PRUint64 dtls_seq_num;
+ DTLSEpoch epoch;
+ sslSequenceNumber dtls_seq_num;
+ epoch = cText->seq_num >> 48;
if (crSpec->epoch != epoch) {
SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, received packet "
"from irrelevant epoch %d",
SSL_GETPID(), ss->fd, epoch));
return PR_FALSE;
}
- dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) |
- ((PRUint64)cText->seq_num.low);
-
+ dtls_seq_num = cText->seq_num & RECORD_SEQ_MAX;
if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) {
SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, rejecting "
"potentially replayed packet",
SSL_GETPID(), ss->fd));
return PR_FALSE;
}
*seqNum = dtls_seq_num;
@@ -1223,17 +1223,17 @@ dtls_IsRelevant(sslSocket *ss, const ssl
* Note: This isn't an issue in earlier versions because the second-to-last
* flight (sent by the server) includes the Finished message, which is not
* dropped because it has the same epoch that the client currently expects.
*/
SECStatus
dtls_MaybeRetransmitHandshake(sslSocket *ss, const SSL3Ciphertext *cText)
{
SECStatus rv = SECSuccess;
- DTLSEpoch messageEpoch = cText->seq_num.high >> 16;
+ DTLSEpoch messageEpoch = cText->seq_num >> 48;
if (!ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
messageEpoch == 0 && cText->type == content_handshake) {
ssl_GetSSL3HandshakeLock(ss);
if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb &&
ss->ssl3.hs.ws == idle_handshake) {
rv = dtls_RetransmitDetected(ss);
}
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -285,65 +285,73 @@ static const /*SSL3ClientCertificateType
#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
/* This global item is used only in servers. It is is initialized by
** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
*/
CERTDistNames *ssl3_server_ca_list = NULL;
static SSL3Statistics ssl3stats;
-/* indexed by SSL3BulkCipher */
+/* Record protection algorithms, indexed by SSL3BulkCipher.
+ *
+ * The |max_records| field (|mr| below) is set to a number that is higher than
+ * recommended in some literature (esp. TLS 1.3) because we currently abort the
+ * connection when this limit is reached and we want to ensure that we only
+ * rarely hit this limit. See bug 1268745 for details.
+ */
+#define MR_MAX RECORD_SEQ_MAX /* 2^48-1 */
+#define MR_128 (0x5aULL<<28) /* For AES and similar. */
+#define MR_LOW (1ULL<<20) /* For weak ciphers. */
/* clang-format off */
static const ssl3BulkCipherDef bulk_cipher_defs[] = {
/* |--------- Lengths ---------| */
- /* cipher calg k s type i b t n */
- /* e e v l a o */
- /* oid short_name y c | o g n */
- /* | r | c | c */
- /* | e | k | e */
- /* | t | | | | */
+ /* cipher calg : s : */
+ /* : e b n */
+ /* oid short_name mr : l o */
+ /* k r o t n */
+ /* e e i c a c */
+ /* y t type v k g e */
{cipher_null, calg_null, 0, 0, type_stream, 0, 0, 0, 0,
- SEC_OID_NULL_CIPHER, "NULL"},
+ SEC_OID_NULL_CIPHER, "NULL", MR_MAX},
{cipher_rc4, calg_rc4, 16,16, type_stream, 0, 0, 0, 0,
- SEC_OID_RC4, "RC4"},
+ SEC_OID_RC4, "RC4", MR_LOW},
{cipher_rc4_40, calg_rc4, 16, 5, type_stream, 0, 0, 0, 0,
- SEC_OID_RC4_40, "RC4-40"},
+ SEC_OID_RC4_40, "RC4-40", MR_LOW},
{cipher_rc4_56, calg_rc4, 16, 7, type_stream, 0, 0, 0, 0,
- SEC_OID_RC4_56, "RC4-56"},
+ SEC_OID_RC4_56, "RC4-56", MR_LOW},
{cipher_rc2, calg_rc2, 16,16, type_block, 8, 8, 0, 0,
- SEC_OID_RC2_CBC, "RC2-CBC"},
+ SEC_OID_RC2_CBC, "RC2-CBC", MR_LOW},
{cipher_rc2_40, calg_rc2, 16, 5, type_block, 8, 8, 0, 0,
- SEC_OID_RC2_40_CBC, "RC2-CBC-40"},
+ SEC_OID_RC2_40_CBC, "RC2-CBC-40", MR_LOW},
{cipher_des, calg_des, 8, 8, type_block, 8, 8, 0, 0,
- SEC_OID_DES_CBC, "DES-CBC"},
+ SEC_OID_DES_CBC, "DES-CBC", MR_LOW},
{cipher_3des, calg_3des, 24,24, type_block, 8, 8, 0, 0,
- SEC_OID_DES_EDE3_CBC, "3DES-EDE-CBC"},
- {cipher_des40, calg_des, 8, 5, type_block, 8, 8, 0, 0,
- SEC_OID_DES_40_CBC, "DES-CBC-40"},
- {cipher_idea, calg_idea, 16,16, type_block, 8, 8, 0, 0,
- SEC_OID_IDEA_CBC, "IDEA-CBC"},
+ SEC_OID_DES_EDE3_CBC, "3DES-EDE-CBC", MR_LOW},
{cipher_aes_128, calg_aes, 16,16, type_block, 16,16, 0, 0,
- SEC_OID_AES_128_CBC, "AES-128"},
+ SEC_OID_AES_128_CBC, "AES-128", MR_128},
{cipher_aes_256, calg_aes, 32,32, type_block, 16,16, 0, 0,
- SEC_OID_AES_256_CBC, "AES-256"},
+ SEC_OID_AES_256_CBC, "AES-256", MR_128},
{cipher_camellia_128, calg_camellia, 16,16, type_block, 16,16, 0, 0,
- SEC_OID_CAMELLIA_128_CBC, "Camellia-128"},
+ SEC_OID_CAMELLIA_128_CBC, "Camellia-128", MR_128},
{cipher_camellia_256, calg_camellia, 32,32, type_block, 16,16, 0, 0,
- SEC_OID_CAMELLIA_256_CBC, "Camellia-256"},
+ SEC_OID_CAMELLIA_256_CBC, "Camellia-256", MR_128},
{cipher_seed, calg_seed, 16,16, type_block, 16,16, 0, 0,
- SEC_OID_SEED_CBC, "SEED-CBC"},
+ SEC_OID_SEED_CBC, "SEED-CBC", MR_128},
{cipher_aes_128_gcm, calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8,
- SEC_OID_AES_128_GCM, "AES-128-GCM"},
+ SEC_OID_AES_128_GCM, "AES-128-GCM", MR_128},
{cipher_aes_256_gcm, calg_aes_gcm, 32,32, type_aead, 4, 0,16, 8,
- SEC_OID_AES_256_GCM, "AES-256-GCM"},
+ SEC_OID_AES_256_GCM, "AES-256-GCM", MR_128},
{cipher_chacha20, calg_chacha20, 32,32, type_aead, 12, 0,16, 0,
- SEC_OID_CHACHA20_POLY1305, "ChaCha20-Poly1305"},
+ SEC_OID_CHACHA20_POLY1305, "ChaCha20-Poly1305", MR_MAX},
{cipher_missing, calg_null, 0, 0, type_stream, 0, 0, 0, 0,
- SEC_OID_UNKNOWN, "missing"},
+ SEC_OID_UNKNOWN, "missing", 0U},
};
+#undef MR_MAX
+#undef MR_128
+#undef MR_LOW
static const ssl3KEADef kea_defs[] =
{ /* indexed by SSL3KeyExchangeAlgorithm */
/* kea exchKeyType signKeyType authKeyType, is_limited limit tls_keygen ephemeral oid */
{kea_null, ssl_kea_null, nullKey, ssl_auth_null, PR_FALSE, 0, PR_FALSE, PR_FALSE, 0},
{kea_rsa, ssl_kea_rsa, nullKey, ssl_auth_rsa_decrypt, PR_FALSE, 0, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA},
/* note: export suites abuse RSA, but these will be removed soon */
{kea_rsa_export, ssl_kea_rsa, rsaKey, ssl_auth_rsa_sign, PR_TRUE, 512, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT},
@@ -378,73 +386,39 @@ static const ssl3CipherSuiteDef cipher_s
{TLS_RSA_WITH_NULL_MD5, cipher_null, mac_md5, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_NULL_SHA256, cipher_null, hmac_sha256, kea_rsa, ssl_hash_sha256},
{TLS_RSA_EXPORT_WITH_RC4_40_MD5,cipher_rc4_40, mac_md5, kea_rsa_export, ssl_hash_none},
{TLS_RSA_WITH_RC4_128_MD5, cipher_rc4, mac_md5, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
cipher_rc2_40, mac_md5, kea_rsa_export, ssl_hash_none},
-#if 0 /* not implemented */
- {TLS_RSA_WITH_IDEA_CBC_SHA, cipher_idea, mac_sha, kea_rsa, ssl_hash_none},
- {TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_rsa_export, ssl_hash_none},
-#endif
{TLS_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa, ssl_hash_none},
{TLS_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_dss, ssl_hash_none},
{TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
cipher_3des, mac_sha, kea_dhe_dss, ssl_hash_none},
{TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_dhe_dss, ssl_hash_none},
-#if 0 /* not implemented */
- {TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_dh_dss_export, ssl_hash_none},
- {TLS_DH_DSS_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_dss, ssl_hash_none},
- {TLS_DH_DSS_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_dss, ssl_hash_none},
- {TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_dh_rsa_export, ssl_hash_none},
- {TLS_DH_RSA_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_rsa, ssl_hash_none},
- {TLS_DH_RSA_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_rsa, ssl_hash_none},
- {TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_dh_dss_export, ssl_hash_none},
- {TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_dh_rsa_export, ssl_hash_none},
-#endif
{TLS_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_rsa, ssl_hash_none},
{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_3des, mac_sha, kea_dhe_rsa, ssl_hash_none},
-#if 0
- {SSL_DH_ANON_EXPORT_RC4_40_MD5, cipher_rc4_40, mac_md5, kea_dh_anon_export, ssl_hash_none},
- {TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
- cipher_des40, mac_sha, kea_dh_anon_export, ssl_hash_none},
- {TLS_DH_anon_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_anon, ssl_hash_none},
- {TLS_DH_anon_WITH_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_anon, ssl_hash_none},
-#endif
/* New TLS cipher suites */
{TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_rsa, ssl_hash_sha256},
{TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_dss, ssl_hash_none},
{TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_rsa, ssl_hash_none},
{TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256},
{TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_rsa, ssl_hash_sha256},
{TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_dss, ssl_hash_none},
{TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_rsa, ssl_hash_none},
{TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256},
{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_rsa, ssl_hash_sha384},
-#if 0
- {TLS_DH_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_dss, ssl_hash_none},
- {TLS_DH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_rsa, ssl_hash_none},
- {TLS_DH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_anon, ssl_hash_none},
- {TLS_DH_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_dss, ssl_hash_none},
- {TLS_DH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_rsa, ssl_hash_none},
- {TLS_DH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_anon, ssl_hash_none},
-#endif
{TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, mac_sha, kea_rsa, ssl_hash_none},
{TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa, ssl_hash_none},
{TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
cipher_camellia_128, mac_sha, kea_dhe_dss, ssl_hash_none},
{TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
cipher_camellia_128, mac_sha, kea_dhe_rsa, ssl_hash_none},
@@ -1569,24 +1543,16 @@ ssl3_ComputeDHKeyHash(sslSocket *ss, SSL
}
}
if (hashBuf != buf && hashBuf != NULL)
PORT_Free(hashBuf);
return rv;
}
-void
-ssl3_BumpSequenceNumber(SSL3SequenceNumber *num)
-{
- num->low++;
- if (num->low == 0)
- num->high++;
-}
-
/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */
static void
ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
{
if (mat->write_key != NULL) {
PK11_FreeSymKey(mat->write_key);
mat->write_key = NULL;
}
@@ -2071,31 +2037,31 @@ ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype
* pseudo-header defintiion to use should be decided based on the version of
* the protocol that was negotiated when the cipher spec became current, NOT
* based on the version value in the record itself, and the decision is passed
* to this function as the |includesVersion| argument. But, the |version|
* argument should be the record's version value.
*/
static unsigned int
ssl3_BuildRecordPseudoHeader(unsigned char *out,
- SSL3SequenceNumber seq_num,
+ sslSequenceNumber seq_num,
SSL3ContentType type,
PRBool includesVersion,
SSL3ProtocolVersion version,
PRBool isDTLS,
int length)
{
- out[0] = (unsigned char)(seq_num.high >> 24);
- out[1] = (unsigned char)(seq_num.high >> 16);
- out[2] = (unsigned char)(seq_num.high >> 8);
- out[3] = (unsigned char)(seq_num.high >> 0);
- out[4] = (unsigned char)(seq_num.low >> 24);
- out[5] = (unsigned char)(seq_num.low >> 16);
- out[6] = (unsigned char)(seq_num.low >> 8);
- out[7] = (unsigned char)(seq_num.low >> 0);
+ out[0] = (unsigned char)(seq_num >> 56);
+ out[1] = (unsigned char)(seq_num >> 48);
+ out[2] = (unsigned char)(seq_num >> 40);
+ out[3] = (unsigned char)(seq_num >> 32);
+ out[4] = (unsigned char)(seq_num >> 24);
+ out[5] = (unsigned char)(seq_num >> 16);
+ out[6] = (unsigned char)(seq_num >> 8);
+ out[7] = (unsigned char)(seq_num >> 0);
out[8] = type;
/* SSL3 MAC doesn't include the record's version field. */
if (!includesVersion) {
out[9] = MSB(length);
out[10] = LSB(length);
return 11;
}
@@ -2594,35 +2560,34 @@ ssl3_InitPendingCipherSpec(sslSocket *ss
rv = SECFailure;
}
if (rv != SECSuccess) {
goto done;
}
/* Generic behaviors -- common to all crypto methods */
if (!IS_DTLS(ss)) {
- pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0;
+ pwSpec->read_seq_num = pwSpec->write_seq_num = 0;
} else {
if (cwSpec->epoch == PR_UINT16_MAX) {
/* The problem here is that we have rehandshaked too many
* times (you are not allowed to wrap the epoch). The
* spec says you should be discarding the connection
* and start over, so not much we can do here. */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
rv = SECFailure;
goto done;
}
/* The sequence number has the high 16 bits as the epoch. */
pwSpec->epoch = cwSpec->epoch + 1;
- pwSpec->read_seq_num.high = pwSpec->write_seq_num.high =
- pwSpec->epoch << 16;
+ pwSpec->read_seq_num = pwSpec->write_seq_num =
+ (sslSequenceNumber)pwSpec->epoch << 48;
dtls_InitRecvdRecords(&pwSpec->recvdRecords);
}
- pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0;
done:
ssl_ReleaseSpecWriteLock(ss); /******************************/
if (rv != SECSuccess)
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return rv;
}
@@ -2925,20 +2890,29 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
PRUint32 macLen = 0;
PRUint32 fragLen;
PRUint32 p1Len, p2Len, oddLen = 0;
PRUint16 headerLen;
unsigned int ivLen = 0;
int cipherBytes = 0;
unsigned char pseudoHeader[13];
unsigned int pseudoHeaderLen;
+ PRUint8 *b;
cipher_def = cwSpec->cipher_def;
headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
+ PORT_Assert(cipher_def->max_records <= RECORD_SEQ_MAX);
+ if ((cwSpec->write_seq_num & RECORD_SEQ_MAX) >= cipher_def->max_records) {
+ SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
+ SSL_GETPID(), cwSpec->write_seq_num));
+ PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
+ return SECFailure;
+ }
+
if (cipher_def->type == type_block &&
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
/* Prepend the per-record explicit IV using technique 2b from
* RFC 4346 section 6.2.3.2: The IV is a cryptographically
* strong random number XORed with the CBC residue from the previous
* record.
*/
ivLen = cipher_def->iv_size;
@@ -3085,47 +3059,36 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
}
cipherBytes += cipherBytesPart2;
}
}
PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
wrBuf->len = cipherBytes + headerLen;
- wrBuf->buf[0] = type;
+ b = &wrBuf->buf[0];
+ b = ssl_EncodeUintX(type, 1, b);
if (isDTLS) {
SSL3ProtocolVersion version;
version = dtls_TLSVersionToDTLSVersion(cwSpec->version);
- wrBuf->buf[1] = MSB(version);
- wrBuf->buf[2] = LSB(version);
- wrBuf->buf[3] = (unsigned char)(cwSpec->write_seq_num.high >> 24);
- wrBuf->buf[4] = (unsigned char)(cwSpec->write_seq_num.high >> 16);
- wrBuf->buf[5] = (unsigned char)(cwSpec->write_seq_num.high >> 8);
- wrBuf->buf[6] = (unsigned char)(cwSpec->write_seq_num.high >> 0);
- wrBuf->buf[7] = (unsigned char)(cwSpec->write_seq_num.low >> 24);
- wrBuf->buf[8] = (unsigned char)(cwSpec->write_seq_num.low >> 16);
- wrBuf->buf[9] = (unsigned char)(cwSpec->write_seq_num.low >> 8);
- wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0);
- wrBuf->buf[11] = MSB(cipherBytes);
- wrBuf->buf[12] = LSB(cipherBytes);
+ b = ssl_EncodeUintX(version, 2, b);
+ b = ssl_EncodeUintX(cwSpec->write_seq_num, 8, b);
} else {
SSL3ProtocolVersion version = cwSpec->version;
if (capRecordVersion || version >= SSL_LIBRARY_VERSION_TLS_1_3) {
version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
}
- wrBuf->buf[1] = MSB(version);
- wrBuf->buf[2] = LSB(version);
- wrBuf->buf[3] = MSB(cipherBytes);
- wrBuf->buf[4] = LSB(cipherBytes);
- }
-
- ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
+ b = ssl_EncodeUintX(version, 2, b);
+ }
+ b = ssl_EncodeUintX(cipherBytes, 2, b);
+
+ ++cwSpec->write_seq_num;
return SECSuccess;
}
/* Process the plain text before sending it.
* Returns the number of bytes of plaintext that were successfully sent
* plus the number of bytes of plaintext that were copied into the
* output (write) buffer.
@@ -4975,26 +4938,26 @@ ssl3_ConsumeHandshakeVariable(sslSocket
i->data = *b;
i->len = count;
*b += count;
*length -= count;
}
return SECSuccess;
}
-/* Helper function to encode a uint32 into a buffer */
+/* Helper function to encode an unsigned integer into a buffer. */
PRUint8 *
-ssl_EncodeUintX(PRUint32 value, unsigned int bytes, PRUint8 *to)
-{
- PRUint32 encoded;
-
- PORT_Assert(bytes > 0 && bytes <= 4);
-
- encoded = PR_htonl(value);
- memcpy(to, ((unsigned char *)(&encoded)) + (4 - bytes), bytes);
+ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to)
+{
+ PRUint64 encoded;
+
+ PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
+
+ encoded = PR_htonll(value);
+ memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes);
return to + bytes;
}
/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value.
* If the hash is not recognised, SEC_OID_UNKNOWN is returned.
*
* See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
SECOidTag
@@ -13517,17 +13480,17 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3
* lock around any calls to functions that handle records other than
* Application Data records.
*/
SECStatus
ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
{
SECStatus rv;
PRBool isTLS;
- PRUint64 dtls_seq_num = 0;
+ sslSequenceNumber seq_num = 0;
ssl3CipherSpec *crSpec;
SSL3ContentType rType;
sslBuffer *plaintext;
sslBuffer temp_buf;
SSL3AlertDescription alert;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
if (!ss->ssl3.initialized) {
@@ -13556,22 +13519,31 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
goto process_it;
}
ssl_GetSpecReadLock(ss); /******************************************/
crSpec = ss->ssl3.crSpec;
isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0);
if (IS_DTLS(ss)) {
- if (!dtls_IsRelevant(ss, crSpec, cText, &dtls_seq_num)) {
+ if (!dtls_IsRelevant(ss, crSpec, cText, &seq_num)) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
databuf->len = 0; /* Needed to ensure data not left around */
/* Drop the packet, but first see if retransmission is needed. */
return dtls_MaybeRetransmitHandshake(ss, cText);
}
+ } else {
+ seq_num = crSpec->read_seq_num + 1;
+ }
+ if (seq_num >= crSpec->cipher_def->max_records) {
+ ssl_ReleaseSpecReadLock(ss); /*****************************/
+ SSL_TRC(3, ("%d: SSL[%d]: read sequence number at limit 0x%0llx",
+ SSL_GETPID(), ss->fd, seq_num));
+ PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
+ return SECFailure;
}
/* If we will be decompressing the buffer we need to decrypt somewhere
* other than into databuf */
if (crSpec->decompressor) {
temp_buf.buf = NULL;
temp_buf.space = 0;
plaintext = &temp_buf;
@@ -13618,20 +13590,19 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
/* Reset the error code in case SSL3_SendAlert called
* PORT_SetError(). */
PORT_SetError(errCode);
return SECFailure;
}
}
/* SECSuccess */
- if (!IS_DTLS(ss)) {
- ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
- } else {
- dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num);
+ crSpec->read_seq_num = seq_num;
+ if (IS_DTLS(ss)) {
+ dtls_RecordSetRecvd(&crSpec->recvdRecords, seq_num);
}
ssl_ReleaseSpecReadLock(ss); /*****************************************/
/*
* The decrypted data is now in plaintext.
*/
rType = cText->type; /* This must go after decryption because TLS 1.3
@@ -13793,23 +13764,20 @@ ssl3_InitCipherSpec(ssl3CipherSpec *spec
spec->client.write_key = NULL;
spec->client.write_mac_key = NULL;
spec->client.write_mac_context = NULL;
spec->server.write_key = NULL;
spec->server.write_mac_key = NULL;
spec->server.write_mac_context = NULL;
- spec->write_seq_num.high = 0;
- spec->write_seq_num.low = 0;
-
- spec->read_seq_num.high = 0;
- spec->read_seq_num.low = 0;
-
+ spec->write_seq_num = 0;
+ spec->read_seq_num = 0;
spec->epoch = 0;
+
spec->refCt = 128; /* Arbitrarily high number to prevent
* non-TLS 1.3 cipherSpecs from being
* GCed. This will be overwritten with
* a valid refCt for TLS 1.3. */
dtls_InitRecvdRecords(&spec->recvdRecords);
}
/* Called from: ssl3_SendRecord
--- a/lib/ssl/ssl3gthr.c
+++ b/lib/ssl/ssl3gthr.c
@@ -457,28 +457,22 @@ ssl3_GatherCompleteHandshake(sslSocket *
* If it's application data, ss->gs.buf will not be empty upon return.
* If it's a change cipher spec, alert, or handshake message,
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
*/
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
if (IS_DTLS(ss)) {
- int i;
+ sslSequenceNumber seq_num;
cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
/* DTLS sequence number */
- cText.seq_num.high = 0;
- cText.seq_num.low = 0;
- for (i = 0; i < 4; i++) {
- cText.seq_num.high <<= 8;
- cText.seq_num.low <<= 8;
- cText.seq_num.high |= ss->gs.hdr[3 + i];
- cText.seq_num.low |= ss->gs.hdr[7 + i];
- }
+ PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
+ cText.seq_num = PR_ntohll(seq_num);
}
cText.buf = &ss->gs.inbuf;
rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
}
}
if (rv < 0) {
return ss->recvdCloseNotify ? 0 : rv;
--- a/lib/ssl/sslerr.h
+++ b/lib/ssl/sslerr.h
@@ -231,15 +231,16 @@ typedef enum {
SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 145),
SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 146),
SSL_ERROR_MALFORMED_PRE_SHARED_KEY = (SSL_ERROR_BASE + 147),
SSL_ERROR_MALFORMED_EARLY_DATA = (SSL_ERROR_BASE + 148),
SSL_ERROR_END_OF_EARLY_DATA_ALERT = (SSL_ERROR_BASE + 149),
SSL_ERROR_MISSING_ALPN_EXTENSION = (SSL_ERROR_BASE + 150),
SSL_ERROR_RX_UNEXPECTED_EXTENSION = (SSL_ERROR_BASE + 151),
SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION = (SSL_ERROR_BASE + 152),
+ SSL_ERROR_TOO_MANY_RECORDS = (SSL_ERROR_BASE + 153),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
/* clang-format on */
#endif /* __SSL_ERR_H_ */
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -432,18 +432,16 @@ typedef enum {
cipher_null,
cipher_rc4,
cipher_rc4_40,
cipher_rc4_56,
cipher_rc2,
cipher_rc2_40,
cipher_des,
cipher_3des,
- cipher_des40,
- cipher_idea,
cipher_aes_128,
cipher_aes_256,
cipher_camellia_128,
cipher_camellia_256,
cipher_seed,
cipher_aes_128_gcm,
cipher_aes_256_gcm,
cipher_chacha20,
@@ -452,24 +450,17 @@ typedef enum {
} SSL3BulkCipher;
typedef enum { type_stream,
type_block,
type_aead } CipherType;
#define MAX_IV_LENGTH 24
-/*
- * Do not depend upon 64 bit arithmetic in the underlying machine.
- */
-typedef struct {
- PRUint32 high;
- PRUint32 low;
-} SSL3SequenceNumber;
-
+typedef PRUint64 sslSequenceNumber;
typedef PRUint16 DTLSEpoch;
typedef void (*DTLSTimerCb)(sslSocket *);
/* 400 is large enough for MD5, SHA-1, and SHA-256.
* For SHA-384 support, increase it to 712. */
#define MAX_MAC_CONTEXT_BYTES 712
#define MAX_MAC_CONTEXT_LLONGS (MAX_MAC_CONTEXT_BYTES / 8)
@@ -523,20 +514,21 @@ typedef SECStatus (*SSLDestroy)(void *co
/* The DTLS anti-replay window. Defined here because we need it in
* the cipher spec. Note that this is a ring buffer but left and
* right represent the true window, with modular arithmetic used to
* map them onto the buffer.
*/
#define DTLS_RECVD_RECORDS_WINDOW 1024 /* Packets; approximate \
* Must be divisible by 8 \
*/
+#define RECORD_SEQ_MAX ((1ULL<<48)-1)
typedef struct DTLSRecvdRecordsStr {
unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8];
- PRUint64 left;
- PRUint64 right;
+ sslSequenceNumber left;
+ sslSequenceNumber right;
} DTLSRecvdRecords;
/*
** These are the "specs" in the "ssl3" struct.
** Access to the pointers to these specs, and all the specs' contents
** (direct and indirect) is protected by the reader/writer lock ss->specLock.
*/
typedef struct {
@@ -555,18 +547,18 @@ typedef struct {
SSLCompressor decompressor; /* and uncompress because zconf.h */
/* may define them as macros. */
SSLDestroy destroyCompressContext;
void *compressContext;
SSLDestroy destroyDecompressContext;
void *decompressContext;
PRBool bypassCiphers; /* did double bypass (at least) */
PK11SymKey *master_secret;
- SSL3SequenceNumber write_seq_num;
- SSL3SequenceNumber read_seq_num;
+ sslSequenceNumber write_seq_num;
+ sslSequenceNumber read_seq_num;
SSL3ProtocolVersion version;
ssl3KeyMaterial client;
ssl3KeyMaterial server;
SECItem msItem;
unsigned char key_block[NUM_MIXERS * HASH_LENGTH_MAX];
unsigned char raw_master_secret[56];
DTLSEpoch epoch;
DTLSRecvdRecords recvdRecords;
@@ -736,16 +728,19 @@ struct ssl3BulkCipherDefStr {
unsigned int secret_key_size;
CipherType type;
unsigned int iv_size;
unsigned int block_size;
unsigned int tag_size; /* for AEAD ciphers. */
unsigned int explicit_nonce_size; /* for AEAD ciphers. */
SECOidTag oid;
const char *short_name;
+ /* The maximum number of records that can be sent/received with the same
+ * symmetric key before the connection will be terminated. */
+ PRUint64 max_records;
};
/*
** There are tables of these, all const.
*/
struct ssl3MACDefStr {
SSL3MACAlgorithm mac;
CK_MECHANISM_TYPE mmech;
@@ -1068,17 +1063,17 @@ struct ssl3StateStr {
/* Ethernet MTU but without subtracting the headers,
* so slightly larger than expected */
#define DTLS_MAX_MTU 1500U
#define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram)
typedef struct {
SSL3ContentType type;
SSL3ProtocolVersion version;
- SSL3SequenceNumber seq_num; /* DTLS only */
+ sslSequenceNumber seq_num; /* DTLS only */
sslBuffer *buf;
} SSL3Ciphertext;
struct sslKeyPairStr {
SECKEYPrivateKey *privKey;
SECKEYPublicKey *pubKey;
PRInt32 refCount; /* use PR_Atomic calls for this. */
};
@@ -1793,17 +1788,17 @@ extern SECStatus ssl3_AppendSignatureAnd
sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash);
extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes,
SSL3Opaque **b, PRUint32 *length);
extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes,
SSL3Opaque **b, PRUint32 *length);
extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
PRInt32 bytes, SSL3Opaque **b,
PRUint32 *length);
-extern PRUint8 *ssl_EncodeUintX(PRUint32 value, unsigned int bytes,
+extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes,
PRUint8 *to);
extern PRBool ssl_IsSupportedSignatureScheme(SignatureScheme scheme);
extern SECStatus ssl_CheckSignatureSchemeConsistency(
sslSocket *ss, SignatureScheme scheme, CERTCertificate *cert);
extern SECStatus ssl_ParseSignatureSchemes(sslSocket *ss, PLArenaPool *arena,
SignatureScheme **schemesOut,
unsigned int *numSchemesOut,
unsigned char **b,
@@ -1931,25 +1926,28 @@ extern SECStatus dtls_CompressMACEncrypt
PRUint32 contentLen,
sslBuffer *wrBuf);
SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss);
extern SECStatus dtls_StartHolddownTimer(sslSocket *ss);
extern void dtls_CheckTimer(sslSocket *ss);
extern void dtls_CancelTimer(sslSocket *ss);
extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
-extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq);
-extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
+extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records,
+ sslSequenceNumber seq);
+extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records,
+ sslSequenceNumber seq);
extern void dtls_RehandshakeCleanup(sslSocket *ss);
extern SSL3ProtocolVersion
dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
extern SSL3ProtocolVersion
dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec,
- const SSL3Ciphertext *cText, PRUint64 *seqNum);
+ const SSL3Ciphertext *cText,
+ sslSequenceNumber *seqNum);
extern SECStatus dtls_MaybeRetransmitHandshake(sslSocket *ss,
const SSL3Ciphertext *cText);
CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg);
SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites);
SECStatus ssl3_ServerCallSNICallback(sslSocket *ss);
SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss);
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
@@ -1970,17 +1968,16 @@ SECStatus ssl3_ParseCertificateRequestCA
SECStatus ssl3_CompleteHandleCertificateRequest(
sslSocket *ss, const SignatureScheme *signatureSchemes,
unsigned int signatureSchemeCount, CERTDistNames *ca_list);
SECStatus ssl3_SendServerHello(sslSocket *ss);
SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
ssl3CipherSpec *spec,
SSL3Hashes *hashes,
PRUint32 sender);
-void ssl3_BumpSequenceNumber(SSL3SequenceNumber *num);
PRInt32 tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
SECStatus ssl_CreateECDHEphemeralKeyPair(const namedGroupDef *ecGroup,
sslEphemeralKeyPair **keyPair);
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
const sslServerCert *serverCert,
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -2036,25 +2036,24 @@ tls13_SetCipherSpec(sslSocket *ss, Traff
* it in both TLS and DTLS. */
if ((*specp)->epoch == PR_UINT16_MAX) {
ssl_ReleaseSpecWriteLock(ss);
return SECFailure;
}
spec->epoch = (*specp)->epoch + 1;
if (!IS_DTLS(ss)) {
- spec->read_seq_num.high = spec->write_seq_num.high = 0;
+ spec->read_seq_num = spec->write_seq_num = 0;
} else {
/* The sequence number has the high 16 bits as the epoch. */
- spec->read_seq_num.high = spec->write_seq_num.high =
- spec->epoch << 16;
+ spec->read_seq_num = spec->write_seq_num =
+ (sslSequenceNumber)spec->epoch << 48;
dtls_InitRecvdRecords(&spec->recvdRecords);
}
- spec->read_seq_num.low = spec->write_seq_num.low = 0;
/* Now that we've set almost everything up, finally cut over. */
ssl_GetSpecWriteLock(ss);
tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
*specp = spec; /* Overwrite. */
ssl_ReleaseSpecWriteLock(ss);
SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for phase='%s' dir=%s",
@@ -3224,23 +3223,22 @@ tls13_ExtensionAllowed(PRUint16 extensio
/* TLS 1.3 doesn't actually have additional data but the aead function
* signature overloads additional data to carry the record sequence
* number and that's what we put here. The TLS 1.3 AEAD functions
* just use this input as the sequence number and not as additional
* data. */
static void
tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length,
- SSL3SequenceNumber seqNum)
+ sslSequenceNumber seqNum)
{
PRUint8 *ptr = aad;
PORT_Assert(length == 8);
- ptr = ssl_EncodeUintX(seqNum.high, 4, ptr);
- ptr = ssl_EncodeUintX(seqNum.low, 4, ptr);
+ ptr = ssl_EncodeUintX(seqNum, 8, ptr);
PORT_Assert((ptr - aad) == length);
}
SECStatus
tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
SSL3ContentType type,
const SSL3Opaque *pIn,
@@ -3248,20 +3246,27 @@ tls13_ProtectRecord(sslSocket *ss,
sslBuffer *wrBuf)
{
const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
SECStatus rv;
PRUint16 headerLen;
int cipherBytes = 0;
const int tagLen = cipher_def->tag_size;
- SSL_TRC(3, ("%d: TLS13[%d]: spec=%d phase=%s protect record of length %u, seq=0x%0x%0x",
- SSL_GETPID(), ss->fd, cwSpec, cwSpec->phase, contentLen,
- cwSpec->write_seq_num.high,
- cwSpec->write_seq_num.low));
+ SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) protect record 0x%0llx len=%u",
+ SSL_GETPID(), ss->fd, cwSpec, cwSpec->phase,
+ cwSpec->write_seq_num, contentLen));
+
+ PORT_Assert(cipher_def->max_records <= RECORD_SEQ_MAX);
+ if ((cwSpec->write_seq_num & RECORD_SEQ_MAX) >= cipher_def->max_records) {
+ SSL_TRC(3, ("%d: TLS13[%d]: write sequence number at limit 0x%0llx",
+ SSL_GETPID(), ss->fd, cwSpec->write_seq_num));
+ PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
+ return SECFailure;
+ }
headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
if (headerLen + contentLen + 1 + tagLen > wrBuf->space) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
@@ -3277,18 +3282,17 @@ tls13_ProtectRecord(sslSocket *ss,
PORT_Assert(cipher_def->type == type_aead);
/* Add the content type at the end. */
wrBuf->buf[headerLen + contentLen] = type;
/* Stomp the content type to be application_data */
type = content_application_data;
- tls13_FormatAdditionalData(aad, sizeof(aad),
- cwSpec->write_seq_num);
+ tls13_FormatAdditionalData(aad, sizeof(aad), cwSpec->write_seq_num);
cipherBytes = contentLen + 1; /* Room for the content type on the end. */
rv = cwSpec->aead(
ss->sec.isServer ? &cwSpec->server : &cwSpec->client,
PR_FALSE, /* do encrypt */
wrBuf->buf + headerLen, /* output */
&cipherBytes, /* out len */
wrBuf->space - headerLen, /* max out */
wrBuf->buf + headerLen, contentLen + 1, /* input */
@@ -3303,24 +3307,23 @@ tls13_ProtectRecord(sslSocket *ss,
wrBuf->len = cipherBytes + headerLen;
wrBuf->buf[0] = type;
if (IS_DTLS(ss)) {
(void)ssl_EncodeUintX(
dtls_TLSVersionToDTLSVersion(kDtlsRecordVersion), 2,
&wrBuf->buf[1]);
- (void)ssl_EncodeUintX(cwSpec->write_seq_num.high, 4, &wrBuf->buf[3]);
- (void)ssl_EncodeUintX(cwSpec->write_seq_num.low, 4, &wrBuf->buf[7]);
+ (void)ssl_EncodeUintX(cwSpec->write_seq_num, 8, &wrBuf->buf[3]);
(void)ssl_EncodeUintX(cipherBytes, 2, &wrBuf->buf[11]);
} else {
(void)ssl_EncodeUintX(kTlsRecordVersion, 2, &wrBuf->buf[1]);
(void)ssl_EncodeUintX(cipherBytes, 2, &wrBuf->buf[3]);
}
- ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
+ ++cwSpec->write_seq_num;
return SECSuccess;
}
/* Unprotect a TLS 1.3 record and leave the result in plaintext.
*
* Called by ssl3_HandleRecord. Caller must hold the spec read lock.
* Therefore, we MUST not call SSL3_SendAlert().
@@ -3335,20 +3338,19 @@ tls13_UnprotectRecord(sslSocket *ss, SSL
{
ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def;
PRUint8 aad[8];
SECStatus rv;
*alert = bad_record_mac; /* Default alert for most issues. */
- SSL_TRC(3, ("%d: TLS13[%d]: spec=%d phase=%s unprotect record of length %u seq=0x%0x%0x",
- SSL_GETPID(), ss->fd, crSpec, crSpec->phase, cText->buf->len,
- crSpec->read_seq_num.high,
- crSpec->read_seq_num.low));
+ SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) unprotect record 0x%0llx len=%u",
+ SSL_GETPID(), ss->fd, crSpec, crSpec->phase,
+ crSpec->read_seq_num, cText->buf->len));
/* We can perform this test in variable time because the record's total
* length and the ciphersuite are both public knowledge. */
if (cText->buf->len < cipher_def->tag_size) {
SSL_TRC(3,
("%d: TLS13[%d]: record too short to contain valid AEAD data",
SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_BAD_MAC_READ);