summaryrefslogtreecommitdiff
path: root/security/nss/gtests
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests')
-rw-r--r--security/nss/gtests/freebl_gtest/blake2b_unittest.cc4
-rw-r--r--security/nss/gtests/freebl_gtest/kat/blake2b_kat.h2
-rw-r--r--security/nss/gtests/nss_bogo_shim/config.cc35
-rw-r--r--security/nss/gtests/nss_bogo_shim/config.h17
-rw-r--r--security/nss/gtests/nss_bogo_shim/config.json74
-rw-r--r--security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc59
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_signature_test.h4
-rw-r--r--security/nss/gtests/ssl_gtest/libssl_internals.c13
-rw-r--r--security/nss/gtests/ssl_gtest/manifest.mn1
-rw-r--r--security/nss/gtests/ssl_gtest/rsa8193.h209
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc4
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc78
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc48
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc11
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc73
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc126
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc111
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc35
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc28
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc4
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_gtest.gyp1
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc136
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc71
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_record_unittest.cc57
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc431
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc6
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc6
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc36
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc92
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc12
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.cc8
-rw-r--r--security/nss/gtests/ssl_gtest/test_io.h6
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.cc131
-rw-r--r--security/nss/gtests/ssl_gtest/tls_agent.h24
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.cc49
-rw-r--r--security/nss/gtests/ssl_gtest/tls_connect.h4
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.cc234
-rw-r--r--security/nss/gtests/ssl_gtest/tls_filter.h149
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.cc35
-rw-r--r--security/nss/gtests/ssl_gtest/tls_protect.h15
41 files changed, 1995 insertions, 445 deletions
diff --git a/security/nss/gtests/freebl_gtest/blake2b_unittest.cc b/security/nss/gtests/freebl_gtest/blake2b_unittest.cc
index e6b0c11576..ac9cca83fd 100644
--- a/security/nss/gtests/freebl_gtest/blake2b_unittest.cc
+++ b/security/nss/gtests/freebl_gtest/blake2b_unittest.cc
@@ -50,7 +50,7 @@ TEST_P(Blake2BKATUnkeyed, Unkeyed) {
TEST_P(Blake2BKATKeyed, Keyed) {
std::vector<uint8_t> values(BLAKE2B512_LENGTH);
SECStatus rv = BLAKE2B_MAC_HashBuf(values.data(), kat_data.data(),
- std::get<0>(GetParam()), key.data(),
+ std::get<0>(GetParam()), kat_key.data(),
BLAKE2B_KEY_SIZE);
ASSERT_EQ(SECSuccess, rv);
EXPECT_EQ(values, std::get<1>(GetParam()));
@@ -139,7 +139,7 @@ TEST_F(Blake2BTests, NullTest) {
EXPECT_EQ(std::get<1>(TestcasesUnkeyed[0]), digest);
digest = std::vector<uint8_t>(BLAKE2B512_LENGTH);
- rv = BLAKE2B_MAC_HashBuf(digest.data(), nullptr, 0, key.data(),
+ rv = BLAKE2B_MAC_HashBuf(digest.data(), nullptr, 0, kat_key.data(),
BLAKE2B_KEY_SIZE);
ASSERT_EQ(SECSuccess, rv);
EXPECT_EQ(std::get<1>(TestcasesKeyed[0]), digest);
diff --git a/security/nss/gtests/freebl_gtest/kat/blake2b_kat.h b/security/nss/gtests/freebl_gtest/kat/blake2b_kat.h
index 28921cc945..2d73a4ab55 100644
--- a/security/nss/gtests/freebl_gtest/kat/blake2b_kat.h
+++ b/security/nss/gtests/freebl_gtest/kat/blake2b_kat.h
@@ -7,7 +7,7 @@
#include <vector>
#include <stdint.h>
-const std::vector<uint8_t> key = {
+const std::vector<uint8_t> kat_key = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
diff --git a/security/nss/gtests/nss_bogo_shim/config.cc b/security/nss/gtests/nss_bogo_shim/config.cc
index 2e6f7f7752..603bb60296 100644
--- a/security/nss/gtests/nss_bogo_shim/config.cc
+++ b/security/nss/gtests/nss_bogo_shim/config.cc
@@ -9,26 +9,37 @@
#include <queue>
#include <string>
-bool ConfigEntryBase::ParseInternal(std::queue<const char *> *args,
- std::string *out) {
- if (args->empty()) return false;
- *out = args->front();
- args->pop();
+bool ConfigEntryBase::ParseInternal(std::queue<const char *> &args,
+ std::vector<int> &out) {
+ if (args.empty()) return false;
+
+ char *endptr;
+ out.push_back(strtol(args.front(), &endptr, 10));
+ args.pop();
+
+ return !*endptr;
+}
+
+bool ConfigEntryBase::ParseInternal(std::queue<const char *> &args,
+ std::string &out) {
+ if (args.empty()) return false;
+ out = args.front();
+ args.pop();
return true;
}
-bool ConfigEntryBase::ParseInternal(std::queue<const char *> *args, int *out) {
- if (args->empty()) return false;
+bool ConfigEntryBase::ParseInternal(std::queue<const char *> &args, int &out) {
+ if (args.empty()) return false;
char *endptr;
- *out = strtol(args->front(), &endptr, 10);
- args->pop();
+ out = strtol(args.front(), &endptr, 10);
+ args.pop();
return !*endptr;
}
-bool ConfigEntryBase::ParseInternal(std::queue<const char *> *args, bool *out) {
- *out = true;
+bool ConfigEntryBase::ParseInternal(std::queue<const char *> &args, bool &out) {
+ out = true;
return true;
}
@@ -51,7 +62,7 @@ Config::Status Config::ParseArgs(int argc, char **argv) {
if (e == entries_.end()) {
return kUnknownFlag;
}
- if (!e->second->Parse(&args)) return kMalformedArgument;
+ if (!e->second->Parse(args)) return kMalformedArgument;
}
return kOK;
diff --git a/security/nss/gtests/nss_bogo_shim/config.h b/security/nss/gtests/nss_bogo_shim/config.h
index 822df65b3a..0e7fb5ed58 100644
--- a/security/nss/gtests/nss_bogo_shim/config.h
+++ b/security/nss/gtests/nss_bogo_shim/config.h
@@ -23,18 +23,19 @@
// Abstract base class for a given config flag.
class ConfigEntryBase {
public:
- ConfigEntryBase(const std::string& name, const std::string& type)
- : name_(name), type_(type) {}
+ ConfigEntryBase(const std::string& nm, const std::string& typ)
+ : name_(nm), type_(typ) {}
virtual ~ConfigEntryBase() {}
const std::string& type() const { return type_; }
- virtual bool Parse(std::queue<const char*>* args) = 0;
+ virtual bool Parse(std::queue<const char*>& args) = 0;
protected:
- bool ParseInternal(std::queue<const char*>* args, std::string* out);
- bool ParseInternal(std::queue<const char*>* args, int* out);
- bool ParseInternal(std::queue<const char*>* args, bool* out);
+ bool ParseInternal(std::queue<const char*>& args, std::vector<int>& out);
+ bool ParseInternal(std::queue<const char*>& args, std::string& out);
+ bool ParseInternal(std::queue<const char*>& args, int& out);
+ bool ParseInternal(std::queue<const char*>& args, bool& out);
const std::string name_;
const std::string type_;
@@ -48,8 +49,8 @@ class ConfigEntry : public ConfigEntryBase {
: ConfigEntryBase(name, typeid(T).name()), value_(init) {}
T get() const { return value_; }
- bool Parse(std::queue<const char*>* args) {
- return ParseInternal(args, &value_);
+ bool Parse(std::queue<const char*>& args) {
+ return ParseInternal(args, value_);
}
private:
diff --git a/security/nss/gtests/nss_bogo_shim/config.json b/security/nss/gtests/nss_bogo_shim/config.json
index 03f8754662..6dc155befa 100644
--- a/security/nss/gtests/nss_bogo_shim/config.json
+++ b/security/nss/gtests/nss_bogo_shim/config.json
@@ -1,69 +1,16 @@
{
"DisabledTests": {
"### These tests break whenever we rev versions, so just leave them here for easy uncommenting":"",
- "SendWarningAlerts-Pass":"BoringSSL updated",
- "SendBogusAlertType":"BoringSSL updated",
- "SendEmptyRecords-Pass":"BoringSSL updated",
- "ExtraCompressionMethods-TLS12":"BoringSSL updated",
- "SendSNIWarningAlert":"BoringSSL updated",
- "NoNullCompression-TLS12":"BoringSSL updated",
- "InvalidCompressionMethod":"BoringSSL updated",
- "SupportTicketsWithSessionID":"BoringSSL updated",
- "NoSharedCipher":"BoringSSL updated",
- "ServerHelloBogusCipher":"BoringSSL updated",
- "ClientHelloVersionTooHigh":"BoringSSL updated",
- "ServerAuth-SignatureType":"BoringSSL updated",
- "ECDSACurveMismatch-Verify-TLS12":"BoringSSL updated",
- "UnknownExtension-Client":"BoringSSL updated",
- "UnofferedExtension-Client":"BoringSSL updated",
- "SendClientVersion-RSA":"BoringSSL updated",
- "SupportedCurves-ServerHello-TLS12":"BoringSSL updated",
- "Basic-Client*Sync":"BoringSSL updated",
- "Resume-Client-CipherMismatch":"BoringSSL updated",
- "ClientAuth-SignatureType":"BoringSSL updated",
- "Agree-Digest-Default":"BoringSSL updated",
- "Basic-Server*Sync":"BoringSSL updated",
- "ClientAuth-*-Sync":"BoringSSL updated",
- "RSA-PSS-Default*":"BoringSSL updated",
- "Renegotiate-Server-NoExt*":"BoringSSL updated",
- "Downgrade-TLS12*":"BoringSSL updated",
- "MaxCBCPadding":"BoringSSL updated",
- "UnknownCipher":"BoringSSL updated",
- "LargeMessage":"BoringSSL updated",
- "NoCommonCurves":"BoringSSL updated",
- "UnknownCurve":"BoringSSL updated",
- "SessionTicketsDisabled*":"BoringSSL updated",
- "BadFinished-*":"BoringSSL updated",
- "ServerSkipCertificateVerify":"BoringSSL updated",
- "*VersionTolerance":"BoringSSL updated",
- "ConflictingVersionNegotiation*":"BoringSSL updated",
- "Ed25519DefaultDisable*":"BoringSSL updated",
- "*SHA1-Fallback*":"BoringSSL updated",
- "ExtendedMasterSecret-NoToNo*":"BoringSSL updated",
- "ServerNameExtensionClientMissing*":"BoringSSL updated",
- "NoClientCertificate*":"BoringSSL updated",
- "ServerCipherFilter*":"BoringSSL updated",
- "*FallbackSCSV*":"BoringSSL updated",
- "LooseInitialRecordVersion*":"BoringSSL updated",
- "ALPNClient*":"BoringSSL updated",
- "MinimumVersion*":"BoringSSL updated",
- "VersionNegotiation*":"BoringSSL updated",
- "*Client-ClientAuth*":"BoringSSL updated",
- "*Server-ClientAuth*":"BoringSSL updated",
- "NoExtendedMasterSecret*":"BoringSSL updated",
- "PointFormat*":"BoringSSL updated",
- "*Sync-SplitHandshakeRecords*":"BoringSSL updated",
- "*Sync-PackHandshakeFlight*":"BoringSSL updated",
- "TicketSessionIDLength*":"BoringSSL updated",
- "*LargeRecord*":"BoringSSL updated",
- "WrongMessageType-NewSessionTicket":"BoringSSL updated",
- "WrongMessageType*Certificate*":"BoringSSL updated",
- "WrongMessageType*Client*":"BoringSSL updated",
- "WrongMessageType*Server*":"BoringSSL updated",
- "WrongMessageType*DTLS":"BoringSSL updated",
- "GarbageCertificate*":"BoringSSL updated",
- "EmptyExtensions*":"BoringSSL updated",
- "*OmitExtensions*":"BoringSSL updated",
+ "ServerBogusVersion":"Check that SH.legacy_version=TLS12 when the server picks TLS 1.3 (Bug 1443761)",
+ "DummyPQPadding-Server*":"Boring is testing a dummy PQ padding extension",
+ "VerifyPreferences-Enforced":"NSS sends alerts in response to errors in protected handshake messages in the clear",
+ "Draft-Downgrade-Server":"Boring implements a draft downgrade sentinel used for measurements.",
+ "FilterExtraAlgorithms":"NSS doesn't allow sending unsupported signature algorithms",
+ "SendBogusAlertType":"Unexpected TLS alerts should abort connections (Bug 1438263)",
+ "VerifyPreferences-Ed25519":"Add Ed25519 support (Bug 1325335)",
+ "Ed25519DefaultDisable*":"Add Ed25519 support (Bug 1325335)",
+ "ServerCipherFilter*":"Add Ed25519 support (Bug 1325335)",
+ "GarbageCertificate*":"Send bad_certificate alert when certificate parsing fails (Bug 1441565)",
"SupportedVersionSelection-TLS12":"Should maybe reject TLS 1.2 in SH.supported_versions (Bug 1438266)",
"*TLS13*":"(NSS=19, BoGo=18)",
"*HelloRetryRequest*":"(NSS=19, BoGo=18)",
@@ -108,7 +55,6 @@
"WrongMessageType-TLS13-ServerCertificateVerify":"nss updated/broken",
"WrongMessageType-TLS13-ServerCertificate":"nss updated/broken",
"WrongMessageType-TLS13-ServerFinished":"nss updated/broken",
- "EncryptedExtensionsWithKeyShare":"nss updated/broken",
"EmptyEncryptedExtensions":"nss updated/broken",
"TrailingMessageData-*": "Bug 1304575",
"DuplicateKeyShares":"Bug 1304578",
diff --git a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
index e12714e8d1..72dbd57711 100644
--- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
+++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
@@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "config.h"
+#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
@@ -90,9 +91,14 @@ class TestAgent {
PRStatus prv;
PRNetAddr addr;
- prv = PR_StringToNetAddr("127.0.0.1", &addr);
+ // Try IPv6 first.
+ prv = PR_StringToNetAddr("::1", &addr);
if (prv != PR_SUCCESS) {
- return false;
+ // If that fails, try IPv4.
+ prv = PR_StringToNetAddr("127.0.0.1", &addr);
+ if (prv != PR_SUCCESS) {
+ return false;
+ }
}
addr.inet.port = PR_htons(cfg_.get<int>("port"));
@@ -256,7 +262,11 @@ class TestAgent {
}
bool SetupOptions() {
- SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
+ SECStatus rv =
+ SSL_OptionSet(ssl_fd_, SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE);
+ if (rv != SECSuccess) return false;
+
+ rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
if (rv != SECSuccess) return false;
SSLVersionRange vrange;
@@ -287,6 +297,26 @@ class TestAgent {
if (rv != SECSuccess) return false;
}
+ // Set supported signature schemes.
+ auto sign_prefs = cfg_.get<std::vector<int>>("signing-prefs");
+ auto verify_prefs = cfg_.get<std::vector<int>>("verify-prefs");
+ if (sign_prefs.empty()) {
+ sign_prefs = verify_prefs;
+ } else if (!verify_prefs.empty()) {
+ return false; // Both shouldn't be set.
+ }
+ if (!sign_prefs.empty()) {
+ std::vector<SSLSignatureScheme> sig_schemes;
+ std::transform(
+ sign_prefs.begin(), sign_prefs.end(), std::back_inserter(sig_schemes),
+ [](int scheme) { return static_cast<SSLSignatureScheme>(scheme); });
+
+ rv = SSL_SignatureSchemePrefSet(
+ ssl_fd_, sig_schemes.data(),
+ static_cast<unsigned int>(sig_schemes.size()));
+ if (rv != SECSuccess) return false;
+ }
+
if (cfg_.get<bool>("fallback-scsv")) {
rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
if (rv != SECSuccess) return false;
@@ -410,7 +440,7 @@ class TestAgent {
size_t left = sizeof(block);
while (left) {
- int32_t rv = PR_Read(ssl_fd_, block, left);
+ rv = PR_Read(ssl_fd_, block, left);
if (rv < 0) {
std::cerr << "Failure reading\n";
return SECFailure;
@@ -481,6 +511,24 @@ class TestAgent {
}
}
+ auto sig_alg = cfg_.get<int>("expect-peer-signature-algorithm");
+ if (sig_alg) {
+ SSLChannelInfo info;
+ rv = SSL_GetChannelInfo(ssl_fd_, &info, sizeof(info));
+ if (rv != SECSuccess) {
+ PRErrorCode err = PR_GetError();
+ std::cerr << "SSL_GetChannelInfo failed with error=" << FormatError(err)
+ << std::endl;
+ return SECFailure;
+ }
+
+ auto expected = static_cast<SSLSignatureScheme>(sig_alg);
+ if (info.signatureScheme != expected) {
+ std::cerr << "Unexpected signature scheme" << std::endl;
+ return SECFailure;
+ }
+ }
+
return SECSuccess;
}
@@ -513,6 +561,9 @@ std::unique_ptr<const Config> ReadConfig(int argc, char** argv) {
cfg->AddEntry<bool>("verify-peer", false);
cfg->AddEntry<std::string>("advertise-alpn", "");
cfg->AddEntry<std::string>("expect-alpn", "");
+ cfg->AddEntry<std::vector<int>>("signing-prefs", std::vector<int>());
+ cfg->AddEntry<std::vector<int>>("verify-prefs", std::vector<int>());
+ cfg->AddEntry<int>("expect-peer-signature-algorithm", 0);
auto rv = cfg->ParseArgs(argc, argv);
switch (rv) {
diff --git a/security/nss/gtests/pk11_gtest/pk11_signature_test.h b/security/nss/gtests/pk11_gtest/pk11_signature_test.h
index b141043716..8a12171a0a 100644
--- a/security/nss/gtests/pk11_gtest/pk11_signature_test.h
+++ b/security/nss/gtests/pk11_gtest/pk11_signature_test.h
@@ -25,8 +25,8 @@ struct Pkcs11SignatureTestParams {
class Pk11SignatureTest : public ::testing::Test {
protected:
- Pk11SignatureTest(CK_MECHANISM_TYPE mechanism, SECOidTag hash_oid)
- : mechanism_(mechanism), hash_oid_(hash_oid) {}
+ Pk11SignatureTest(CK_MECHANISM_TYPE mech, SECOidTag hash_oid)
+ : mechanism_(mech), hash_oid_(hash_oid) {}
virtual const SECItem* parameters() const { return nullptr; }
CK_MECHANISM_TYPE mechanism() const { return mechanism_; }
diff --git a/security/nss/gtests/ssl_gtest/libssl_internals.c b/security/nss/gtests/ssl_gtest/libssl_internals.c
index 17b4ffe49a..e43113de42 100644
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -237,22 +237,23 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
if (!ss) {
return SECFailure;
}
- if (to >= RECORD_SEQ_MAX) {
+ if (to > RECORD_SEQ_MAX) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
spec = ss->ssl3.crSpec;
- spec->seqNum = to;
+ spec->nextSeqNum = 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 (spec->seqNum <= spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
+ if (spec->nextSeqNum <=
+ spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- dtls_RecordSetRecvd(&spec->recvdRecords, spec->seqNum);
+ dtls_RecordSetRecvd(&spec->recvdRecords, spec->nextSeqNum - 1);
ssl_ReleaseSpecWriteLock(ss);
return SECSuccess;
@@ -270,7 +271,7 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
- ss->ssl3.cwSpec->seqNum = to;
+ ss->ssl3.cwSpec->nextSeqNum = to;
ssl_ReleaseSpecWriteLock(ss);
return SECSuccess;
}
@@ -284,7 +285,7 @@ SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra) {
return SECFailure;
}
ssl_GetSpecReadLock(ss);
- to = ss->ssl3.cwSpec->seqNum + DTLS_RECVD_RECORDS_WINDOW + extra;
+ to = ss->ssl3.cwSpec->nextSeqNum + DTLS_RECVD_RECORDS_WINDOW + extra;
ssl_ReleaseSpecReadLock(ss);
return SSLInt_AdvanceWriteSeqNum(fd, to);
}
diff --git a/security/nss/gtests/ssl_gtest/manifest.mn b/security/nss/gtests/ssl_gtest/manifest.mn
index 5d893bab35..8547e56d1d 100644
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -36,6 +36,7 @@ CPPSRCS = \
ssl_loopback_unittest.cc \
ssl_misc_unittest.cc \
ssl_record_unittest.cc \
+ ssl_recordsize_unittest.cc \
ssl_resumption_unittest.cc \
ssl_renegotiation_unittest.cc \
ssl_skip_unittest.cc \
diff --git a/security/nss/gtests/ssl_gtest/rsa8193.h b/security/nss/gtests/ssl_gtest/rsa8193.h
new file mode 100644
index 0000000000..6265163896
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/rsa8193.h
@@ -0,0 +1,209 @@
+/* -*- 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/. */
+
+// openssl req -nodes -x509 -newkey rsa:8193 -out cert.pem -days 365
+static const uint8_t rsa8193[] = {
+ 0x30, 0x82, 0x09, 0x61, 0x30, 0x82, 0x05, 0x48, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xaf, 0xff, 0x37, 0x91, 0x3e, 0x44, 0xae, 0x57,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x0b, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
+ 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x35, 0x31, 0x37,
+ 0x30, 0x39, 0x34, 0x32, 0x32, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30,
+ 0x35, 0x31, 0x37, 0x30, 0x39, 0x34, 0x32, 0x32, 0x39, 0x5a, 0x30, 0x45,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
+ 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a,
+ 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
+ 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74,
+ 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
+ 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x82, 0x04,
+ 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x04, 0x0f, 0x00, 0x30, 0x82, 0x04,
+ 0x0a, 0x02, 0x82, 0x04, 0x01, 0x01, 0x77, 0xd6, 0xa9, 0x93, 0x4e, 0x15,
+ 0xb5, 0x67, 0x70, 0x8e, 0xc3, 0x77, 0x4f, 0xc9, 0x8a, 0x06, 0xd9, 0xb9,
+ 0xa6, 0x41, 0xb8, 0xfa, 0x4a, 0x13, 0x26, 0xdc, 0x2b, 0xc5, 0x82, 0xa0,
+ 0x74, 0x8c, 0x1e, 0xe9, 0xc0, 0x70, 0x15, 0x56, 0xec, 0x1f, 0x7e, 0x91,
+ 0x6e, 0x31, 0x42, 0x8b, 0xd5, 0xe2, 0x0e, 0x9c, 0xeb, 0xff, 0xbc, 0xf9,
+ 0x42, 0xd3, 0xb9, 0x1c, 0x5e, 0x46, 0x80, 0x90, 0x5f, 0xe1, 0x59, 0x22,
+ 0x13, 0x71, 0xd3, 0xd6, 0x66, 0x7a, 0xe0, 0x56, 0x04, 0x10, 0x59, 0x01,
+ 0xb3, 0xb6, 0xd2, 0xc7, 0xa7, 0x3b, 0xbc, 0xe6, 0x38, 0x44, 0xd5, 0x71,
+ 0x66, 0x1d, 0xb2, 0x63, 0x2f, 0xa9, 0x5e, 0x80, 0x92, 0x3c, 0x21, 0x0e,
+ 0xe1, 0xda, 0xd6, 0x1d, 0xcb, 0xce, 0xac, 0xe1, 0x5f, 0x97, 0x45, 0x8f,
+ 0xc1, 0x64, 0x16, 0xa6, 0x88, 0x2a, 0x36, 0x4a, 0x76, 0x64, 0x8f, 0x83,
+ 0x7a, 0x1d, 0xd8, 0x91, 0x90, 0x7b, 0x58, 0xb8, 0x1c, 0x7f, 0x56, 0x57,
+ 0x35, 0xfb, 0xf3, 0x1a, 0xcb, 0x7c, 0x66, 0x66, 0x04, 0x95, 0xee, 0x3a,
+ 0x80, 0xf0, 0xd4, 0x12, 0x3a, 0x7e, 0x7e, 0x5e, 0xb8, 0x55, 0x29, 0x23,
+ 0x06, 0xd3, 0x85, 0x0c, 0x99, 0x91, 0x42, 0xee, 0x5a, 0x30, 0x7f, 0x52,
+ 0x20, 0xb3, 0xe2, 0xe7, 0x39, 0x69, 0xb6, 0xfc, 0x42, 0x1e, 0x98, 0xd3,
+ 0x31, 0xa2, 0xfa, 0x81, 0x52, 0x69, 0x6d, 0x23, 0xf8, 0xc4, 0xc3, 0x3c,
+ 0x9b, 0x48, 0x75, 0xa8, 0xc7, 0xe7, 0x61, 0x81, 0x1f, 0xf7, 0xce, 0x10,
+ 0xaa, 0x13, 0xcb, 0x6e, 0x19, 0xc0, 0x4f, 0x6f, 0x90, 0xa8, 0x41, 0xea,
+ 0x49, 0xdf, 0xe4, 0xef, 0x84, 0x54, 0xb5, 0x37, 0xaf, 0x12, 0x75, 0x1a,
+ 0x11, 0x4b, 0x58, 0x7f, 0x63, 0x22, 0x33, 0xb1, 0xc8, 0x4d, 0xf2, 0x41,
+ 0x10, 0xbc, 0x37, 0xb5, 0xd5, 0xb2, 0x21, 0x32, 0x35, 0x9d, 0xf3, 0x8d,
+ 0xab, 0x66, 0x9d, 0x19, 0x12, 0x71, 0x45, 0xb3, 0x82, 0x5a, 0x5c, 0xff,
+ 0x2d, 0xcf, 0xf4, 0x5b, 0x56, 0xb8, 0x08, 0xb3, 0xd2, 0x43, 0x8c, 0xac,
+ 0xd2, 0xf8, 0xcc, 0x6d, 0x90, 0x97, 0xff, 0x12, 0x74, 0x97, 0xf8, 0xa4,
+ 0xe3, 0x95, 0xae, 0x92, 0xdc, 0x7e, 0x9d, 0x2b, 0xb4, 0x94, 0xc3, 0x8d,
+ 0x80, 0xe7, 0x77, 0x5c, 0x5b, 0xbb, 0x43, 0xdc, 0xa6, 0xe9, 0xbe, 0x20,
+ 0xcc, 0x9d, 0x8e, 0xa4, 0x2b, 0xf2, 0x72, 0xdc, 0x44, 0x61, 0x0f, 0xad,
+ 0x1a, 0x5e, 0xa5, 0x48, 0xe4, 0x42, 0xc5, 0xe4, 0xf1, 0x6d, 0x33, 0xdb,
+ 0xb2, 0x1b, 0x9f, 0xb2, 0xff, 0x18, 0x0e, 0x62, 0x35, 0x99, 0xed, 0x22,
+ 0x19, 0x4a, 0x5e, 0xb3, 0x3c, 0x07, 0x8f, 0x6e, 0x22, 0x5b, 0x16, 0x4a,
+ 0x9f, 0xef, 0xf3, 0xe7, 0xd6, 0x48, 0xe1, 0xb4, 0x3b, 0xab, 0x1b, 0x9e,
+ 0x53, 0xd7, 0x1b, 0xd9, 0x2d, 0x51, 0x8f, 0xe4, 0x1c, 0xab, 0xdd, 0xb9,
+ 0xe2, 0xee, 0xe4, 0xdd, 0x60, 0x04, 0x86, 0x6b, 0x4e, 0x7a, 0xc8, 0x09,
+ 0x51, 0xd1, 0x9b, 0x36, 0x9a, 0x36, 0x7f, 0xe8, 0x6b, 0x09, 0x6c, 0xee,
+ 0xad, 0x3a, 0x2f, 0xa8, 0x63, 0x92, 0x23, 0x2f, 0x7e, 0x00, 0xe2, 0xd1,
+ 0xbb, 0xd9, 0x5b, 0x5b, 0xfa, 0x4b, 0x83, 0x00, 0x19, 0x28, 0xfb, 0x7e,
+ 0xfe, 0x58, 0xab, 0xb7, 0x33, 0x45, 0x8f, 0x75, 0x9a, 0x54, 0x3d, 0x77,
+ 0x06, 0x75, 0x61, 0x4f, 0x5c, 0x93, 0xa0, 0xf9, 0xe8, 0xcf, 0xf6, 0x04,
+ 0x14, 0xda, 0x1b, 0x2e, 0x79, 0x35, 0xb8, 0xb4, 0xfa, 0x08, 0x27, 0x9a,
+ 0x03, 0x70, 0x78, 0x97, 0x8f, 0xae, 0x2e, 0xd5, 0x1c, 0xe0, 0x4d, 0x91,
+ 0x3a, 0xfe, 0x1a, 0x64, 0xd8, 0x49, 0xdf, 0x6c, 0x66, 0xac, 0xc9, 0x57,
+ 0x06, 0x72, 0xc0, 0xc0, 0x09, 0x71, 0x6a, 0xd0, 0xb0, 0x7d, 0x35, 0x3f,
+ 0x53, 0x17, 0x49, 0x38, 0x92, 0x22, 0x55, 0xf6, 0x58, 0x56, 0xa2, 0x42,
+ 0x77, 0x94, 0xb7, 0x28, 0x0a, 0xa0, 0xd2, 0xda, 0x25, 0xc1, 0xcc, 0x52,
+ 0x51, 0xd6, 0xba, 0x18, 0x0f, 0x0d, 0xe3, 0x7d, 0xd1, 0xda, 0xd9, 0x0c,
+ 0x5e, 0x3a, 0xca, 0xe9, 0xf1, 0xf5, 0x65, 0xfc, 0xc3, 0x99, 0x72, 0x25,
+ 0xf2, 0xc0, 0xa1, 0x8c, 0x43, 0x9d, 0xb2, 0xc9, 0xb1, 0x1a, 0x24, 0x34,
+ 0x57, 0xd8, 0xa7, 0x52, 0xa3, 0x39, 0x6e, 0x0b, 0xec, 0xbd, 0x5e, 0xc9,
+ 0x1f, 0x74, 0xed, 0xae, 0xe6, 0x4e, 0x49, 0xe8, 0x87, 0x3e, 0x46, 0x0d,
+ 0x40, 0x30, 0xda, 0x9d, 0xcf, 0xf5, 0x03, 0x1f, 0x38, 0x29, 0x3b, 0x66,
+ 0xe5, 0xc0, 0x89, 0x4c, 0xfc, 0x09, 0x62, 0x37, 0x01, 0xf9, 0x01, 0xab,
+ 0x8d, 0x53, 0x9c, 0x36, 0x5d, 0x36, 0x66, 0x8d, 0x87, 0xf4, 0xab, 0x37,
+ 0xb7, 0xf7, 0xe3, 0xdf, 0xc1, 0x52, 0xc0, 0x1d, 0x09, 0x92, 0x21, 0x47,
+ 0x49, 0x9a, 0x19, 0x38, 0x05, 0x62, 0xf3, 0x47, 0x80, 0x89, 0x1e, 0x70,
+ 0xa1, 0x57, 0xb7, 0x72, 0xd0, 0x41, 0x7a, 0x5c, 0x6a, 0x13, 0x8b, 0x6c,
+ 0xda, 0xdf, 0x6b, 0x01, 0x15, 0x20, 0xfa, 0xc8, 0x67, 0xee, 0xb2, 0x13,
+ 0xd8, 0x5f, 0x84, 0x30, 0x44, 0x8e, 0xf9, 0x2a, 0xae, 0x17, 0x53, 0x49,
+ 0xaa, 0x34, 0x31, 0x12, 0x31, 0xec, 0xf3, 0x25, 0x27, 0x53, 0x6b, 0xb5,
+ 0x63, 0xa6, 0xbc, 0xf1, 0x77, 0xd4, 0xb4, 0x77, 0xd1, 0xee, 0xad, 0x62,
+ 0x9d, 0x2c, 0x2e, 0x11, 0x0a, 0xd1, 0x87, 0xfe, 0xef, 0x77, 0x0e, 0xd1,
+ 0x38, 0xfe, 0xcc, 0x88, 0xaa, 0x1c, 0x06, 0x93, 0x25, 0x56, 0xfe, 0x0c,
+ 0x52, 0xe9, 0x7f, 0x4c, 0x3b, 0x2a, 0xfb, 0x40, 0x62, 0x29, 0x0a, 0x1d,
+ 0x58, 0x78, 0x8b, 0x09, 0x25, 0xaa, 0xc6, 0x8f, 0x66, 0x8f, 0xd1, 0x93,
+ 0x5a, 0xd6, 0x68, 0x35, 0x69, 0x13, 0x5d, 0x42, 0x35, 0x95, 0xcb, 0xc4,
+ 0xec, 0x17, 0x92, 0x96, 0xcb, 0x4a, 0xb9, 0x8f, 0xe5, 0xc4, 0x4a, 0xe7,
+ 0x54, 0x52, 0x4c, 0x64, 0x06, 0xac, 0x2f, 0x13, 0x32, 0x02, 0x47, 0x13,
+ 0x5c, 0xa2, 0x66, 0xdc, 0x36, 0x0c, 0x4f, 0xbb, 0x89, 0x58, 0x85, 0x16,
+ 0xf1, 0xf1, 0xff, 0xd2, 0x86, 0x54, 0x29, 0xb3, 0x7e, 0x2a, 0xbd, 0xf9,
+ 0x53, 0x8c, 0xa0, 0x60, 0x60, 0xb2, 0x90, 0x7f, 0x3a, 0x11, 0x5f, 0x2a,
+ 0x50, 0x74, 0x2a, 0xd1, 0x68, 0x78, 0xdb, 0x31, 0x1b, 0x8b, 0xee, 0xee,
+ 0x18, 0x97, 0xf3, 0x50, 0x84, 0xc1, 0x8f, 0xe1, 0xc6, 0x01, 0xb4, 0x16,
+ 0x65, 0x25, 0x0c, 0x03, 0xab, 0xed, 0x4f, 0xd6, 0xe6, 0x16, 0x23, 0xcc,
+ 0x42, 0x93, 0xff, 0xfa, 0x92, 0x63, 0x33, 0x9e, 0x36, 0xb0, 0xdc, 0x9a,
+ 0xb6, 0xaa, 0xd7, 0x48, 0xfe, 0x27, 0x01, 0xcf, 0x67, 0xc0, 0x75, 0xa0,
+ 0x86, 0x9a, 0xec, 0xa7, 0x2e, 0xb8, 0x7b, 0x00, 0x7f, 0xd4, 0xe3, 0xb3,
+ 0xfc, 0x48, 0xab, 0x50, 0x20, 0xd4, 0x0d, 0x58, 0x26, 0xc0, 0x3c, 0x09,
+ 0x0b, 0x80, 0x9e, 0xaf, 0x14, 0x3c, 0x0c, 0x6e, 0x69, 0xbc, 0x6c, 0x4e,
+ 0x50, 0x33, 0xb0, 0x07, 0x64, 0x6e, 0x77, 0x96, 0xc2, 0xe6, 0x3b, 0xd7,
+ 0xfe, 0xdc, 0xa4, 0x2f, 0x18, 0x5b, 0x53, 0xe5, 0xdd, 0xb6, 0xce, 0xeb,
+ 0x16, 0xb4, 0x25, 0xc6, 0xcb, 0xf2, 0x65, 0x3c, 0x4f, 0x94, 0xa5, 0x11,
+ 0x18, 0xeb, 0x7b, 0x62, 0x1d, 0xd5, 0x02, 0x35, 0x76, 0xf6, 0xb5, 0x20,
+ 0x27, 0x21, 0x9b, 0xab, 0xf4, 0xb6, 0x8f, 0x1a, 0x70, 0x1d, 0x12, 0xe3,
+ 0xb9, 0x8e, 0x29, 0x52, 0x25, 0xf4, 0xba, 0xb4, 0x25, 0x2c, 0x91, 0x11,
+ 0xf2, 0xae, 0x7b, 0xbe, 0xb6, 0x67, 0xd6, 0x08, 0xf8, 0x6f, 0xe7, 0xb0,
+ 0x16, 0xc5, 0xf6, 0xd5, 0xfb, 0x07, 0x71, 0x5b, 0x0e, 0xe1, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xaa, 0xe7, 0x7f, 0xcf, 0xf8, 0xb4,
+ 0xe0, 0x8d, 0x39, 0x9a, 0x1d, 0x4f, 0x86, 0xa2, 0xac, 0x56, 0x32, 0xd9,
+ 0x58, 0xe3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
+ 0x16, 0x80, 0x14, 0xaa, 0xe7, 0x7f, 0xcf, 0xf8, 0xb4, 0xe0, 0x8d, 0x39,
+ 0x9a, 0x1d, 0x4f, 0x86, 0xa2, 0xac, 0x56, 0x32, 0xd9, 0x58, 0xe3, 0x30,
+ 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+ 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x04, 0x02, 0x00,
+ 0x00, 0x0a, 0x0a, 0x81, 0xb5, 0x2e, 0xac, 0x52, 0xab, 0x0f, 0xeb, 0xad,
+ 0x96, 0xd6, 0xd6, 0x59, 0x8f, 0x55, 0x15, 0x56, 0x70, 0xda, 0xd5, 0x75,
+ 0x47, 0x12, 0x9a, 0x0e, 0xd1, 0x65, 0x68, 0xe0, 0x51, 0x89, 0x59, 0xcc,
+ 0xe3, 0x5a, 0x1b, 0x85, 0x14, 0xa3, 0x1d, 0x9b, 0x3f, 0xd1, 0xa4, 0x42,
+ 0xb0, 0x89, 0x12, 0x93, 0xd3, 0x54, 0x19, 0x04, 0xa2, 0xaf, 0xaa, 0x60,
+ 0xca, 0x03, 0xc2, 0xae, 0x62, 0x8c, 0xb6, 0x31, 0x03, 0xd6, 0xa5, 0xf3,
+ 0x5e, 0x8d, 0x5c, 0x69, 0x4c, 0x7d, 0x81, 0x49, 0x20, 0x25, 0x41, 0xa4,
+ 0x2a, 0x95, 0x87, 0x36, 0xa3, 0x9b, 0x9e, 0x9f, 0xed, 0x85, 0xf3, 0xb1,
+ 0xf1, 0xe9, 0x1b, 0xbb, 0xe3, 0xbc, 0x3b, 0x11, 0x36, 0xca, 0xb9, 0x5f,
+ 0xee, 0x64, 0xde, 0x2a, 0x99, 0x27, 0x91, 0xc0, 0x54, 0x9e, 0x7a, 0xd4,
+ 0x89, 0x8c, 0xa0, 0xe3, 0xfd, 0x44, 0x6f, 0x02, 0x38, 0x3c, 0xee, 0x52,
+ 0x48, 0x1b, 0xd4, 0x25, 0x2b, 0xcb, 0x8e, 0xa8, 0x1b, 0x09, 0xd6, 0x30,
+ 0x51, 0x15, 0x6c, 0x5c, 0x03, 0x76, 0xad, 0x64, 0x45, 0x50, 0xa2, 0xe1,
+ 0x3c, 0x5a, 0x67, 0x87, 0xff, 0x8c, 0xed, 0x9a, 0x8d, 0x04, 0xc1, 0xac,
+ 0xf9, 0xca, 0xf5, 0x2a, 0x05, 0x9c, 0xdd, 0x78, 0xce, 0x99, 0x78, 0x7b,
+ 0xcd, 0x43, 0x10, 0x40, 0xf7, 0xb5, 0x27, 0x12, 0xec, 0xe9, 0xb2, 0x3f,
+ 0xf4, 0x5d, 0xd9, 0xbb, 0xf8, 0xc4, 0xc9, 0xa4, 0x46, 0x20, 0x41, 0x7f,
+ 0xeb, 0x79, 0xb0, 0x51, 0x8c, 0xf7, 0xc3, 0x2c, 0x16, 0xfe, 0x42, 0x59,
+ 0x77, 0xfe, 0x53, 0xfe, 0x19, 0x57, 0x58, 0x44, 0x6d, 0x12, 0xe2, 0x95,
+ 0xd0, 0xd3, 0x5a, 0xb5, 0x2d, 0xe5, 0x7e, 0xb4, 0xb3, 0xa9, 0xcc, 0x7d,
+ 0x53, 0x77, 0x81, 0x01, 0x0f, 0x0a, 0xf6, 0x86, 0x3c, 0x7d, 0xb5, 0x2c,
+ 0xbf, 0x62, 0xc3, 0xf5, 0x38, 0x89, 0x13, 0x84, 0x1f, 0x44, 0x2d, 0x87,
+ 0x5c, 0x23, 0x9e, 0x05, 0x62, 0x56, 0x3d, 0x71, 0x4d, 0xd0, 0xe3, 0x15,
+ 0xe9, 0x09, 0x9c, 0x1a, 0xc0, 0x9a, 0x19, 0x8b, 0x9c, 0xe9, 0xae, 0xde,
+ 0x62, 0x05, 0x23, 0xe2, 0xd0, 0x3f, 0xf5, 0xef, 0x04, 0x96, 0x4c, 0x87,
+ 0x34, 0x2f, 0xd5, 0x90, 0xde, 0xbf, 0x4b, 0x56, 0x12, 0x5f, 0xc6, 0xdc,
+ 0xa4, 0x1c, 0xc4, 0x53, 0x0c, 0xf9, 0xb4, 0xe4, 0x2c, 0xe7, 0x48, 0xbd,
+ 0xb1, 0xac, 0xf1, 0xc1, 0x8d, 0x53, 0x47, 0x84, 0xc0, 0x78, 0x0a, 0x5e,
+ 0xc2, 0x16, 0xff, 0xef, 0x97, 0x5b, 0x33, 0x85, 0x92, 0xcd, 0xd4, 0xbb,
+ 0x64, 0xee, 0xed, 0x17, 0x18, 0x43, 0x32, 0x99, 0x32, 0x36, 0x25, 0xf4,
+ 0x21, 0x3c, 0x2f, 0x55, 0xdc, 0x16, 0x06, 0x4d, 0x86, 0xa3, 0xa9, 0x34,
+ 0x22, 0xd5, 0xc3, 0xc8, 0x64, 0x3c, 0x4e, 0x3a, 0x69, 0xbd, 0xcf, 0xd7,
+ 0xee, 0x3f, 0x0d, 0x15, 0xeb, 0xfb, 0xbd, 0x91, 0x7f, 0xef, 0x48, 0xec,
+ 0x86, 0xb2, 0x78, 0xf7, 0x53, 0x90, 0x38, 0xb5, 0x04, 0x9c, 0xb7, 0xd7,
+ 0x9e, 0xaa, 0x15, 0xf7, 0xcd, 0xc2, 0x17, 0xd5, 0x8f, 0x82, 0x98, 0xa3,
+ 0xaf, 0x59, 0xf1, 0x71, 0xda, 0x6e, 0xaf, 0x97, 0x6d, 0x77, 0x72, 0xfd,
+ 0xa8, 0x80, 0x25, 0xce, 0x46, 0x04, 0x6e, 0x40, 0x15, 0x24, 0xc0, 0xf9,
+ 0xbf, 0x13, 0x16, 0x72, 0xcb, 0xb7, 0x10, 0xc7, 0x0a, 0xd6, 0x66, 0x96,
+ 0x5b, 0x27, 0x4d, 0x66, 0xc4, 0x2f, 0x21, 0x90, 0x9f, 0x8c, 0x24, 0xa0,
+ 0x0e, 0xa2, 0x89, 0x92, 0xd2, 0x44, 0x63, 0x06, 0xb2, 0xab, 0x07, 0x26,
+ 0xde, 0x03, 0x1d, 0xdb, 0x2a, 0x42, 0x5b, 0x4c, 0xf6, 0xfe, 0x53, 0xfa,
+ 0x80, 0x45, 0x8d, 0x75, 0xf6, 0x0e, 0x1d, 0xcc, 0x4c, 0x3b, 0xb0, 0x80,
+ 0x6d, 0x4c, 0xed, 0x7c, 0xe0, 0xd2, 0xe7, 0x62, 0x59, 0xb1, 0x5a, 0x5d,
+ 0x3a, 0xec, 0x86, 0x04, 0xfe, 0x26, 0xd1, 0x18, 0xed, 0x56, 0x7d, 0x67,
+ 0x56, 0x24, 0x6d, 0x7c, 0x6e, 0x8f, 0xc8, 0xa0, 0xba, 0x42, 0x0a, 0x33,
+ 0x38, 0x7a, 0x09, 0x03, 0xc2, 0xbf, 0x9b, 0x01, 0xdd, 0x03, 0x5a, 0xba,
+ 0x76, 0x04, 0xb1, 0xc3, 0x40, 0x23, 0x53, 0xbd, 0x64, 0x4e, 0x0f, 0xe7,
+ 0xc3, 0x4e, 0x48, 0xea, 0x19, 0x2b, 0x1c, 0xe4, 0x3d, 0x93, 0xd8, 0xf6,
+ 0xfb, 0xda, 0x3d, 0xeb, 0xed, 0xc2, 0xbd, 0x14, 0x57, 0x40, 0xde, 0xd1,
+ 0x74, 0x54, 0x1b, 0xa8, 0x39, 0xda, 0x73, 0x56, 0xd4, 0xbe, 0xab, 0xec,
+ 0xc7, 0x17, 0x4f, 0x91, 0xb6, 0xf6, 0xcb, 0x24, 0xc6, 0x1c, 0x07, 0xc4,
+ 0xf3, 0xd0, 0x5e, 0x8d, 0xfa, 0x44, 0x98, 0x5c, 0x87, 0x36, 0x75, 0xb6,
+ 0xa5, 0x31, 0xaa, 0xab, 0x7d, 0x38, 0x66, 0xb3, 0x18, 0x58, 0x65, 0x97,
+ 0x06, 0xfd, 0x61, 0x81, 0x71, 0xc5, 0x17, 0x8b, 0x19, 0x03, 0xc8, 0x58,
+ 0xec, 0x05, 0xca, 0x7b, 0x0f, 0xec, 0x9d, 0xb4, 0xbc, 0xa3, 0x20, 0x2e,
+ 0xf8, 0xe4, 0xb1, 0x82, 0xdc, 0x5a, 0xd2, 0x92, 0x9c, 0x43, 0x5d, 0x16,
+ 0x5b, 0x90, 0x80, 0xe4, 0xfb, 0x6e, 0x24, 0x6b, 0x8c, 0x1a, 0x35, 0xab,
+ 0xbd, 0x77, 0x7f, 0xf9, 0x61, 0x80, 0xa5, 0xab, 0xa3, 0x39, 0xc2, 0xc9,
+ 0x69, 0x3c, 0xfc, 0xb3, 0x9a, 0x05, 0x45, 0x03, 0x88, 0x8f, 0x8e, 0x23,
+ 0xf2, 0x0c, 0x4c, 0x54, 0xb9, 0x40, 0x3a, 0x31, 0x1a, 0x22, 0x67, 0x43,
+ 0x4a, 0x3e, 0xa0, 0x8c, 0x2d, 0x4d, 0x4f, 0xfc, 0xb5, 0x9b, 0x1f, 0xe1,
+ 0xef, 0x02, 0x54, 0xab, 0x8d, 0x75, 0x4d, 0x93, 0xba, 0x76, 0xe1, 0xbc,
+ 0x42, 0x7f, 0x6c, 0xcb, 0xf5, 0x47, 0xd6, 0x8a, 0xac, 0x5d, 0xe9, 0xbb,
+ 0x3a, 0x65, 0x2c, 0x81, 0xe5, 0xff, 0x27, 0x7e, 0x60, 0x64, 0x80, 0x42,
+ 0x8d, 0x36, 0x6b, 0x07, 0x76, 0x6a, 0xf1, 0xdf, 0x96, 0x17, 0x93, 0x21,
+ 0x5d, 0xe4, 0x6c, 0xce, 0x1c, 0xb9, 0x82, 0x45, 0x05, 0x61, 0xe2, 0x41,
+ 0x96, 0x03, 0x7d, 0x10, 0x8b, 0x3e, 0xc7, 0xe5, 0xcf, 0x08, 0xeb, 0x81,
+ 0xd3, 0x82, 0x1b, 0x04, 0x96, 0x93, 0x5a, 0xe2, 0x8c, 0x8e, 0x50, 0x33,
+ 0xf6, 0xf9, 0xf0, 0xfb, 0xb1, 0xd7, 0xc6, 0x97, 0xaa, 0xef, 0x0b, 0x87,
+ 0xe1, 0x34, 0x97, 0x78, 0x2e, 0x7c, 0x46, 0x11, 0xd5, 0x3c, 0xec, 0x38,
+ 0x70, 0x59, 0x14, 0x65, 0x4d, 0x0e, 0xd1, 0xeb, 0x49, 0xb3, 0x99, 0x6f,
+ 0x87, 0xf1, 0x79, 0x21, 0xd9, 0x5c, 0x37, 0xb2, 0xfe, 0xc4, 0x7a, 0xc1,
+ 0x67, 0xbd, 0x02, 0xfc, 0x02, 0xab, 0x2f, 0xf5, 0x0f, 0xa7, 0xae, 0x90,
+ 0xc2, 0xaf, 0xdb, 0xd1, 0x96, 0xb2, 0x92, 0x5a, 0xfb, 0xca, 0x28, 0x74,
+ 0x17, 0xed, 0xda, 0x2c, 0x9f, 0xb4, 0x2d, 0xf5, 0x71, 0x20, 0x64, 0x2d,
+ 0x44, 0xe5, 0xa3, 0xa0, 0x94, 0x6f, 0x20, 0xb3, 0x73, 0x96, 0x40, 0x06,
+ 0x9b, 0x25, 0x47, 0x4b, 0xe0, 0x63, 0x91, 0xd9, 0xda, 0xf3, 0xc3, 0xe5,
+ 0x3a, 0x3c, 0xb7, 0x5f, 0xab, 0x1e, 0x51, 0x17, 0x4f, 0xec, 0xc1, 0x6d,
+ 0x82, 0x79, 0x8e, 0xba, 0x7c, 0x47, 0x8e, 0x99, 0x00, 0x17, 0x9e, 0xda,
+ 0x10, 0x42, 0x70, 0x25, 0x42, 0x84, 0xc8, 0xb1, 0x95, 0x56, 0xb2, 0x08,
+ 0xa0, 0x4f, 0xdc, 0xcd, 0x9e, 0x31, 0x4b, 0x0c, 0x0b, 0x03, 0x5d, 0x2c,
+ 0x26, 0xbc, 0xa9, 0x4b, 0x19, 0xdf, 0x90, 0x01, 0x9a, 0xe0, 0x06, 0x05,
+ 0x13, 0x34, 0x9d, 0x34, 0xb8, 0xef, 0x13, 0x3a, 0x20, 0xf5, 0x74, 0x02,
+ 0x70, 0x3b, 0x41, 0x60, 0x1f, 0x5e, 0x76, 0x0a, 0xb1, 0x17, 0xd5, 0xcf,
+ 0x79, 0xef, 0xf7, 0xab, 0xe7, 0xd6, 0x0f, 0xad, 0x85, 0x2c, 0x52, 0x67,
+ 0xb5, 0xa0, 0x4a, 0xfd, 0xaf}; \ No newline at end of file
diff --git a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
index 08781af711..28fdc66318 100644
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -345,8 +345,8 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttNoAlpnClient) {
TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpnChangeBoth) {
EnableAlpn();
SetupForZeroRtt();
- static const uint8_t alpn[] = {0x01, 0x62}; // "b"
- EnableAlpn(alpn, sizeof(alpn));
+ static const std::vector<uint8_t> alpn({0x01, 0x62}); // "b"
+ EnableAlpn(alpn);
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
diff --git a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
index f0c57e8b10..6be3b61f8d 100644
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -8,9 +8,6 @@
#include "sslerr.h"
#include "sslproto.h"
-// This is an internal header, used to get TLS_1_3_DRAFT_VERSION.
-#include "ssl3prot.h"
-
#include <memory>
#include "databuffer.h"
@@ -21,7 +18,6 @@
namespace nss_test {
-static const uint8_t kD13 = TLS_1_3_DRAFT_VERSION;
// This is a 1-RTT ClientHello with ECDHE.
const static uint8_t kCannedTls13ClientHello[] = {
0x01, 0x00, 0x00, 0xcf, 0x03, 0x03, 0x6c, 0xb3, 0x46, 0x81, 0xc8, 0x1a,
@@ -42,16 +38,7 @@ const static uint8_t kCannedTls13ClientHello[] = {
0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08,
0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01, 0x04,
0x02, 0x05, 0x02, 0x06, 0x02, 0x02, 0x02};
-
-const static uint8_t kCannedTls13ServerHello[] = {
- 0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
- 0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
- 0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
- 0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
- 0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
- 0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
- 0x80, 0x8f, 0x2c, 0xac, 0x0a, 0xea, 0x53, 0x3a, 0xcb, 0xe3, 0x08,
- 0x84, 0xae, 0x19, 0x00, 0x2b, 0x00, 0x02, 0x7f, kD13};
+static const size_t kFirstFragmentSize = 20;
static const char *k0RttData = "ABCDEF";
TEST_P(TlsAgentTest, EarlyFinished) {
@@ -74,8 +61,9 @@ TEST_P(TlsAgentTestClient13, CannedHello) {
DataBuffer buffer;
EnsureInit();
DataBuffer server_hello;
- MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
- sizeof(kCannedTls13ServerHello), &server_hello);
+ auto sh = MakeCannedTls13ServerHello();
+ MakeHandshakeMessage(kTlsHandshakeServerHello, sh.data(), sh.len(),
+ &server_hello);
MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
server_hello.data(), server_hello.len(), &buffer);
ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
@@ -83,8 +71,9 @@ TEST_P(TlsAgentTestClient13, CannedHello) {
TEST_P(TlsAgentTestClient13, EncryptedExtensionsInClear) {
DataBuffer server_hello;
- MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
- sizeof(kCannedTls13ServerHello), &server_hello);
+ auto sh = MakeCannedTls13ServerHello();
+ MakeHandshakeMessage(kTlsHandshakeServerHello, sh.data(), sh.len(),
+ &server_hello);
DataBuffer encrypted_extensions;
MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
&encrypted_extensions, 1);
@@ -100,19 +89,21 @@ TEST_P(TlsAgentTestClient13, EncryptedExtensionsInClear) {
TEST_F(TlsAgentStreamTestClient, EncryptedExtensionsInClearTwoPieces) {
DataBuffer server_hello;
- MakeHandshakeMessage(kTlsHandshakeServerHello, kCannedTls13ServerHello,
- sizeof(kCannedTls13ServerHello), &server_hello);
+ auto sh = MakeCannedTls13ServerHello();
+ MakeHandshakeMessage(kTlsHandshakeServerHello, sh.data(), sh.len(),
+ &server_hello);
DataBuffer encrypted_extensions;
MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
&encrypted_extensions, 1);
server_hello.Append(encrypted_extensions);
DataBuffer buffer;
MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
- server_hello.data(), 20, &buffer);
+ server_hello.data(), kFirstFragmentSize, &buffer);
DataBuffer buffer2;
MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
- server_hello.data() + 20, server_hello.len() - 20, &buffer2);
+ server_hello.data() + kFirstFragmentSize,
+ server_hello.len() - kFirstFragmentSize, &buffer2);
EnsureInit();
agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
@@ -124,15 +115,15 @@ TEST_F(TlsAgentStreamTestClient, EncryptedExtensionsInClearTwoPieces) {
}
TEST_F(TlsAgentDgramTestClient, EncryptedExtensionsInClearTwoPieces) {
+ auto sh = MakeCannedTls13ServerHello();
DataBuffer server_hello_frag1;
- MakeHandshakeMessageFragment(
- kTlsHandshakeServerHello, kCannedTls13ServerHello,
- sizeof(kCannedTls13ServerHello), &server_hello_frag1, 0, 0, 20);
+ MakeHandshakeMessageFragment(kTlsHandshakeServerHello, sh.data(), sh.len(),
+ &server_hello_frag1, 0, 0, kFirstFragmentSize);
DataBuffer server_hello_frag2;
- MakeHandshakeMessageFragment(
- kTlsHandshakeServerHello, kCannedTls13ServerHello + 20,
- sizeof(kCannedTls13ServerHello), &server_hello_frag2, 0, 20,
- sizeof(kCannedTls13ServerHello) - 20);
+ MakeHandshakeMessageFragment(kTlsHandshakeServerHello,
+ sh.data() + kFirstFragmentSize, sh.len(),
+ &server_hello_frag2, 0, kFirstFragmentSize,
+ sh.len() - kFirstFragmentSize);
DataBuffer encrypted_extensions;
MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
&encrypted_extensions, 1);
@@ -154,6 +145,35 @@ TEST_F(TlsAgentDgramTestClient, EncryptedExtensionsInClearTwoPieces) {
SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
}
+TEST_F(TlsAgentDgramTestClient, AckWithBogusLengthField) {
+ EnsureInit();
+ // Length doesn't match
+ const uint8_t ackBuf[] = {0x00, 0x08, 0x00};
+ DataBuffer record;
+ MakeRecord(variant_, kTlsAckType, SSL_LIBRARY_VERSION_TLS_1_2, ackBuf,
+ sizeof(ackBuf), &record, 0);
+ agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ ExpectAlert(kTlsAlertDecodeError);
+ ProcessMessage(record, TlsAgent::STATE_ERROR,
+ SSL_ERROR_RX_MALFORMED_DTLS_ACK);
+}
+
+TEST_F(TlsAgentDgramTestClient, AckWithNonEvenLength) {
+ EnsureInit();
+ // Length isn't a multiple of 8
+ const uint8_t ackBuf[] = {0x00, 0x01, 0x00};
+ DataBuffer record;
+ MakeRecord(variant_, kTlsAckType, SSL_LIBRARY_VERSION_TLS_1_2, ackBuf,
+ sizeof(ackBuf), &record, 0);
+ agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+ // Because we haven't negotiated the version,
+ // ssl3_DecodeError() sends an older (pre-TLS error).
+ ExpectAlert(kTlsAlertIllegalParameter);
+ ProcessMessage(record, TlsAgent::STATE_ERROR, SSL_ERROR_BAD_SERVER);
+}
+
TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
EnsureInit();
agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
diff --git a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
index 7f2b2840d5..e2a30e6bcb 100644
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -155,8 +155,8 @@ TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) {
class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter {
public:
- TlsZeroCertificateRequestSigAlgsFilter(const std::shared_ptr<TlsAgent>& agent)
- : TlsHandshakeFilter(agent, {kTlsHandshakeCertificateRequest}) {}
+ TlsZeroCertificateRequestSigAlgsFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}) {}
virtual PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
const DataBuffer& input, DataBuffer* output) {
@@ -366,6 +366,50 @@ TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) {
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
+// Replaces the signature scheme in a TLS 1.3 CertificateVerify message.
+class TlsReplaceSignatureSchemeFilter : public TlsHandshakeFilter {
+ public:
+ TlsReplaceSignatureSchemeFilter(const std::shared_ptr<TlsAgent>& a,
+ SSLSignatureScheme scheme)
+ : TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}),
+ scheme_(scheme) {
+ EnableDecryption();
+ }
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ *output = input;
+ output->Write(0, scheme_, 2);
+ return CHANGE;
+ }
+
+ private:
+ SSLSignatureScheme scheme_;
+};
+
+TEST_P(TlsConnectTls13, UnsupportedSignatureSchemeAlert) {
+ EnsureTlsSetup();
+ MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, ssl_sig_none);
+
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
+}
+
+TEST_P(TlsConnectTls13, InconsistentSignatureSchemeAlert) {
+ EnsureTlsSetup();
+
+ // This won't work because we use an RSA cert by default.
+ MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(
+ server_, ssl_sig_ecdsa_secp256r1_sha256);
+
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+}
+
TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) {
server_->SetSignatureSchemes(SignatureSchemeRsaSha384,
PR_ARRAY_SIZE(SignatureSchemeRsaSha384));
diff --git a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
index fa2238be7d..ec289bdd69 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -166,8 +166,8 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
case ssl_calg_seed:
break;
}
- EXPECT_TRUE(false) << "No limit for " << csinfo_.cipherSuiteName;
- return 1ULL < 48;
+ ADD_FAILURE() << "No limit for " << csinfo_.cipherSuiteName;
+ return 0;
}
uint64_t last_safe_write() const {
@@ -246,12 +246,13 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) {
client_->SendData(10, 10);
server_->ReadBytes(); // This should be OK.
+ server_->ReadBytes(); // Read twice to flush any 1,N-1 record splitting.
} else {
// In TLS 1.3, reading or writing triggers a KeyUpdate. That would mean
// that the sequence numbers would reset and we wouldn't hit the limit. So
- // we move the sequence number to one less than the limit directly and don't
- // test sending and receiving just before the limit.
- uint64_t last = record_limit() - 1;
+ // move the sequence number to the limit directly and don't test sending and
+ // receiving just before the limit.
+ uint64_t last = record_limit();
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), last));
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
index c2f582a93a..5be62e5065 100644
--- a/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
@@ -68,6 +68,7 @@ static const uint16_t kManyExtensions[] = {
ssl_next_proto_nego_xtn,
ssl_renegotiation_info_xtn,
ssl_tls13_short_header_xtn,
+ ssl_record_size_limit_xtn,
1,
0xffff};
// The list here includes all extensions we expect to use (SSL_MAX_EXTENSIONS),
diff --git a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
index cdafa7a84f..b99461632c 100644
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -103,8 +103,8 @@ TEST_P(TlsConnectGenericPre13, ConnectFfdheServer) {
class TlsDheServerKeyExchangeDamager : public TlsHandshakeFilter {
public:
- TlsDheServerKeyExchangeDamager(const std::shared_ptr<TlsAgent>& agent)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerKeyExchange}) {}
+ TlsDheServerKeyExchangeDamager(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {}
virtual PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
const DataBuffer& input, DataBuffer* output) {
@@ -141,9 +141,9 @@ class TlsDheSkeChangeY : public TlsHandshakeFilter {
kYZeroPad
};
- TlsDheSkeChangeY(const std::shared_ptr<TlsAgent>& agent,
- uint8_t handshake_type, ChangeYTo change)
- : TlsHandshakeFilter(agent, {handshake_type}), change_Y_(change) {}
+ TlsDheSkeChangeY(const std::shared_ptr<TlsAgent>& a, uint8_t handshake_type,
+ ChangeYTo change)
+ : TlsHandshakeFilter(a, {handshake_type}), change_Y_(change) {}
protected:
void ChangeY(const DataBuffer& input, DataBuffer* output, size_t offset,
@@ -208,9 +208,9 @@ class TlsDheSkeChangeY : public TlsHandshakeFilter {
class TlsDheSkeChangeYServer : public TlsDheSkeChangeY {
public:
- TlsDheSkeChangeYServer(const std::shared_ptr<TlsAgent>& agent,
- ChangeYTo change, bool modify)
- : TlsDheSkeChangeY(agent, kTlsHandshakeServerKeyExchange, change),
+ TlsDheSkeChangeYServer(const std::shared_ptr<TlsAgent>& a, ChangeYTo change,
+ bool modify)
+ : TlsDheSkeChangeY(a, kTlsHandshakeServerKeyExchange, change),
modify_(modify),
p_() {}
@@ -247,9 +247,9 @@ class TlsDheSkeChangeYServer : public TlsDheSkeChangeY {
class TlsDheSkeChangeYClient : public TlsDheSkeChangeY {
public:
TlsDheSkeChangeYClient(
- const std::shared_ptr<TlsAgent>& agent, ChangeYTo change,
+ const std::shared_ptr<TlsAgent>& a, ChangeYTo change,
std::shared_ptr<const TlsDheSkeChangeYServer> server_filter)
- : TlsDheSkeChangeY(agent, kTlsHandshakeClientKeyExchange, change),
+ : TlsDheSkeChangeY(a, kTlsHandshakeClientKeyExchange, change),
server_filter_(server_filter) {}
protected:
@@ -357,8 +357,8 @@ INSTANTIATE_TEST_CASE_P(
class TlsDheSkeMakePEven : public TlsHandshakeFilter {
public:
- TlsDheSkeMakePEven(const std::shared_ptr<TlsAgent>& agent)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerKeyExchange}) {}
+ TlsDheSkeMakePEven(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {}
virtual PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
@@ -390,8 +390,8 @@ TEST_P(TlsConnectGenericPre13, MakeDhePEven) {
class TlsDheSkeZeroPadP : public TlsHandshakeFilter {
public:
- TlsDheSkeZeroPadP(const std::shared_ptr<TlsAgent>& agent)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerKeyExchange}) {}
+ TlsDheSkeZeroPadP(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}) {}
virtual PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
@@ -475,6 +475,45 @@ TEST_P(TlsConnectTls13, NamedGroupMismatch13) {
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
+// Replace the key share in the server key exchange message with one that's
+// larger than 8192 bits.
+class TooLongDHEServerKEXFilter : public TlsHandshakeFilter {
+ public:
+ TooLongDHEServerKEXFilter(const std::shared_ptr<TlsAgent>& server)
+ : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ // Replace the server key exchange message very large DH shares that are
+ // not supported by NSS.
+ const uint32_t share_len = 0x401;
+ const uint8_t zero_share[share_len] = {0x80};
+ size_t offset = 0;
+ // Write dh_p.
+ offset = output->Write(offset, share_len, 2);
+ offset = output->Write(offset, zero_share, share_len);
+ // Write dh_g.
+ offset = output->Write(offset, share_len, 2);
+ offset = output->Write(offset, zero_share, share_len);
+ // Write dh_Y.
+ offset = output->Write(offset, share_len, 2);
+ offset = output->Write(offset, zero_share, share_len);
+
+ return CHANGE;
+ }
+};
+
+TEST_P(TlsConnectGenericPre13, TooBigDHGroup) {
+ EnableOnlyDheCiphers();
+ MakeTlsFilter<TooLongDHEServerKEXFilter>(server_);
+ client_->SetOption(SSL_REQUIRE_DH_NAMED_GROUPS, PR_FALSE);
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ client_->CheckErrorCode(SSL_ERROR_DH_KEY_TOO_LONG);
+}
+
// Even though the client doesn't have DHE groups enabled the server assumes it
// does. The client requires named groups and thus does not accept FF3072 as
// custom group in contrast to the previous test.
@@ -546,9 +585,9 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
class TlsDheSkeChangeSignature : public TlsHandshakeFilter {
public:
- TlsDheSkeChangeSignature(const std::shared_ptr<TlsAgent>& agent,
- uint16_t version, const uint8_t* data, size_t len)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerKeyExchange}),
+ TlsDheSkeChangeSignature(const std::shared_ptr<TlsAgent>& a, uint16_t version,
+ const uint8_t* data, size_t len)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}),
version_(version),
data_(data),
len_(len) {}
diff --git a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
index ee8906deb5..e5b52ff06b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
@@ -66,7 +66,8 @@ TEST_P(TlsConnectDatagramPre13, DropServerSecondFlightThrice) {
Connect();
}
-class TlsDropDatagram13 : public TlsConnectDatagram13 {
+class TlsDropDatagram13 : public TlsConnectDatagram13,
+ public ::testing::WithParamInterface<bool> {
public:
TlsDropDatagram13()
: client_filters_(),
@@ -77,6 +78,9 @@ class TlsDropDatagram13 : public TlsConnectDatagram13 {
void SetUp() override {
TlsConnectDatagram13::SetUp();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+ int short_header = GetParam() ? PR_TRUE : PR_FALSE;
+ client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, short_header);
+ server_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, short_header);
SetFilters();
}
@@ -138,10 +142,13 @@ class TlsDropDatagram13 : public TlsConnectDatagram13 {
void CheckAcks(const DropAckChain& chain, size_t index,
std::vector<uint64_t> acks) {
const DataBuffer& buf = chain.ack_->record(index).buffer;
- size_t offset = 0;
+ size_t offset = 2;
+ uint64_t len;
- EXPECT_EQ(acks.size() * 8, buf.len());
- if ((acks.size() * 8) != buf.len()) {
+ EXPECT_EQ(2 + acks.size() * 8, buf.len());
+ ASSERT_TRUE(buf.Read(0, 2, &len));
+ ASSERT_EQ(static_cast<size_t>(len + 2), buf.len());
+ if ((2 + acks.size() * 8) != buf.len()) {
while (offset < buf.len()) {
uint64_t ack;
ASSERT_TRUE(buf.Read(offset, 8, &ack));
@@ -186,7 +193,7 @@ class TlsDropDatagram13 : public TlsConnectDatagram13 {
// to the client upon receiving the client Finished.
// Dropping complete first and second flights does not produce
// ACKs
-TEST_F(TlsDropDatagram13, DropClientFirstFlightOnce) {
+TEST_P(TlsDropDatagram13, DropClientFirstFlightOnce) {
client_filters_.drop_->Reset({0});
StartConnect();
client_->Handshake();
@@ -195,7 +202,7 @@ TEST_F(TlsDropDatagram13, DropClientFirstFlightOnce) {
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
}
-TEST_F(TlsDropDatagram13, DropServerFirstFlightOnce) {
+TEST_P(TlsDropDatagram13, DropServerFirstFlightOnce) {
server_filters_.drop_->Reset(0xff);
StartConnect();
client_->Handshake();
@@ -209,7 +216,7 @@ TEST_F(TlsDropDatagram13, DropServerFirstFlightOnce) {
// Dropping the server's first record also does not produce
// an ACK because the next record is ignored.
// TODO(ekr@rtfm.com): We should generate an empty ACK.
-TEST_F(TlsDropDatagram13, DropServerFirstRecordOnce) {
+TEST_P(TlsDropDatagram13, DropServerFirstRecordOnce) {
server_filters_.drop_->Reset({0});
StartConnect();
client_->Handshake();
@@ -221,7 +228,7 @@ TEST_F(TlsDropDatagram13, DropServerFirstRecordOnce) {
// Dropping the second packet of the server's flight should
// produce an ACK.
-TEST_F(TlsDropDatagram13, DropServerSecondRecordOnce) {
+TEST_P(TlsDropDatagram13, DropServerSecondRecordOnce) {
server_filters_.drop_->Reset({1});
StartConnect();
client_->Handshake();
@@ -235,7 +242,7 @@ TEST_F(TlsDropDatagram13, DropServerSecondRecordOnce) {
// Drop the server ACK and verify that the client retransmits
// the ClientHello.
-TEST_F(TlsDropDatagram13, DropServerAckOnce) {
+TEST_P(TlsDropDatagram13, DropServerAckOnce) {
StartConnect();
client_->Handshake();
server_->Handshake();
@@ -263,7 +270,7 @@ TEST_F(TlsDropDatagram13, DropServerAckOnce) {
}
// Drop the client certificate verify.
-TEST_F(TlsDropDatagram13, DropClientCertVerify) {
+TEST_P(TlsDropDatagram13, DropClientCertVerify) {
StartConnect();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
@@ -284,7 +291,7 @@ TEST_F(TlsDropDatagram13, DropClientCertVerify) {
}
// Shrink the MTU down so that certs get split and drop the first piece.
-TEST_F(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
+TEST_P(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
server_filters_.drop_->Reset({2});
StartConnect();
ShrinkPostServerHelloMtu();
@@ -311,7 +318,7 @@ TEST_F(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
}
// Shrink the MTU down so that certs get split and drop the second piece.
-TEST_F(TlsDropDatagram13, DropSecondHalfOfServerCertificate) {
+TEST_P(TlsDropDatagram13, DropSecondHalfOfServerCertificate) {
server_filters_.drop_->Reset({3});
StartConnect();
ShrinkPostServerHelloMtu();
@@ -524,11 +531,11 @@ class TlsFragmentationAndRecoveryTest : public TlsDropDatagram13 {
size_t cert_len_;
};
-TEST_F(TlsFragmentationAndRecoveryTest, DropFirstHalf) { RunTest(0); }
+TEST_P(TlsFragmentationAndRecoveryTest, DropFirstHalf) { RunTest(0); }
-TEST_F(TlsFragmentationAndRecoveryTest, DropSecondHalf) { RunTest(1); }
+TEST_P(TlsFragmentationAndRecoveryTest, DropSecondHalf) { RunTest(1); }
-TEST_F(TlsDropDatagram13, NoDropsDuringZeroRtt) {
+TEST_P(TlsDropDatagram13, NoDropsDuringZeroRtt) {
SetupForZeroRtt();
SetFilters();
std::cerr << "Starting second handshake" << std::endl;
@@ -546,7 +553,7 @@ TEST_F(TlsDropDatagram13, NoDropsDuringZeroRtt) {
0x0002000000000000ULL}); // Finished
}
-TEST_F(TlsDropDatagram13, DropEEDuringZeroRtt) {
+TEST_P(TlsDropDatagram13, DropEEDuringZeroRtt) {
SetupForZeroRtt();
SetFilters();
std::cerr << "Starting second handshake" << std::endl;
@@ -591,7 +598,7 @@ class TlsReorderDatagram13 : public TlsDropDatagram13 {
// Reorder the server records so that EE comes at the end
// of the flight and will still produce an ACK.
-TEST_F(TlsDropDatagram13, ReorderServerEE) {
+TEST_P(TlsDropDatagram13, ReorderServerEE) {
server_filters_.drop_->Reset({1});
StartConnect();
client_->Handshake();
@@ -647,7 +654,7 @@ class TlsSendCipherSpecCapturer {
std::vector<std::shared_ptr<TlsCipherSpec>> send_cipher_specs_;
};
-TEST_F(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
+TEST_P(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
StartConnect();
TlsSendCipherSpecCapturer capturer(client_);
client_->Handshake();
@@ -662,9 +669,9 @@ TEST_F(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
auto spec = capturer.spec(0);
ASSERT_NE(nullptr, spec.get());
ASSERT_EQ(2, spec->epoch());
- ASSERT_TRUE(client_->SendEncryptedRecord(
- spec, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, 0x0002000000000002,
- kTlsApplicationDataType, DataBuffer(buf, sizeof(buf))));
+ ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002,
+ kTlsApplicationDataType,
+ DataBuffer(buf, sizeof(buf))));
// Now have the server consume the bogus message.
server_->ExpectSendAlert(illegal_parameter, kTlsAlertFatal);
@@ -673,7 +680,7 @@ TEST_F(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
EXPECT_EQ(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, PORT_GetError());
}
-TEST_F(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
+TEST_P(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
StartConnect();
TlsSendCipherSpecCapturer capturer(client_);
client_->Handshake();
@@ -688,9 +695,9 @@ TEST_F(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
auto spec = capturer.spec(0);
ASSERT_NE(nullptr, spec.get());
ASSERT_EQ(2, spec->epoch());
- ASSERT_TRUE(client_->SendEncryptedRecord(
- spec, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, 0x0002000000000002,
- kTlsHandshakeType, DataBuffer(buf, sizeof(buf))));
+ ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002,
+ kTlsHandshakeType,
+ DataBuffer(buf, sizeof(buf))));
server_->Handshake();
EXPECT_EQ(2UL, server_filters_.ack_->count());
// The server acknowledges client Finished twice.
@@ -700,7 +707,7 @@ TEST_F(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
// Shrink the MTU down so that certs get split and then swap the first and
// second pieces of the server certificate.
-TEST_F(TlsReorderDatagram13, ReorderServerCertificate) {
+TEST_P(TlsReorderDatagram13, ReorderServerCertificate) {
StartConnect();
ShrinkPostServerHelloMtu();
client_->Handshake();
@@ -722,7 +729,7 @@ TEST_F(TlsReorderDatagram13, ReorderServerCertificate) {
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
}
-TEST_F(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
+TEST_P(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
SetupForZeroRtt();
SetFilters();
std::cerr << "Starting second handshake" << std::endl;
@@ -761,7 +768,7 @@ TEST_F(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}
-TEST_F(TlsReorderDatagram13, DataAfterFinDuringZeroRtt) {
+TEST_P(TlsReorderDatagram13, DataAfterFinDuringZeroRtt) {
SetupForZeroRtt();
SetFilters();
std::cerr << "Starting second handshake" << std::endl;
@@ -812,12 +819,17 @@ static void GetCipherAndLimit(uint16_t version, uint16_t* cipher,
*cipher = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
*limit = (1ULL << 48) - 1;
} else {
+ // This test probably isn't especially useful for TLS 1.3, which has a much
+ // shorter sequence number encoding. That space can probably be searched in
+ // a reasonable amount of time.
*cipher = TLS_CHACHA20_POLY1305_SHA256;
- *limit = (1ULL << 48) - 1;
+ // Assume that we are starting with an expected sequence number of 0.
+ *limit = (1ULL << 29) - 1;
}
}
// This simulates a huge number of drops on one side.
+// See Bug 12965514 where a large gap was handled very inefficiently.
TEST_P(TlsConnectDatagram, MissLotsOfPackets) {
uint16_t cipher;
uint64_t limit;
@@ -834,6 +846,17 @@ TEST_P(TlsConnectDatagram, MissLotsOfPackets) {
SendReceive();
}
+// Send a sequence number of 0xfffffffd 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));
+ SendReceive();
+}
+
class TlsConnectDatagram12Plus : public TlsConnectDatagram {
public:
TlsConnectDatagram12Plus() : TlsConnectDatagram() {}
@@ -861,9 +884,54 @@ TEST_P(TlsConnectDatagram12Plus, MissAWindowAndOne) {
SendReceive();
}
+// This filter replaces the first record it sees with junk application data.
+class TlsReplaceFirstRecordWithJunk : public TlsRecordFilter {
+ public:
+ TlsReplaceFirstRecordWithJunk(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a), replaced_(false) {}
+
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& record, size_t* offset,
+ DataBuffer* output) override {
+ if (replaced_) {
+ return KEEP;
+ }
+ replaced_ = true;
+ TlsRecordHeader out_header(header.variant(), header.version(),
+ kTlsApplicationDataType,
+ header.sequence_number());
+
+ static const uint8_t junk[] = {1, 2, 3, 4};
+ *offset = out_header.Write(output, *offset, DataBuffer(junk, sizeof(junk)));
+ return CHANGE;
+ }
+
+ private:
+ bool replaced_;
+};
+
+// DTLS needs to discard application_data that it receives prior to handshake
+// completion, not generate an error.
+TEST_P(TlsConnectDatagram, ReplaceFirstServerRecordWithApplicationData) {
+ MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(server_);
+ Connect();
+}
+
+TEST_P(TlsConnectDatagram, ReplaceFirstClientRecordWithApplicationData) {
+ MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(client_);
+ Connect();
+}
+
INSTANTIATE_TEST_CASE_P(Datagram12Plus, TlsConnectDatagram12Plus,
TlsConnectTestBase::kTlsV12Plus);
INSTANTIATE_TEST_CASE_P(DatagramPre13, TlsConnectDatagramPre13,
TlsConnectTestBase::kTlsV11V12);
+INSTANTIATE_TEST_CASE_P(DatagramDrop13, TlsDropDatagram13,
+ ::testing::Values(true, false));
+INSTANTIATE_TEST_CASE_P(DatagramReorder13, TlsReorderDatagram13,
+ ::testing::Values(true, false));
+INSTANTIATE_TEST_CASE_P(DatagramFragment13, TlsFragmentationAndRecoveryTest,
+ ::testing::Values(true, false));
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
index 3c7cd2ecfa..12c6e8516c 100644
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -192,8 +192,8 @@ TEST_P(TlsConnectGenericPre13, P384PriorityFromModelSocket) {
class TlsKeyExchangeGroupCapture : public TlsHandshakeFilter {
public:
- TlsKeyExchangeGroupCapture(const std::shared_ptr<TlsAgent> &agent)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerKeyExchange}),
+ TlsKeyExchangeGroupCapture(const std::shared_ptr<TlsAgent> &a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}),
group_(ssl_grp_none) {}
SSLNamedGroup group() const { return group_; }
@@ -559,6 +559,113 @@ TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
}
+// Damage ECParams/ECPoint of a SKE.
+class ECCServerKEXDamager : public TlsHandshakeFilter {
+ public:
+ ECCServerKEXDamager(const std::shared_ptr<TlsAgent> &server, ECType ec_type,
+ SSLNamedGroup named_curve)
+ : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
+ ec_type_(ec_type),
+ named_curve_(named_curve) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
+ const DataBuffer &input,
+ DataBuffer *output) {
+ size_t offset = 0;
+ output->Allocate(5);
+ offset = output->Write(offset, ec_type_, 1);
+ offset = output->Write(offset, named_curve_, 2);
+ // Write a point with fmt != EC_POINT_FORM_UNCOMPRESSED.
+ offset = output->Write(offset, 1U, 1);
+ (void)output->Write(offset, 0x02, 1); // EC_POINT_FORM_COMPRESSED_Y0
+ return CHANGE;
+ }
+
+ private:
+ ECType ec_type_;
+ SSLNamedGroup named_curve_;
+};
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurveType) {
+ EnsureTlsSetup();
+ client_->DisableAllCiphers();
+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+ MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_explicitPrime,
+ ssl_grp_none);
+ ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+ client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+}
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurve) {
+ EnsureTlsSetup();
+ client_->DisableAllCiphers();
+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+ MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
+ ssl_grp_ffdhe_2048);
+ ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+ client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+}
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedPointFormat) {
+ EnsureTlsSetup();
+ client_->DisableAllCiphers();
+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+ MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
+ ssl_grp_ec_secp256r1);
+ ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+ client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+}
+
+// Replace SignatureAndHashAlgorithm of a SKE.
+class ECCServerKEXSigAlgReplacer : public TlsHandshakeFilter {
+ public:
+ ECCServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent> &server,
+ SSLSignatureScheme sig_scheme)
+ : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
+ sig_scheme_(sig_scheme) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
+ const DataBuffer &input,
+ DataBuffer *output) {
+ *output = input;
+
+ uint32_t point_len;
+ EXPECT_TRUE(output->Read(3, 1, &point_len));
+ output->Write(4 + point_len, sig_scheme_, 2);
+
+ return CHANGE;
+ }
+
+ private:
+ SSLSignatureScheme sig_scheme_;
+};
+
+TEST_P(TlsConnectTls12, ConnectUnsupportedSigAlg) {
+ EnsureTlsSetup();
+ client_->DisableAllCiphers();
+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+ MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_, ssl_sig_none);
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+}
+
+TEST_P(TlsConnectTls12, ConnectIncorrectSigAlg) {
+ EnsureTlsSetup();
+ client_->DisableAllCiphers();
+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+ MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_,
+ ssl_sig_ecdsa_secp256r1_sha256);
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+}
+
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV11Plus));
diff --git a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
index 0453dabdb6..6965e9ca75 100644
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -19,9 +19,9 @@ namespace nss_test {
class TlsExtensionTruncator : public TlsExtensionFilter {
public:
- TlsExtensionTruncator(const std::shared_ptr<TlsAgent>& agent,
- uint16_t extension, size_t length)
- : TlsExtensionFilter(agent), extension_(extension), length_(length) {}
+ TlsExtensionTruncator(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
+ size_t length)
+ : TlsExtensionFilter(a), extension_(extension), length_(length) {}
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
DataBuffer* output) {
@@ -43,9 +43,9 @@ class TlsExtensionTruncator : public TlsExtensionFilter {
class TlsExtensionDamager : public TlsExtensionFilter {
public:
- TlsExtensionDamager(const std::shared_ptr<TlsAgent>& agent,
- uint16_t extension, size_t index)
- : TlsExtensionFilter(agent), extension_(extension), index_(index) {}
+ TlsExtensionDamager(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
+ size_t index)
+ : TlsExtensionFilter(a), extension_(extension), index_(index) {}
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
DataBuffer* output) {
@@ -65,11 +65,9 @@ class TlsExtensionDamager : public TlsExtensionFilter {
class TlsExtensionAppender : public TlsHandshakeFilter {
public:
- TlsExtensionAppender(const std::shared_ptr<TlsAgent>& agent,
+ TlsExtensionAppender(const std::shared_ptr<TlsAgent>& a,
uint8_t handshake_type, uint16_t ext, DataBuffer& data)
- : TlsHandshakeFilter(agent, {handshake_type}),
- extension_(ext),
- data_(data) {}
+ : TlsHandshakeFilter(a, {handshake_type}), extension_(ext), data_(data) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
@@ -323,7 +321,15 @@ TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
EnableAlpn();
- const uint8_t val[] = {0x01, 0x61, 0x00};
+ const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x00};
+ DataBuffer extension(val, sizeof(val));
+ ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+ client_, ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnLengthOverflow) {
+ EnableAlpn();
+ const uint8_t val[] = {0x00, 0x03, 0x01, 0x61, 0x01};
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
client_, ssl_app_layer_protocol_xtn, extension));
@@ -628,12 +634,9 @@ typedef std::function<void(TlsPreSharedKeyReplacer*)>
class TlsPreSharedKeyReplacer : public TlsExtensionFilter {
public:
- TlsPreSharedKeyReplacer(const std::shared_ptr<TlsAgent>& agent,
+ TlsPreSharedKeyReplacer(const std::shared_ptr<TlsAgent>& a,
TlsPreSharedKeyReplacerFunc function)
- : TlsExtensionFilter(agent),
- identities_(),
- binders_(),
- function_(function) {}
+ : TlsExtensionFilter(a), identities_(), binders_(), function_(function) {}
static size_t CopyAndMaybeReplace(TlsParser* parser, size_t size,
const std::unique_ptr<DataBuffer>& replace,
diff --git a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
index f4940bf282..92947c2c70 100644
--- a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
@@ -20,14 +20,16 @@ namespace nss_test {
// This class cuts every unencrypted handshake record into two parts.
class RecordFragmenter : public PacketFilter {
public:
- RecordFragmenter() : sequence_number_(0), splitting_(true) {}
+ RecordFragmenter(bool is_dtls13)
+ : is_dtls13_(is_dtls13), sequence_number_(0), splitting_(true) {}
private:
class HandshakeSplitter {
public:
- HandshakeSplitter(const DataBuffer& input, DataBuffer* output,
- uint64_t* sequence_number)
- : input_(input),
+ HandshakeSplitter(bool is_dtls13, const DataBuffer& input,
+ DataBuffer* output, uint64_t* sequence_number)
+ : is_dtls13_(is_dtls13),
+ input_(input),
output_(output),
cursor_(0),
sequence_number_(sequence_number) {}
@@ -35,9 +37,9 @@ class RecordFragmenter : public PacketFilter {
private:
void WriteRecord(TlsRecordHeader& record_header,
DataBuffer& record_fragment) {
- TlsRecordHeader fragment_header(record_header.version(),
- record_header.content_type(),
- *sequence_number_);
+ TlsRecordHeader fragment_header(
+ record_header.variant(), record_header.version(),
+ record_header.content_type(), *sequence_number_);
++*sequence_number_;
if (::g_ssl_gtest_verbose) {
std::cerr << "Fragment: " << fragment_header << ' ' << record_fragment
@@ -88,7 +90,7 @@ class RecordFragmenter : public PacketFilter {
while (parser.remaining()) {
TlsRecordHeader header;
DataBuffer record;
- if (!header.Parse(0, &parser, &record)) {
+ if (!header.Parse(is_dtls13_, 0, &parser, &record)) {
ADD_FAILURE() << "bad record header";
return false;
}
@@ -118,6 +120,7 @@ class RecordFragmenter : public PacketFilter {
}
private:
+ bool is_dtls13_;
const DataBuffer& input_;
DataBuffer* output_;
size_t cursor_;
@@ -132,7 +135,7 @@ class RecordFragmenter : public PacketFilter {
}
output->Allocate(input.len());
- HandshakeSplitter splitter(input, output, &sequence_number_);
+ HandshakeSplitter splitter(is_dtls13_, input, output, &sequence_number_);
if (!splitter.Split()) {
// If splitting fails, we obviously reached encrypted packets.
// Stop splitting from that point onward.
@@ -144,18 +147,21 @@ class RecordFragmenter : public PacketFilter {
}
private:
+ bool is_dtls13_;
uint64_t sequence_number_;
bool splitting_;
};
TEST_P(TlsConnectDatagram, FragmentClientPackets) {
- client_->SetFilter(std::make_shared<RecordFragmenter>());
+ bool is_dtls13 = version_ >= SSL_LIBRARY_VERSION_TLS_1_3;
+ client_->SetFilter(std::make_shared<RecordFragmenter>(is_dtls13));
Connect();
SendReceive();
}
TEST_P(TlsConnectDatagram, FragmentServerPackets) {
- server_->SetFilter(std::make_shared<RecordFragmenter>());
+ bool is_dtls13 = version_ >= SSL_LIBRARY_VERSION_TLS_1_3;
+ server_->SetFilter(std::make_shared<RecordFragmenter>(is_dtls13));
Connect();
SendReceive();
}
diff --git a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
index 99448321c5..f0afc9118a 100644
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -27,8 +27,8 @@ class TlsFuzzTest : public ::testing::Test {};
// Record the application data stream.
class TlsApplicationDataRecorder : public TlsRecordFilter {
public:
- TlsApplicationDataRecorder(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent), buffer_() {}
+ TlsApplicationDataRecorder(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a), buffer_() {}
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
diff --git a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
index e2a8d830ac..17677713d6 100644
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -37,6 +37,7 @@
'ssl_loopback_unittest.cc',
'ssl_misc_unittest.cc',
'ssl_record_unittest.cc',
+ 'ssl_recordsize_unittest.cc',
'ssl_resumption_unittest.cc',
'ssl_renegotiation_unittest.cc',
'ssl_skip_unittest.cc',
diff --git a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
index 05ae870348..77b335e86b 100644
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -69,8 +69,8 @@ TEST_P(TlsConnectTls13, HelloRetryRequestAbortsZeroRtt) {
// handshake packets, this will break.
class CorrectMessageSeqAfterHrrFilter : public TlsRecordFilter {
public:
- CorrectMessageSeqAfterHrrFilter(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent) {}
+ CorrectMessageSeqAfterHrrFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
@@ -81,8 +81,9 @@ class CorrectMessageSeqAfterHrrFilter : public TlsRecordFilter {
}
DataBuffer buffer(record);
- TlsRecordHeader new_header = {header.version(), header.content_type(),
- header.sequence_number() + 1};
+ TlsRecordHeader new_header(header.variant(), header.version(),
+ header.content_type(),
+ header.sequence_number() + 1);
// Correct message_seq.
buffer.Write(4, 1U, 2);
@@ -151,8 +152,8 @@ TEST_P(TlsConnectTls13, SecondClientHelloRejectEarlyDataXtn) {
class KeyShareReplayer : public TlsExtensionFilter {
public:
- KeyShareReplayer(const std::shared_ptr<TlsAgent>& agent)
- : TlsExtensionFilter(agent) {}
+ KeyShareReplayer(const std::shared_ptr<TlsAgent>& a)
+ : TlsExtensionFilter(a) {}
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
@@ -567,6 +568,28 @@ void TriggerHelloRetryRequest(std::shared_ptr<TlsAgent>& client,
client->Handshake();
server->Handshake();
EXPECT_EQ(1U, cb_called);
+ // Stop the callback from being called in future handshakes.
+ EXPECT_EQ(SECSuccess,
+ SSL_HelloRetryRequestCallback(server->ssl_fd(), nullptr, nullptr));
+}
+
+TEST_P(TlsConnectTls13, VersionNumbersAfterRetry) {
+ ConfigureSelfEncrypt();
+ EnsureTlsSetup();
+ auto r = MakeTlsFilter<TlsRecordRecorder>(client_);
+ TriggerHelloRetryRequest(client_, server_);
+ Handshake();
+ ASSERT_GT(r->count(), 1UL);
+ auto ch1 = r->record(0);
+ if (ch1.header.is_dtls()) {
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, ch1.header.version());
+ } else {
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, ch1.header.version());
+ }
+ auto ch2 = r->record(1);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, ch2.header.version());
+
+ CheckConnected();
}
TEST_P(TlsConnectTls13, RetryStateless) {
@@ -577,6 +600,7 @@ TEST_P(TlsConnectTls13, RetryStateless) {
MakeNewServer();
Handshake();
+ CheckConnected();
SendReceive();
}
@@ -593,6 +617,68 @@ TEST_P(TlsConnectTls13, RetryStatefulDropCookie) {
server_->CheckErrorCode(SSL_ERROR_MISSING_COOKIE_EXTENSION);
}
+class TruncateHrrCookie : public TlsExtensionFilter {
+ public:
+ TruncateHrrCookie(const std::shared_ptr<TlsAgent>& a)
+ : TlsExtensionFilter(a) {}
+ virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ if (extension_type != ssl_tls13_cookie_xtn) {
+ return KEEP;
+ }
+
+ // Claim a zero-length cookie.
+ output->Allocate(2);
+ output->Write(0, static_cast<uint32_t>(0), 2);
+ return CHANGE;
+ }
+};
+
+TEST_P(TlsConnectTls13, RetryCookieEmpty) {
+ ConfigureSelfEncrypt();
+ EnsureTlsSetup();
+
+ TriggerHelloRetryRequest(client_, server_);
+ MakeTlsFilter<TruncateHrrCookie>(client_);
+
+ ExpectAlert(server_, kTlsAlertHandshakeFailure);
+ Handshake();
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
+class AddJunkToCookie : public TlsExtensionFilter {
+ public:
+ AddJunkToCookie(const std::shared_ptr<TlsAgent>& a) : TlsExtensionFilter(a) {}
+ virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ if (extension_type != ssl_tls13_cookie_xtn) {
+ return KEEP;
+ }
+
+ *output = input;
+ // Add junk after the cookie.
+ static const uint8_t junk[2] = {1, 2};
+ output->Append(DataBuffer(junk, sizeof(junk)));
+ return CHANGE;
+ }
+};
+
+TEST_P(TlsConnectTls13, RetryCookieWithExtras) {
+ ConfigureSelfEncrypt();
+ EnsureTlsSetup();
+
+ TriggerHelloRetryRequest(client_, server_);
+ MakeTlsFilter<AddJunkToCookie>(client_);
+
+ ExpectAlert(server_, kTlsAlertHandshakeFailure);
+ Handshake();
+ client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+ server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+}
+
// Stream only because DTLS drops bad packets.
TEST_F(TlsConnectStreamTls13, RetryStatelessDamageFirstClientHello) {
ConfigureSelfEncrypt();
@@ -907,7 +993,10 @@ class HelloRetryRequestAgentTest : public TlsAgentTestClient {
hrr_data.Allocate(len + 6);
size_t i = 0;
- i = hrr_data.Write(i, 0x0303, 2);
+ i = hrr_data.Write(i, variant_ == ssl_variant_datagram
+ ? SSL_LIBRARY_VERSION_DTLS_1_2_WIRE
+ : SSL_LIBRARY_VERSION_TLS_1_2,
+ 2);
i = hrr_data.Write(i, ssl_hello_retry_random,
sizeof(ssl_hello_retry_random));
i = hrr_data.Write(i, static_cast<uint32_t>(0), 1); // session_id
@@ -973,6 +1062,39 @@ TEST_P(HelloRetryRequestAgentTest, HandleNoopHelloRetryRequest) {
SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
}
+class ReplaceRandom : public TlsHandshakeFilter {
+ public:
+ ReplaceRandom(const std::shared_ptr<TlsAgent>& a, const DataBuffer& r)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerHello}), random_(r) {}
+
+ PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) override {
+ output->Assign(input);
+ output->Write(2, random_);
+ return CHANGE;
+ }
+
+ private:
+ DataBuffer random_;
+};
+
+// Make sure that the TLS 1.3 special value for the ServerHello.random
+// is rejected by earlier versions.
+TEST_P(TlsConnectStreamPre13, HrrRandomOnTls10) {
+ static const uint8_t hrr_random[] = {
+ 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C,
+ 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB,
+ 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
+
+ EnsureTlsSetup();
+ MakeTlsFilter<ReplaceRandom>(server_,
+ DataBuffer(hrr_random, sizeof(hrr_random)));
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
INSTANTIATE_TEST_CASE_P(HelloRetryRequestAgentTests, HelloRetryRequestAgentTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13));
diff --git a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
index f1b78f52fd..5adbd9dc71 100644
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -56,8 +56,8 @@ TEST_P(TlsConnectGeneric, CipherSuiteMismatch) {
class TlsAlertRecorder : public TlsRecordFilter {
public:
- TlsAlertRecorder(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent), level_(255), description_(255) {}
+ TlsAlertRecorder(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a), level_(255), description_(255) {}
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
@@ -87,9 +87,9 @@ class TlsAlertRecorder : public TlsRecordFilter {
class HelloTruncator : public TlsHandshakeFilter {
public:
- HelloTruncator(const std::shared_ptr<TlsAgent>& agent)
+ HelloTruncator(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(
- agent, {kTlsHandshakeClientHello, kTlsHandshakeServerHello}) {}
+ a, {kTlsHandshakeClientHello, kTlsHandshakeServerHello}) {}
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) override {
@@ -149,6 +149,27 @@ TEST_P(TlsConnectGeneric, ConnectAlpn) {
CheckAlpn("a");
}
+TEST_P(TlsConnectGeneric, ConnectAlpnPriorityA) {
+ // "alpn" "npn"
+ // alpn is the fallback here. npn has the highest priority and should be
+ // picked.
+ const std::vector<uint8_t> alpn = {0x04, 0x61, 0x6c, 0x70, 0x6e,
+ 0x03, 0x6e, 0x70, 0x6e};
+ EnableAlpn(alpn);
+ Connect();
+ CheckAlpn("npn");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnPriorityB) {
+ // "alpn" "npn" "http"
+ // npn has the highest priority and should be picked.
+ const std::vector<uint8_t> alpn = {0x04, 0x61, 0x6c, 0x70, 0x6e, 0x03, 0x6e,
+ 0x70, 0x6e, 0x04, 0x68, 0x74, 0x74, 0x70};
+ EnableAlpn(alpn);
+ Connect();
+ CheckAlpn("npn");
+}
+
TEST_P(TlsConnectGeneric, ConnectAlpnClone) {
EnsureModelSockets();
client_model_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
@@ -157,6 +178,33 @@ TEST_P(TlsConnectGeneric, ConnectAlpnClone) {
CheckAlpn("a");
}
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackA) {
+ // "ab" "alpn"
+ const std::vector<uint8_t> client_alpn = {0x02, 0x61, 0x62, 0x04,
+ 0x61, 0x6c, 0x70, 0x6e};
+ EnableAlpnWithCallback(client_alpn, "alpn");
+ Connect();
+ CheckAlpn("alpn");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackB) {
+ // "ab" "alpn"
+ const std::vector<uint8_t> client_alpn = {0x02, 0x61, 0x62, 0x04,
+ 0x61, 0x6c, 0x70, 0x6e};
+ EnableAlpnWithCallback(client_alpn, "ab");
+ Connect();
+ CheckAlpn("ab");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackC) {
+ // "cd" "npn" "alpn"
+ const std::vector<uint8_t> client_alpn = {0x02, 0x63, 0x64, 0x03, 0x6e, 0x70,
+ 0x6e, 0x04, 0x61, 0x6c, 0x70, 0x6e};
+ EnableAlpnWithCallback(client_alpn, "npn");
+ Connect();
+ CheckAlpn("npn");
+}
+
TEST_P(TlsConnectDatagram, ConnectSrtp) {
EnableSrtp();
Connect();
@@ -171,8 +219,8 @@ TEST_P(TlsConnectGeneric, ConnectSendReceive) {
class SaveTlsRecord : public TlsRecordFilter {
public:
- SaveTlsRecord(const std::shared_ptr<TlsAgent>& agent, size_t index)
- : TlsRecordFilter(agent), index_(index), count_(0), contents_() {}
+ SaveTlsRecord(const std::shared_ptr<TlsAgent>& a, size_t index)
+ : TlsRecordFilter(a), index_(index), count_(0), contents_() {}
const DataBuffer& contents() const { return contents_; }
@@ -227,8 +275,8 @@ TEST_F(TlsConnectStreamTls13, DecryptRecordServer) {
class DropTlsRecord : public TlsRecordFilter {
public:
- DropTlsRecord(const std::shared_ptr<TlsAgent>& agent, size_t index)
- : TlsRecordFilter(agent), index_(index), count_(0) {}
+ DropTlsRecord(const std::shared_ptr<TlsAgent>& a, size_t index)
+ : TlsRecordFilter(a), index_(index), count_(0) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
@@ -373,8 +421,8 @@ TEST_P(TlsHolddownTest, TestDtlsHolddownExpiryResumption) {
class TlsPreCCSHeaderInjector : public TlsRecordFilter {
public:
- TlsPreCCSHeaderInjector(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent) {}
+ TlsPreCCSHeaderInjector(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a) {}
virtual PacketFilter::Action FilterRecord(
const TlsRecordHeader& record_header, const DataBuffer& input,
size_t* offset, DataBuffer* output) override {
@@ -383,7 +431,8 @@ class TlsPreCCSHeaderInjector : public TlsRecordFilter {
std::cerr << "Injecting Finished header before CCS\n";
const uint8_t hhdr[] = {kTlsHandshakeFinished, 0x00, 0x00, 0x0c};
DataBuffer hhdr_buf(hhdr, sizeof(hhdr));
- TlsRecordHeader nhdr(record_header.version(), kTlsHandshakeType, 0);
+ TlsRecordHeader nhdr(record_header.variant(), record_header.version(),
+ kTlsHandshakeType, 0);
*offset = nhdr.Write(output, *offset, hhdr_buf);
*offset = record_header.Write(output, *offset, input);
return CHANGE;
diff --git a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
index 3b87278501..53b11c61a5 100644
--- a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
@@ -103,16 +103,14 @@ TEST_P(TlsPaddingTest, LastByteOfPadWrong) {
class RecordReplacer : public TlsRecordFilter {
public:
- RecordReplacer(const std::shared_ptr<TlsAgent>& agent, size_t size)
- : TlsRecordFilter(agent), enabled_(false), size_(size) {}
+ RecordReplacer(const std::shared_ptr<TlsAgent>& a, size_t size)
+ : TlsRecordFilter(a), size_(size) {
+ Disable();
+ }
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& data,
DataBuffer* changed) override {
- if (!enabled_) {
- return KEEP;
- }
-
EXPECT_EQ(kTlsApplicationDataType, header.content_type());
changed->Allocate(size_);
@@ -120,17 +118,33 @@ class RecordReplacer : public TlsRecordFilter {
changed->data()[i] = i & 0xff;
}
- enabled_ = false;
+ Disable();
return CHANGE;
}
- void Enable() { enabled_ = true; }
-
private:
- bool enabled_;
size_t size_;
};
+TEST_P(TlsConnectStream, BadRecordMac) {
+ EnsureTlsSetup();
+ Connect();
+ client_->SetFilter(std::make_shared<TlsRecordLastByteDamager>(client_));
+ ExpectAlert(server_, kTlsAlertBadRecordMac);
+ client_->SendData(10);
+
+ // Read from the client, get error.
+ uint8_t buf[10];
+ PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+ EXPECT_GT(0, rv);
+ EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, PORT_GetError());
+
+ // Read the server alert.
+ rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
+ EXPECT_GT(0, rv);
+ EXPECT_EQ(SSL_ERROR_BAD_MAC_ALERT, PORT_GetError());
+}
+
TEST_F(TlsConnectStreamTls13, LargeRecord) {
EnsureTlsSetup();
@@ -168,6 +182,29 @@ TEST_F(TlsConnectStreamTls13, TooLargeRecord) {
EXPECT_EQ(SSL_ERROR_RECORD_OVERFLOW_ALERT, PORT_GetError());
}
+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);
+ return KEEP;
+ }
+};
+
+TEST_F(TlsConnectDatagram13, ShortHeadersClient) {
+ Connect();
+ client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_TRUE);
+ client_->SetFilter(std::make_shared<ShortHeaderChecker>());
+ SendReceive();
+}
+
+TEST_F(TlsConnectDatagram13, ShortHeadersServer) {
+ Connect();
+ server_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_TRUE);
+ server_->SetFilter(std::make_shared<ShortHeaderChecker>());
+ SendReceive();
+}
+
const static size_t kContentSizesArr[] = {
1, kMacSize - 1, kMacSize, 30, 31, 32, 36, 256, 257, 287, 288};
diff --git a/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
new file mode 100644
index 0000000000..00651aec5f
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
@@ -0,0 +1,431 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+// This class 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.
+class TlsRecordMaximum : public TlsRecordFilter {
+ public:
+ TlsRecordMaximum(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a), max_ciphertext_(0), max_plaintext_(0) {}
+
+ size_t max_ciphertext() const { return max_ciphertext_; }
+ size_t max_plaintext() const { return max_plaintext_; }
+
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& record, size_t* offset,
+ DataBuffer* output) override {
+ std::cerr << "max: " << record << std::endl;
+ // Ignore unprotected packets.
+ if (header.content_type() != kTlsApplicationDataType) {
+ return KEEP;
+ }
+
+ max_ciphertext_ = (std::max)(max_ciphertext_, record.len());
+ return TlsRecordFilter::FilterRecord(header, record, offset, output);
+ }
+
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& data,
+ DataBuffer* changed) override {
+ max_plaintext_ = (std::max)(max_plaintext_, data.len());
+ return KEEP;
+ }
+
+ private:
+ size_t max_ciphertext_;
+ size_t max_plaintext_;
+};
+
+void CheckRecordSizes(const std::shared_ptr<TlsAgent>& agent,
+ const std::shared_ptr<TlsRecordMaximum>& record_max,
+ size_t config) {
+ uint16_t cipher_suite;
+ ASSERT_TRUE(agent->cipher_suite(&cipher_suite));
+
+ size_t expansion;
+ size_t iv;
+ switch (cipher_suite) {
+ case TLS_AES_128_GCM_SHA256:
+ case TLS_AES_256_GCM_SHA384:
+ case TLS_CHACHA20_POLY1305_SHA256:
+ expansion = 16;
+ iv = 0;
+ break;
+
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ expansion = 16;
+ iv = 8;
+ break;
+
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ // Expansion is 20 for the MAC. Maximum block padding is 16. Maximum
+ // padding is added when the input plus the MAC is an exact multiple of
+ // the block size.
+ expansion = 20 + 16 - ((config + 20) % 16);
+ iv = 16;
+ break;
+
+ default:
+ ADD_FAILURE() << "No expansion set for ciphersuite "
+ << agent->cipher_suite_name();
+ return;
+ }
+
+ switch (agent->version()) {
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ EXPECT_EQ(0U, iv) << "No IV for TLS 1.3";
+ // We only have decryption in TLS 1.3.
+ EXPECT_EQ(config - 1, record_max->max_plaintext())
+ << "bad plaintext length for " << agent->role_str();
+ break;
+
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ expansion += iv;
+ break;
+
+ case SSL_LIBRARY_VERSION_TLS_1_0:
+ break;
+
+ default:
+ ADD_FAILURE() << "Unexpected version " << agent->version();
+ return;
+ }
+
+ EXPECT_EQ(config + expansion, record_max->max_ciphertext())
+ << "bad ciphertext length for " << agent->role_str();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMaximum) {
+ uint16_t max_record_size =
+ (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) ? 16385 : 16384;
+ size_t send_size = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? max_record_size
+ : max_record_size + 1;
+
+ EnsureTlsSetup();
+ auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+ client_max->EnableDecryption();
+ auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+ server_max->EnableDecryption();
+
+ Connect();
+ client_->SendData(send_size, send_size);
+ server_->SendData(send_size, send_size);
+ server_->ReadBytes(send_size);
+ client_->ReadBytes(send_size);
+
+ CheckRecordSizes(client_, client_max, max_record_size);
+ CheckRecordSizes(server_, server_max, max_record_size);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMinimumClient) {
+ EnsureTlsSetup();
+ auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+ server_max->EnableDecryption();
+
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ Connect();
+ SendReceive(127); // Big enough for one record, allowing for 1+N splitting.
+
+ CheckRecordSizes(server_, server_max, 64);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMinimumServer) {
+ EnsureTlsSetup();
+ auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+ client_max->EnableDecryption();
+
+ server_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ Connect();
+ SendReceive(127);
+
+ CheckRecordSizes(client_, client_max, 64);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeAsymmetric) {
+ EnsureTlsSetup();
+ auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+ client_max->EnableDecryption();
+ auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+ server_max->EnableDecryption();
+
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ server_->SetOption(SSL_RECORD_SIZE_LIMIT, 100);
+ Connect();
+ SendReceive(127);
+
+ CheckRecordSizes(client_, client_max, 100);
+ CheckRecordSizes(server_, server_max, 64);
+}
+
+// This just modifies the encrypted payload so to include a few extra zeros.
+class TlsRecordExpander : public TlsRecordFilter {
+ public:
+ TlsRecordExpander(const std::shared_ptr<TlsAgent>& a, size_t expansion)
+ : TlsRecordFilter(a), expansion_(expansion) {}
+
+ protected:
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& data,
+ DataBuffer* changed) {
+ if (header.content_type() != kTlsApplicationDataType) {
+ return KEEP;
+ }
+ changed->Allocate(data.len() + expansion_);
+ changed->Write(0, data.data(), data.len());
+ return CHANGE;
+ }
+
+ private:
+ size_t expansion_;
+};
+
+// Tweak the plaintext of server records so that they exceed the client's limit.
+TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
+ EnsureTlsSetup();
+ auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 1);
+ server_expand->EnableDecryption();
+
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ Connect();
+
+ server_->SendData(100);
+
+ client_->ExpectReadWriteError();
+ ExpectAlert(client_, kTlsAlertRecordOverflow);
+ client_->ReadBytes(100);
+ EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+ // Consume the alert at the server.
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+// Tweak the ciphertext of server records so that they greatly exceed the limit.
+// This requires a much larger expansion than for plaintext to trigger the
+// guard, which runs before decryption (current allowance is 304 octets).
+TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
+ EnsureTlsSetup();
+
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ Connect();
+
+ auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 320);
+ server_->SendData(100);
+
+ client_->ExpectReadWriteError();
+ ExpectAlert(client_, kTlsAlertRecordOverflow);
+ client_->ReadBytes(100);
+ EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+ // Consume the alert at the server.
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+// This indiscriminately adds padding to application data records.
+class TlsRecordPadder : public TlsRecordFilter {
+ public:
+ TlsRecordPadder(const std::shared_ptr<TlsAgent>& a, size_t padding)
+ : TlsRecordFilter(a), padding_(padding) {}
+
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& record, size_t* offset,
+ DataBuffer* output) override {
+ if (header.content_type() != kTlsApplicationDataType) {
+ return KEEP;
+ }
+
+ uint8_t inner_content_type;
+ DataBuffer plaintext;
+ if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
+ return KEEP;
+ }
+
+ if (inner_content_type != kTlsApplicationDataType) {
+ return KEEP;
+ }
+
+ DataBuffer ciphertext;
+ bool ok =
+ Protect(header, inner_content_type, plaintext, &ciphertext, padding_);
+ EXPECT_TRUE(ok);
+ if (!ok) {
+ return KEEP;
+ }
+ *offset = header.Write(output, *offset, ciphertext);
+ return CHANGE;
+ }
+
+ private:
+ size_t padding_;
+};
+
+TEST_P(TlsConnectTls13, RecordSizeExceedPad) {
+ EnsureTlsSetup();
+ auto server_max = std::make_shared<TlsRecordMaximum>(server_);
+ auto server_expand = std::make_shared<TlsRecordPadder>(server_, 1);
+ server_->SetFilter(std::make_shared<ChainedPacketFilter>(
+ ChainedPacketFilterInit({server_max, server_expand})));
+ server_expand->EnableDecryption();
+
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+ Connect();
+
+ server_->SendData(100);
+
+ client_->ExpectReadWriteError();
+ ExpectAlert(client_, kTlsAlertRecordOverflow);
+ client_->ReadBytes(100);
+ EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+ // Consume the alert at the server.
+ server_->Handshake();
+ server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeBadValues) {
+ EnsureTlsSetup();
+ EXPECT_EQ(SECFailure,
+ SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 63));
+ EXPECT_EQ(SECFailure,
+ SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, -1));
+ EXPECT_EQ(SECFailure,
+ SSL_OptionSet(server_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 16386));
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeGetValues) {
+ EnsureTlsSetup();
+ int v;
+ EXPECT_EQ(SECSuccess,
+ SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
+ EXPECT_EQ(16385, v);
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 300);
+ EXPECT_EQ(SECSuccess,
+ SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
+ EXPECT_EQ(300, v);
+ Connect();
+}
+
+// The value of the extension is capped by the maximum version of the client.
+TEST_P(TlsConnectGeneric, RecordSizeCapExtensionClient) {
+ EnsureTlsSetup();
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
+ auto capture =
+ MakeTlsFilter<TlsExtensionCapture>(client_, ssl_record_size_limit_xtn);
+ capture->EnableDecryption();
+ Connect();
+
+ uint64_t val = 0;
+ EXPECT_TRUE(capture->extension().Read(0, 2, &val));
+ if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
+ EXPECT_EQ(16384U, val) << "Extension should be capped";
+ } else {
+ EXPECT_EQ(16385U, val);
+ }
+}
+
+// The value of the extension is capped by the maximum version of the server.
+TEST_P(TlsConnectGeneric, RecordSizeCapExtensionServer) {
+ EnsureTlsSetup();
+ server_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
+ auto capture =
+ MakeTlsFilter<TlsExtensionCapture>(server_, ssl_record_size_limit_xtn);
+ capture->EnableDecryption();
+ Connect();
+
+ uint64_t val = 0;
+ EXPECT_TRUE(capture->extension().Read(0, 2, &val));
+ if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
+ EXPECT_EQ(16384U, val) << "Extension should be capped";
+ } else {
+ EXPECT_EQ(16385U, val);
+ }
+}
+
+// Damage the client extension and the handshake fails, but the server
+// doesn't generate a validation error.
+TEST_P(TlsConnectGenericPre13, RecordSizeClientExtensionInvalid) {
+ EnsureTlsSetup();
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+ static const uint8_t v[] = {0xf4, 0x1f};
+ MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
+ DataBuffer(v, sizeof(v)));
+ ConnectExpectAlert(server_, kTlsAlertDecryptError);
+}
+
+// Special handling for TLS 1.3, where the alert isn't read.
+TEST_F(TlsConnectStreamTls13, RecordSizeClientExtensionInvalid) {
+ EnsureTlsSetup();
+ client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+ static const uint8_t v[] = {0xf4, 0x1f};
+ MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
+ DataBuffer(v, sizeof(v)));
+ client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeServerExtensionInvalid) {
+ EnsureTlsSetup();
+ server_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+ static const uint8_t v[] = {0xf4, 0x1f};
+ auto replace = MakeTlsFilter<TlsExtensionReplacer>(
+ server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
+ replace->EnableDecryption();
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+class RecordSizeDefaultsTest : public ::testing::Test {
+ public:
+ void SetUp() {
+ EXPECT_EQ(SECSuccess,
+ SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &default_));
+ }
+ void TearDown() {
+ // Make sure to restore the default value at the end.
+ EXPECT_EQ(SECSuccess,
+ SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, default_));
+ }
+
+ private:
+ PRIntn default_ = 0;
+};
+
+TEST_F(RecordSizeDefaultsTest, RecordSizeBadValues) {
+ EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 63));
+ EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, -1));
+ EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 16386));
+}
+
+TEST_F(RecordSizeDefaultsTest, RecordSizeGetValue) {
+ int v;
+ EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
+ EXPECT_EQ(16385, v);
+ EXPECT_EQ(SECSuccess, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 3000));
+ EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
+ EXPECT_EQ(3000, v);
+}
+
+} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
index eb78c05851..2cc98a3278 100644
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -484,10 +484,8 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
class SelectedVersionReplacer : public TlsHandshakeFilter {
public:
- SelectedVersionReplacer(const std::shared_ptr<TlsAgent>& agent,
- uint16_t version)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerHello}),
- version_(version) {}
+ SelectedVersionReplacer(const std::shared_ptr<TlsAgent>& a, uint16_t version)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerHello}), version_(version) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
diff --git a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
index e4a9e5aed7..9ef19653bc 100644
--- a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
@@ -22,11 +22,9 @@ namespace nss_test {
class TlsHandshakeSkipFilter : public TlsRecordFilter {
public:
// A TLS record filter that skips handshake messages of the identified type.
- TlsHandshakeSkipFilter(const std::shared_ptr<TlsAgent>& agent,
+ TlsHandshakeSkipFilter(const std::shared_ptr<TlsAgent>& a,
uint8_t handshake_type)
- : TlsRecordFilter(agent),
- handshake_type_(handshake_type),
- skipped_(false) {}
+ : TlsRecordFilter(a), handshake_type_(handshake_type), skipped_(false) {}
protected:
// Takes a record; if it is a handshake record, it removes the first handshake
diff --git a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
index e5fccc12b6..ff4091b9a3 100644
--- a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -21,6 +21,7 @@ extern "C" {
#include "tls_connect.h"
#include "tls_filter.h"
#include "tls_parser.h"
+#include "rsa8193.h"
namespace nss_test {
@@ -100,4 +101,39 @@ TEST_P(TlsConnectStreamPre13,
Connect();
}
+// Replace the server certificate with one that uses 8193-bit RSA.
+class TooLargeRSACertFilter : public TlsHandshakeFilter {
+ public:
+ TooLargeRSACertFilter(const std::shared_ptr<TlsAgent> &server)
+ : TlsHandshakeFilter(server, {kTlsHandshakeCertificate}) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
+ const DataBuffer &input,
+ DataBuffer *output) {
+ const uint32_t cert_len = sizeof(rsa8193);
+ const uint32_t outer_len = cert_len + 3;
+ size_t offset = 0;
+ offset = output->Write(offset, outer_len, 3);
+ offset = output->Write(offset, cert_len, 3);
+ offset = output->Write(offset, rsa8193, cert_len);
+
+ return CHANGE;
+ }
+};
+
+TEST_P(TlsConnectGenericPre13, TooLargeRSAKeyInCert) {
+ EnableOnlyStaticRsaCiphers();
+ MakeTlsFilter<TooLargeRSACertFilter>(server_);
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ client_->CheckErrorCode(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+TEST_P(TlsConnectGeneric, ServerAuthBiggestRsa) {
+ Reset(TlsAgent::kRsa8192);
+ Connect();
+ CheckKeys();
+}
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
index f5ccf096b8..42f1065f6e 100644
--- a/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_tls13compat_unittest.cc
@@ -214,6 +214,98 @@ TEST_F(Tls13CompatTest, EnabledHrrZeroRtt) {
CheckForCompatHandshake();
}
+class TlsSessionIDEchoFilter : public TlsHandshakeFilter {
+ public:
+ TlsSessionIDEchoFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(
+ a, {kTlsHandshakeClientHello, kTlsHandshakeServerHello}) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ TlsParser parser(input);
+
+ // Skip version + random.
+ EXPECT_TRUE(parser.Skip(2 + 32));
+
+ // Capture CH.legacy_session_id.
+ if (header.handshake_type() == kTlsHandshakeClientHello) {
+ EXPECT_TRUE(parser.ReadVariable(&sid_, 1));
+ return KEEP;
+ }
+
+ // Check that server sends one too.
+ uint32_t sid_len = 0;
+ EXPECT_TRUE(parser.Read(&sid_len, 1));
+ EXPECT_EQ(sid_len, sid_.len());
+
+ // Echo the one we captured.
+ *output = input;
+ output->Write(parser.consumed(), sid_.data(), sid_.len());
+
+ return CHANGE;
+ }
+
+ private:
+ DataBuffer sid_;
+};
+
+TEST_F(TlsConnectTest, EchoTLS13CompatibilitySessionID) {
+ ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
+
+ client_->SetOption(SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE);
+
+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_3);
+
+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_LIBRARY_VERSION_TLS_1_2);
+
+ server_->SetFilter(MakeTlsFilter<TlsSessionIDEchoFilter>(client_));
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+class TlsSessionIDInjectFilter : public TlsHandshakeFilter {
+ public:
+ TlsSessionIDInjectFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerHello}) {}
+
+ protected:
+ virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ TlsParser parser(input);
+
+ // Skip version + random.
+ EXPECT_TRUE(parser.Skip(2 + 32));
+
+ *output = input;
+
+ // Inject a Session ID.
+ const uint8_t fake_sid[SSL3_SESSIONID_BYTES] = {0xff};
+ output->Write(parser.consumed(), sizeof(fake_sid), 1);
+ output->Splice(fake_sid, sizeof(fake_sid), parser.consumed() + 1, 0);
+
+ return CHANGE;
+ }
+};
+
+TEST_F(TlsConnectTest, TLS13NonCompatModeSessionID) {
+ ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+
+ MakeTlsFilter<TlsSessionIDInjectFilter>(server_);
+ client_->ExpectSendAlert(kTlsAlertIllegalParameter);
+ server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+ ConnectExpectFail();
+
+ client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
+}
+
static const uint8_t kCannedCcs[] = {
kTlsChangeCipherSpecType,
SSL_LIBRARY_VERSION_TLS_1_2 >> 8,
diff --git a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
index 7f3c4a8964..09d7801e9a 100644
--- a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
@@ -50,12 +50,12 @@ inline std::ostream& operator<<(std::ostream& stream,
class VersionRangeWithLabel {
public:
- VersionRangeWithLabel(const std::string& label, const SSLVersionRange& vr)
- : label_(label), vr_(vr) {}
- VersionRangeWithLabel(const std::string& label, uint16_t min, uint16_t max)
- : label_(label) {
- vr_.min = min;
- vr_.max = max;
+ VersionRangeWithLabel(const std::string& txt, const SSLVersionRange& vr)
+ : label_(txt), vr_(vr) {}
+ VersionRangeWithLabel(const std::string& txt, uint16_t start, uint16_t end)
+ : label_(txt) {
+ vr_.min = start;
+ vr_.max = end;
}
VersionRangeWithLabel(const std::string& label) : label_(label) {
vr_.min = vr_.max = SSL_LIBRARY_VERSION_NONE;
diff --git a/security/nss/gtests/ssl_gtest/test_io.cc b/security/nss/gtests/ssl_gtest/test_io.cc
index 7282178515..d76b3526c6 100644
--- a/security/nss/gtests/ssl_gtest/test_io.cc
+++ b/security/nss/gtests/ssl_gtest/test_io.cc
@@ -99,8 +99,8 @@ int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
return -1;
}
- auto peer = peer_.lock();
- if (!peer) {
+ auto dst = peer_.lock();
+ if (!dst) {
PR_SetError(PR_IO_ERROR, 0);
return -1;
}
@@ -116,14 +116,14 @@ int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
case PacketFilter::CHANGE:
LOG("Original packet: " << packet);
LOG("Filtered packet: " << filtered);
- peer->PacketReceived(filtered);
+ dst->PacketReceived(filtered);
break;
case PacketFilter::DROP:
LOG("Droppped packet: " << packet);
break;
case PacketFilter::KEEP:
LOGV("Packet: " << packet);
- peer->PacketReceived(packet);
+ dst->PacketReceived(packet);
break;
}
// libssl can't handle it if this reports something other than the length
diff --git a/security/nss/gtests/ssl_gtest/test_io.h b/security/nss/gtests/ssl_gtest/test_io.h
index dbeb6b9d4c..8327373ce5 100644
--- a/security/nss/gtests/ssl_gtest/test_io.h
+++ b/security/nss/gtests/ssl_gtest/test_io.h
@@ -59,9 +59,9 @@ class PacketFilter {
class DummyPrSocket : public DummyIOLayerMethods {
public:
- DummyPrSocket(const std::string& name, SSLProtocolVariant variant)
+ DummyPrSocket(const std::string& name, SSLProtocolVariant var)
: name_(name),
- variant_(variant),
+ variant_(var),
peer_(),
input_(),
filter_(nullptr),
@@ -73,7 +73,7 @@ class DummyPrSocket : public DummyIOLayerMethods {
ScopedPRFileDesc CreateFD();
std::weak_ptr<DummyPrSocket>& peer() { return peer_; }
- void SetPeer(const std::shared_ptr<DummyPrSocket>& peer) { peer_ = peer; }
+ void SetPeer(const std::shared_ptr<DummyPrSocket>& p) { peer_ = p; }
void SetPacketFilter(const std::shared_ptr<PacketFilter>& filter) {
filter_ = filter;
}
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.cc b/security/nss/gtests/ssl_gtest/tls_agent.cc
index 2f71caedb0..9bed1ce1b7 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -33,6 +33,7 @@ const char* TlsAgent::states[] = {"INIT", "CONNECTING", "CONNECTED", "ERROR"};
const std::string TlsAgent::kClient = "client"; // both sign and encrypt
const std::string TlsAgent::kRsa2048 = "rsa2048"; // bigger
+const std::string TlsAgent::kRsa8192 = "rsa8192"; // biggest allowed
const std::string TlsAgent::kServerRsa = "rsa"; // both sign and encrypt
const std::string TlsAgent::kServerRsaSign = "rsa_sign";
const std::string TlsAgent::kServerRsaPss = "rsa_pss";
@@ -44,13 +45,22 @@ const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
const std::string TlsAgent::kServerDsa = "dsa";
-TlsAgent::TlsAgent(const std::string& name, Role role,
- SSLProtocolVariant variant)
- : name_(name),
- variant_(variant),
- role_(role),
+static const uint8_t kCannedTls13ServerHello[] = {
+ 0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
+ 0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
+ 0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
+ 0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
+ 0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
+ 0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
+ 0x80, 0x8f, 0x2c, 0xac, 0x0a, 0xea, 0x53, 0x3a, 0xcb, 0xe3, 0x08,
+ 0x84, 0xae, 0x19, 0x00, 0x2b, 0x00, 0x02, 0x7f, kD13};
+
+TlsAgent::TlsAgent(const std::string& nm, Role rl, SSLProtocolVariant var)
+ : name_(nm),
+ variant_(var),
+ role_(rl),
server_key_bits_(0),
- adapter_(new DummyPrSocket(role_str(), variant)),
+ adapter_(new DummyPrSocket(role_str(), var)),
ssl_fd_(nullptr),
state_(STATE_INIT),
timer_handle_(nullptr),
@@ -103,11 +113,11 @@ TlsAgent::~TlsAgent() {
}
}
-void TlsAgent::SetState(State state) {
- if (state_ == state) return;
+void TlsAgent::SetState(State s) {
+ if (state_ == s) return;
- LOG("Changing state from " << state_ << " to " << state);
- state_ = state;
+ LOG("Changing state from " << state_ << " to " << s);
+ state_ = s;
}
/*static*/ bool TlsAgent::LoadCertificate(const std::string& name,
@@ -124,11 +134,11 @@ void TlsAgent::SetState(State state) {
return true;
}
-bool TlsAgent::ConfigServerCert(const std::string& name, bool updateKeyBits,
+bool TlsAgent::ConfigServerCert(const std::string& id, bool updateKeyBits,
const SSLExtraServerCertData* serverCertData) {
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
- if (!TlsAgent::LoadCertificate(name, &cert, &priv)) {
+ if (!TlsAgent::LoadCertificate(id, &cert, &priv)) {
return false;
}
@@ -175,6 +185,10 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
if (rv != SECSuccess) return false;
}
+ ScopedCERTCertList anchors(CERT_NewCertList());
+ rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get());
+ if (rv != SECSuccess) return false;
+
if (role_ == SERVER) {
EXPECT_TRUE(ConfigServerCert(name_, true));
@@ -182,10 +196,6 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
- ScopedCERTCertList anchors(CERT_NewCertList());
- rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get());
- if (rv != SECSuccess) return false;
-
rv = SSL_SetMaxEarlyDataSize(ssl_fd(), 1024);
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
@@ -246,6 +256,17 @@ void TlsAgent::SetupClientAuth() {
reinterpret_cast<void*>(this)));
}
+void CheckCertReqAgainstDefaultCAs(const CERTDistNames* caNames) {
+ ScopedCERTDistNames expected(CERT_GetSSLCACerts(nullptr));
+
+ ASSERT_EQ(expected->nnames, caNames->nnames);
+
+ for (size_t i = 0; i < static_cast<size_t>(expected->nnames); ++i) {
+ EXPECT_EQ(SECEqual,
+ SECITEM_CompareItem(&(expected->names[i]), &(caNames->names[i])));
+ }
+}
+
SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
CERTDistNames* caNames,
CERTCertificate** clientCert,
@@ -254,6 +275,9 @@ SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
+ // See bug 1457716
+ // CheckCertReqAgainstDefaultCAs(caNames);
+
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) {
@@ -282,8 +306,8 @@ bool TlsAgent::GetPeerChainLength(size_t* count) {
return true;
}
-void TlsAgent::CheckCipherSuite(uint16_t cipher_suite) {
- EXPECT_EQ(csinfo_.cipherSuite, cipher_suite);
+void TlsAgent::CheckCipherSuite(uint16_t suite) {
+ EXPECT_EQ(csinfo_.cipherSuite, suite);
}
void TlsAgent::RequestClientAuth(bool requireAuth) {
@@ -442,9 +466,7 @@ void TlsAgent::GetVersionRange(uint16_t* minver, uint16_t* maxver) {
*maxver = vrange_.max;
}
-void TlsAgent::SetExpectedVersion(uint16_t version) {
- expected_version_ = version;
-}
+void TlsAgent::SetExpectedVersion(uint16_t ver) { expected_version_ = ver; }
void TlsAgent::SetServerKeyBits(uint16_t bits) { server_key_bits_ = bits; }
@@ -491,10 +513,10 @@ void TlsAgent::SetSignatureSchemes(const SSLSignatureScheme* schemes,
EXPECT_EQ(i, configuredCount) << "schemes in use were all set";
}
-void TlsAgent::CheckKEA(SSLKEAType kea_type, SSLNamedGroup kea_group,
+void TlsAgent::CheckKEA(SSLKEAType kea, SSLNamedGroup kea_group,
size_t kea_size) const {
EXPECT_EQ(STATE_CONNECTED, state_);
- EXPECT_EQ(kea_type, info_.keaType);
+ EXPECT_EQ(kea, info_.keaType);
if (kea_size == 0) {
switch (kea_group) {
case ssl_grp_ec_curve25519:
@@ -515,7 +537,7 @@ void TlsAgent::CheckKEA(SSLKEAType kea_type, SSLNamedGroup kea_group,
case ssl_grp_ffdhe_custom:
break;
default:
- if (kea_type == ssl_kea_rsa) {
+ if (kea == ssl_kea_rsa) {
kea_size = server_key_bits_;
} else {
EXPECT_TRUE(false) << "need to update group sizes";
@@ -534,13 +556,13 @@ void TlsAgent::CheckOriginalKEA(SSLNamedGroup kea_group) const {
}
}
-void TlsAgent::CheckAuthType(SSLAuthType auth_type,
+void TlsAgent::CheckAuthType(SSLAuthType auth,
SSLSignatureScheme sig_scheme) const {
EXPECT_EQ(STATE_CONNECTED, state_);
- EXPECT_EQ(auth_type, info_.authType);
+ EXPECT_EQ(auth, info_.authType);
EXPECT_EQ(server_key_bits_, info_.authKeyBits);
if (expected_version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
- switch (auth_type) {
+ switch (auth) {
case ssl_auth_rsa_sign:
sig_scheme = ssl_sig_rsa_pkcs1_sha1md5;
break;
@@ -558,9 +580,8 @@ void TlsAgent::CheckAuthType(SSLAuthType auth_type,
}
// Check authAlgorithm, which is the old value for authType. This is a second
- // switch
- // statement because default label is different.
- switch (auth_type) {
+ // switch statement because default label is different.
+ switch (auth) {
case ssl_auth_rsa_sign:
EXPECT_EQ(ssl_auth_rsa_decrypt, csinfo_.authAlgorithm)
<< "authAlgorithm for RSA is always decrypt";
@@ -574,7 +595,7 @@ void TlsAgent::CheckAuthType(SSLAuthType auth_type,
<< "authAlgorithm for ECDH_ECDSA is ECDSA (i.e., wrong)";
break;
default:
- EXPECT_EQ(auth_type, csinfo_.authAlgorithm)
+ EXPECT_EQ(auth, csinfo_.authAlgorithm)
<< "authAlgorithm is (usually) the same as authType";
break;
}
@@ -593,22 +614,20 @@ void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
EXPECT_TRUE(EnsureTlsSetup());
-
- SetOption(SSL_ENABLE_ALPN, PR_TRUE);
EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd(), val, len));
}
void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
const std::string& expected) const {
- SSLNextProtoState state;
+ SSLNextProtoState alpn_state;
char chosen[10];
unsigned int chosen_len;
- SECStatus rv = SSL_GetNextProto(ssl_fd(), &state,
+ SECStatus rv = SSL_GetNextProto(ssl_fd(), &alpn_state,
reinterpret_cast<unsigned char*>(chosen),
&chosen_len, sizeof(chosen));
EXPECT_EQ(SECSuccess, rv);
- EXPECT_EQ(expected_state, state);
- if (state == SSL_NEXT_PROTO_NO_SUPPORT) {
+ EXPECT_EQ(expected_state, alpn_state);
+ if (alpn_state == SSL_NEXT_PROTO_NO_SUPPORT) {
EXPECT_EQ("", expected);
} else {
EXPECT_NE("", expected);
@@ -840,10 +859,10 @@ void TlsAgent::CheckSecretsDestroyed() {
ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd()));
}
-void TlsAgent::SetDowngradeCheckVersion(uint16_t version) {
+void TlsAgent::SetDowngradeCheckVersion(uint16_t ver) {
ASSERT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd(), version);
+ SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd(), ver);
ASSERT_EQ(SECSuccess, rv);
}
@@ -920,9 +939,9 @@ static bool ErrorIsNonFatal(PRErrorCode code) {
}
void TlsAgent::SendData(size_t bytes, size_t blocksize) {
- uint8_t block[4096];
+ uint8_t block[16385]; // One larger than the maximum record size.
- ASSERT_LT(blocksize, sizeof(block));
+ ASSERT_LE(blocksize, sizeof(block));
while (bytes) {
size_t tosend = std::min(blocksize, bytes);
@@ -951,12 +970,13 @@ void TlsAgent::SendBuffer(const DataBuffer& buf) {
}
bool TlsAgent::SendEncryptedRecord(const std::shared_ptr<TlsCipherSpec>& spec,
- uint16_t wireVersion, uint64_t seq,
- uint8_t ct, const DataBuffer& buf) {
- LOGV("Writing " << buf.len() << " bytes");
- // Ensure we are a TLS 1.3 cipher agent.
+ 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(wireVersion, kTlsApplicationDataType, seq);
+ TlsRecordHeader header(variant_, expected_version_, kTlsApplicationDataType,
+ seq);
DataBuffer padded = buf;
padded.Write(padded.len(), ct, 1);
DataBuffer ciphertext;
@@ -1078,15 +1098,20 @@ void TlsAgentTestBase::ProcessMessage(const DataBuffer& buffer,
void TlsAgentTestBase::MakeRecord(SSLProtocolVariant variant, uint8_t type,
uint16_t version, const uint8_t* buf,
size_t len, DataBuffer* out,
- uint64_t seq_num) {
+ uint64_t sequence_number) {
size_t index = 0;
index = out->Write(index, type, 1);
if (variant == ssl_variant_stream) {
index = out->Write(index, version, 2);
+ } else if (version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ type == kTlsApplicationDataType) {
+ uint32_t epoch = (sequence_number >> 48) & 0x3;
+ uint32_t seqno = sequence_number & ((1ULL << 30) - 1);
+ index = out->Write(index, (epoch << 30) | seqno, 4);
} else {
index = out->Write(index, TlsVersionToDtlsVersion(version), 2);
- index = out->Write(index, seq_num >> 32, 4);
- index = out->Write(index, seq_num & PR_UINT32_MAX, 4);
+ index = out->Write(index, sequence_number >> 32, 4);
+ index = out->Write(index, sequence_number & PR_UINT32_MAX, 4);
}
index = out->Write(index, len, 2);
out->Write(index, buf, len);
@@ -1144,4 +1169,12 @@ void TlsAgentTestBase::MakeTrivialHandshakeRecord(uint8_t hs_type,
}
}
+DataBuffer TlsAgentTestBase::MakeCannedTls13ServerHello() {
+ DataBuffer sh(kCannedTls13ServerHello, sizeof(kCannedTls13ServerHello));
+ if (variant_ == ssl_variant_datagram) {
+ sh.Write(0, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, 2);
+ }
+ return sh;
+}
+
} // namespace nss_test
diff --git a/security/nss/gtests/ssl_gtest/tls_agent.h b/security/nss/gtests/ssl_gtest/tls_agent.h
index 6cd6d5073b..a93d0c6ee5 100644
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -10,6 +10,9 @@
#include "prio.h"
#include "ssl.h"
+// This is an internal header, used to get TLS_1_3_DRAFT_VERSION.
+#include "ssl3prot.h"
+
#include <functional>
#include <iostream>
@@ -57,6 +60,8 @@ typedef std::function<int32_t(TlsAgent* agent, const SECItem* srvNameArr,
PRUint32 srvNameArrSize)>
SniCallbackFunction;
+static const uint8_t kD13 = TLS_1_3_DRAFT_VERSION;
+
class TlsAgent : public PollTarget {
public:
enum Role { CLIENT, SERVER };
@@ -64,6 +69,7 @@ class TlsAgent : public PollTarget {
static const std::string kClient; // the client key is sign only
static const std::string kRsa2048; // bigger sign and encrypt for either
+ static const std::string kRsa8192; // biggest sign and encrypt for either
static const std::string kServerRsa; // both sign and encrypt
static const std::string kServerRsaSign;
static const std::string kServerRsaPss;
@@ -143,8 +149,7 @@ class TlsAgent : public PollTarget {
void SendData(size_t bytes, size_t blocksize = 1024);
void SendBuffer(const DataBuffer& buf);
bool SendEncryptedRecord(const std::shared_ptr<TlsCipherSpec>& spec,
- uint16_t wireVersion, uint64_t seq, uint8_t ct,
- const DataBuffer& buf);
+ uint64_t seq, uint8_t ct, const DataBuffer& buf);
// Send data directly to the underlying socket, skipping the TLS layer.
void SendDirect(const DataBuffer& buf);
void SendRecordDirect(const TlsRecord& record);
@@ -209,10 +214,10 @@ class TlsAgent : public PollTarget {
return info_.protocolVersion;
}
- bool cipher_suite(uint16_t* cipher_suite) const {
+ bool cipher_suite(uint16_t* suite) const {
if (state_ != STATE_CONNECTED) return false;
- *cipher_suite = info_.cipherSuite;
+ *suite = info_.cipherSuite;
return true;
}
@@ -227,17 +232,17 @@ class TlsAgent : public PollTarget {
info_.sessionID + info_.sessionIDLength);
}
- bool auth_type(SSLAuthType* auth_type) const {
+ bool auth_type(SSLAuthType* a) const {
if (state_ != STATE_CONNECTED) return false;
- *auth_type = info_.authType;
+ *a = info_.authType;
return true;
}
- bool kea_type(SSLKEAType* kea_type) const {
+ bool kea_type(SSLKEAType* k) const {
if (state_ != STATE_CONNECTED) return false;
- *kea_type = info_.keaType;
+ *k = info_.keaType;
return true;
}
@@ -264,6 +269,8 @@ class TlsAgent : public PollTarget {
void ExpectReceiveAlert(uint8_t alert, uint8_t level = 0);
void ExpectSendAlert(uint8_t alert, uint8_t level = 0);
+ std::string alpn_value_to_use_ = "";
+
private:
const static char* states[];
@@ -443,6 +450,7 @@ class TlsAgentTestBase : public ::testing::Test {
size_t hs_len, DataBuffer* out,
uint64_t seq_num, uint32_t fragment_offset,
uint32_t fragment_length) const;
+ DataBuffer MakeCannedTls13ServerHello();
static void MakeTrivialHandshakeRecord(uint8_t hs_type, size_t hs_len,
DataBuffer* out);
static inline TlsAgent::Role ToRole(const std::string& str) {
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.cc b/security/nss/gtests/ssl_gtest/tls_connect.cc
index 8567b392fd..68f6d21e9c 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -571,14 +571,57 @@ void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
}
}
+static SECStatus NextProtoCallbackServer(void* arg, PRFileDesc* fd,
+ const unsigned char* protos,
+ unsigned int protos_len,
+ unsigned char* protoOut,
+ unsigned int* protoOutLen,
+ unsigned int protoMaxLen) {
+ EXPECT_EQ(protoMaxLen, 255U);
+ TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
+ // Check that agent->alpn_value_to_use_ is in protos.
+ if (protos_len < 1) {
+ return SECFailure;
+ }
+ for (size_t i = 0; i < protos_len;) {
+ size_t l = protos[i];
+ EXPECT_LT(i + l, protos_len);
+ if (i + l >= protos_len) {
+ return SECFailure;
+ }
+ std::string protos_s(reinterpret_cast<const char*>(protos + i + 1), l);
+ if (protos_s == agent->alpn_value_to_use_) {
+ size_t s_len = agent->alpn_value_to_use_.size();
+ EXPECT_LE(s_len, 255U);
+ memcpy(protoOut, &agent->alpn_value_to_use_[0], s_len);
+ *protoOutLen = s_len;
+ return SECSuccess;
+ }
+ i += l + 1;
+ }
+ return SECFailure;
+}
+
void TlsConnectTestBase::EnableAlpn() {
client_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
server_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
}
-void TlsConnectTestBase::EnableAlpn(const uint8_t* val, size_t len) {
- client_->EnableAlpn(val, len);
- server_->EnableAlpn(val, len);
+void TlsConnectTestBase::EnableAlpnWithCallback(
+ const std::vector<uint8_t>& client_vals, std::string server_choice) {
+ EnsureTlsSetup();
+ server_->alpn_value_to_use_ = server_choice;
+ EXPECT_EQ(SECSuccess,
+ SSL_SetNextProtoNego(client_->ssl_fd(), client_vals.data(),
+ client_vals.size()));
+ SECStatus rv = SSL_SetNextProtoCallback(
+ server_->ssl_fd(), NextProtoCallbackServer, server_.get());
+ EXPECT_EQ(SECSuccess, rv);
+}
+
+void TlsConnectTestBase::EnableAlpn(const std::vector<uint8_t>& vals) {
+ client_->EnableAlpn(vals.data(), vals.size());
+ server_->EnableAlpn(vals.data(), vals.size());
}
void TlsConnectTestBase::EnsureModelSockets() {
diff --git a/security/nss/gtests/ssl_gtest/tls_connect.h b/security/nss/gtests/ssl_gtest/tls_connect.h
index 7dffe7f8aa..0004945011 100644
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -110,7 +110,9 @@ class TlsConnectTestBase : public ::testing::Test {
void ConfigureSessionCache(SessionResumptionMode client,
SessionResumptionMode server);
void EnableAlpn();
- void EnableAlpn(const uint8_t* val, size_t len);
+ void EnableAlpnWithCallback(const std::vector<uint8_t>& client,
+ std::string server_choice);
+ void EnableAlpn(const std::vector<uint8_t>& vals);
void EnsureModelSockets();
void CheckAlpn(const std::string& val);
void EnableSrtp();
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.cc b/security/nss/gtests/ssl_gtest/tls_filter.cc
index d34b13bcb5..aa03cba70b 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -30,11 +30,9 @@ void TlsVersioned::WriteStream(std::ostream& stream) const {
case SSL_LIBRARY_VERSION_TLS_1_0:
stream << "1.0";
break;
- case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
case SSL_LIBRARY_VERSION_TLS_1_1:
stream << (is_dtls() ? "1.0" : "1.1");
break;
- case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
case SSL_LIBRARY_VERSION_TLS_1_2:
stream << "1.2";
break;
@@ -67,8 +65,14 @@ void TlsRecordFilter::CipherSpecChanged(void* arg, PRBool sending,
return;
}
- self->in_sequence_number_ = 0;
- self->out_sequence_number_ = 0;
+ uint64_t seq_no;
+ if (self->agent()->variant() == ssl_variant_datagram) {
+ seq_no = static_cast<uint64_t>(SSLInt_CipherSpecToEpoch(newSpec)) << 48;
+ } else {
+ seq_no = 0;
+ }
+ self->in_sequence_number_ = seq_no;
+ self->out_sequence_number_ = seq_no;
self->dropped_record_ = false;
self->cipher_spec_.reset(new TlsCipherSpec());
bool ret = self->cipher_spec_->Init(
@@ -77,33 +81,59 @@ void TlsRecordFilter::CipherSpecChanged(void* arg, PRBool sending,
EXPECT_EQ(true, ret);
}
+bool TlsRecordFilter::is_dtls13() const {
+ if (agent()->variant() != ssl_variant_datagram) {
+ return false;
+ }
+ if (agent()->state() == TlsAgent::STATE_CONNECTED) {
+ return agent()->version() >= SSL_LIBRARY_VERSION_TLS_1_3;
+ }
+ SSLPreliminaryChannelInfo info;
+ EXPECT_EQ(SECSuccess, SSL_GetPreliminaryChannelInfo(agent()->ssl_fd(), &info,
+ sizeof(info)));
+ return (info.protocolVersion >= SSL_LIBRARY_VERSION_TLS_1_3) ||
+ info.canSendEarlyData;
+}
+
PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
DataBuffer* output) {
+ // Disable during shutdown.
+ if (!agent()) {
+ return KEEP;
+ }
+
bool changed = false;
size_t offset = 0U;
- output->Allocate(input.len());
+ output->Allocate(input.len());
TlsParser parser(input);
while (parser.remaining()) {
TlsRecordHeader header;
DataBuffer record;
- if (!header.Parse(in_sequence_number_, &parser, &record)) {
+ if (!header.Parse(is_dtls13(), in_sequence_number_, &parser, &record)) {
ADD_FAILURE() << "not a valid record";
return KEEP;
}
- // Track the sequence number, which is necessary for stream mode (the
- // sequence number is in the header for datagram).
+ // Track the sequence number, which is necessary for stream mode when
+ // decrypting and for TLS 1.3 datagram to recover the sequence number.
+ //
+ // We reset the counter when the cipher spec changes, but that notification
+ // appears before a record is sent. If multiple records are sent with
+ // different cipher specs, this would fail. This filters out cleartext
+ // records, so we don't get confused by handshake messages that are sent at
+ // the same time as encrypted records. Sequence numbers are therefore
+ // likely to be incorrect for cleartext records.
//
- // This isn't perfectly robust. If there is a change from an active cipher
+ // This isn't perfectly robust: if there is a change from an active cipher
// spec to another active cipher spec (KeyUpdate for instance) AND writes
- // are consolidated across that change AND packets were dropped from the
- // older epoch, we will not correctly re-encrypt records in the old epoch to
- // update their sequence numbers.
- if (cipher_spec_ && header.content_type() == kTlsApplicationDataType) {
- ++in_sequence_number_;
+ // are consolidated across that change, this code could use the wrong
+ // sequence numbers when re-encrypting records with the old keys.
+ if (header.content_type() == kTlsApplicationDataType) {
+ in_sequence_number_ =
+ (std::max)(in_sequence_number_, header.sequence_number() + 1);
}
if (FilterRecord(header, record, &offset, output) != KEEP) {
@@ -131,11 +161,14 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
DataBuffer plaintext;
if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
+ if (g_ssl_gtest_verbose) {
+ std::cerr << "unprotect failed: " << header << ":" << record << std::endl;
+ }
return KEEP;
}
- TlsRecordHeader real_header = {header.version(), inner_content_type,
- header.sequence_number()};
+ TlsRecordHeader real_header(header.variant(), header.version(),
+ inner_content_type, 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
@@ -166,8 +199,8 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
} else {
seq_num = out_sequence_number_++;
}
- TlsRecordHeader out_header = {header.version(), header.content_type(),
- seq_num};
+ TlsRecordHeader out_header(header.variant(), header.version(),
+ header.content_type(), seq_num);
DataBuffer ciphertext;
bool rv = Protect(out_header, inner_content_type, filtered, &ciphertext);
@@ -179,20 +212,119 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
return CHANGE;
}
-bool TlsRecordHeader::Parse(uint64_t sequence_number, TlsParser* parser,
+size_t TlsRecordHeader::header_length() const {
+ // If we have a header, return it's length.
+ if (header_.len()) {
+ return header_.len();
+ }
+
+ // Otherwise make a dummy header and return the length.
+ DataBuffer buf;
+ return WriteHeader(&buf, 0, 0);
+}
+
+uint64_t TlsRecordHeader::RecoverSequenceNumber(uint64_t expected,
+ uint32_t partial,
+ size_t partial_bits) {
+ EXPECT_GE(32U, partial_bits);
+ uint64_t mask = (1 << partial_bits) - 1;
+ // First we determine the highest possible value. This is half the
+ // expressible range above the expected value.
+ uint64_t cap = expected + (1ULL << (partial_bits - 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,
+ // then the real value has to be lower. e.g., xxxx1234 can't become xxxx5678.
+ if (partial > (cap & mask)) {
+ seq_no -= 1ULL << partial_bits;
+ }
+ return seq_no;
+}
+
+// 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,
+ 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)) {
+ // If the epoch has changed, reset the expected sequence number.
+ expected = 0;
+ } else {
+ // Otherwise, retain just the sequence number part.
+ 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;
+}
+
+bool TlsRecordHeader::Parse(bool is_dtls13, uint64_t seqno, TlsParser* parser,
DataBuffer* body) {
+ auto mark = parser->consumed();
+
if (!parser->Read(&content_type_)) {
return false;
}
- uint32_t version;
- if (!parser->Read(&version, 2)) {
+ if (is_dtls13) {
+ variant_ = ssl_variant_datagram;
+ version_ = SSL_LIBRARY_VERSION_TLS_1_3;
+
+#ifndef UNSAFE_FUZZER_MODE
+ // Deal with the 7 octet header.
+ if (content_type_ == kTlsApplicationDataType) {
+ uint32_t tmp;
+ if (!parser->Read(&tmp, 4)) {
+ return false;
+ }
+ sequence_number_ = ParseSequenceNumber(seqno, tmp, 30, 2);
+ if (!parser->ReadFromMark(&header_, parser->consumed() + 2 - mark,
+ mark)) {
+ return false;
+ }
+ return parser->ReadVariable(body, 2);
+ }
+
+ // The short, 2 octet header.
+ if ((content_type_ & 0xe0) == 0x20) {
+ uint32_t tmp;
+ if (!parser->Read(&tmp, 1)) {
+ return false;
+ }
+ // Need to use the low 5 bits of the first octet too.
+ tmp |= (content_type_ & 0x1f) << 8;
+ content_type_ = kTlsApplicationDataType;
+ sequence_number_ = ParseSequenceNumber(seqno, tmp, 12, 1);
+
+ if (!parser->ReadFromMark(&header_, parser->consumed() - mark, mark)) {
+ return false;
+ }
+ return parser->Read(body, parser->remaining());
+ }
+
+ // The full 13 octet header can only be used for a few types.
+ EXPECT_TRUE(content_type_ == kTlsAlertType ||
+ content_type_ == kTlsHandshakeType ||
+ content_type_ == kTlsAckType);
+#endif
+ }
+
+ uint32_t ver;
+ if (!parser->Read(&ver, 2)) {
return false;
}
- version_ = version;
+ if (!is_dtls13) {
+ variant_ = IsDtls(ver) ? ssl_variant_datagram : ssl_variant_stream;
+ }
+ version_ = NormalizeTlsVersion(ver);
- // If this is DTLS, overwrite the sequence number.
- if (IsDtls(version)) {
+ if (is_dtls()) {
+ // If this is DTLS, read the sequence number.
uint32_t tmp;
if (!parser->Read(&tmp, 4)) {
return false;
@@ -203,21 +335,40 @@ bool TlsRecordHeader::Parse(uint64_t sequence_number, TlsParser* parser,
}
sequence_number_ |= static_cast<uint64_t>(tmp);
} else {
- sequence_number_ = sequence_number;
+ sequence_number_ = seqno;
+ }
+ if (!parser->ReadFromMark(&header_, parser->consumed() + 2 - mark, mark)) {
+ return false;
}
return parser->ReadVariable(body, 2);
}
-size_t TlsRecordHeader::Write(DataBuffer* buffer, size_t offset,
- const DataBuffer& body) const {
+size_t TlsRecordHeader::WriteHeader(DataBuffer* buffer, size_t offset,
+ size_t body_len) const {
offset = buffer->Write(offset, content_type_, 1);
- offset = buffer->Write(offset, version_, 2);
- if (is_dtls()) {
- // write epoch (2 octet), and seqnum (6 octet)
- offset = buffer->Write(offset, sequence_number_ >> 32, 4);
- offset = buffer->Write(offset, sequence_number_ & 0xffffffff, 4);
+ if (is_dtls() && version_ >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ content_type() == kTlsApplicationDataType) {
+ // 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);
+ } else {
+ uint16_t v = is_dtls() ? TlsVersionToDtlsVersion(version_) : version_;
+ offset = buffer->Write(offset, v, 2);
+ if (is_dtls()) {
+ // write epoch (2 octet), and seqnum (6 octet)
+ 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;
+}
+
+size_t TlsRecordHeader::Write(DataBuffer* buffer, size_t offset,
+ const DataBuffer& body) const {
+ offset = WriteHeader(buffer, offset, body.len());
offset = buffer->Write(offset, body);
return offset;
}
@@ -259,7 +410,7 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
uint8_t inner_content_type,
const DataBuffer& plaintext,
- DataBuffer* ciphertext) {
+ DataBuffer* ciphertext, size_t padding) {
if (!cipher_spec_ || header.content_type() != kTlsApplicationDataType) {
*ciphertext = plaintext;
return true;
@@ -267,8 +418,10 @@ bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
if (g_ssl_gtest_verbose) {
std::cerr << "protect: " << header.sequence_number() << std::endl;
}
- DataBuffer padded = plaintext;
- padded.Write(padded.len(), inner_content_type, 1);
+ DataBuffer padded;
+ padded.Allocate(plaintext.len() + 1 + padding);
+ size_t offset = padded.Write(0, plaintext.data(), plaintext.len());
+ padded.Write(offset, inner_content_type, 1);
return cipher_spec_->Protect(header, padded, ciphertext);
}
@@ -406,6 +559,7 @@ bool TlsHandshakeFilter::HandshakeHeader::Parse(
const DataBuffer& preceding_fragment, DataBuffer* body, bool* complete) {
*complete = false;
+ variant_ = record_header.variant();
version_ = record_header.version();
if (!parser->Read(&handshake_type_)) {
return false; // malformed
@@ -487,10 +641,10 @@ PacketFilter::Action TlsConversationRecorder::FilterRecord(
return KEEP;
}
-PacketFilter::Action TlsHeaderRecorder::FilterRecord(
- const TlsRecordHeader& header, const DataBuffer& input,
- DataBuffer* output) {
- headers_.push_back(header);
+PacketFilter::Action TlsHeaderRecorder::FilterRecord(const TlsRecordHeader& hdr,
+ const DataBuffer& input,
+ DataBuffer* output) {
+ headers_.push_back(hdr);
return KEEP;
}
diff --git a/security/nss/gtests/ssl_gtest/tls_filter.h b/security/nss/gtests/ssl_gtest/tls_filter.h
index 1bbe190abe..effda4aa06 100644
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -11,7 +11,7 @@
#include <memory>
#include <set>
#include <vector>
-
+#include "sslt.h"
#include "test_io.h"
#include "tls_agent.h"
#include "tls_parser.h"
@@ -27,43 +27,57 @@ class TlsCipherSpec;
class TlsVersioned {
public:
- TlsVersioned() : version_(0) {}
- explicit TlsVersioned(uint16_t version) : version_(version) {}
+ TlsVersioned() : variant_(ssl_variant_stream), version_(0) {}
+ TlsVersioned(SSLProtocolVariant var, uint16_t ver)
+ : variant_(var), version_(ver) {}
- bool is_dtls() const { return IsDtls(version_); }
+ bool is_dtls() const { return variant_ == ssl_variant_datagram; }
+ SSLProtocolVariant variant() const { return variant_; }
uint16_t version() const { return version_; }
void WriteStream(std::ostream& stream) const;
protected:
+ SSLProtocolVariant variant_;
uint16_t version_;
};
class TlsRecordHeader : public TlsVersioned {
public:
- TlsRecordHeader() : TlsVersioned(), content_type_(0), sequence_number_(0) {}
- TlsRecordHeader(uint16_t version, uint8_t content_type,
- uint64_t sequence_number)
- : TlsVersioned(version),
- content_type_(content_type),
- sequence_number_(sequence_number) {}
+ TlsRecordHeader()
+ : TlsVersioned(), content_type_(0), sequence_number_(0), header_() {}
+ TlsRecordHeader(SSLProtocolVariant var, uint16_t ver, uint8_t ct,
+ uint64_t seqno)
+ : TlsVersioned(var, ver),
+ content_type_(ct),
+ sequence_number_(seqno),
+ header_() {}
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);
}
- size_t header_length() const { return is_dtls() ? 13 : 5; }
+ size_t header_length() const;
+ const DataBuffer& header() const { return header_; }
// Parse the header; return true if successful; body in an outparam if OK.
- bool Parse(uint64_t sequence_number, TlsParser* parser, DataBuffer* body);
+ bool Parse(bool is_dtls13, uint64_t sequence_number, TlsParser* parser,
+ DataBuffer* body);
// Write the header and body to a buffer at the given offset.
// Return the offset of the end of the write.
size_t Write(DataBuffer* buffer, size_t offset, const DataBuffer& body) const;
+ size_t WriteHeader(DataBuffer* buffer, size_t offset, size_t body_len) const;
private:
+ static uint64_t RecoverSequenceNumber(uint64_t expected, 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);
+
uint8_t content_type_;
uint64_t sequence_number_;
+ DataBuffer header_;
};
struct TlsRecord {
@@ -83,8 +97,8 @@ inline std::shared_ptr<T> MakeTlsFilter(const std::shared_ptr<TlsAgent>& agent,
// Abstract filter that operates on entire (D)TLS records.
class TlsRecordFilter : public PacketFilter {
public:
- TlsRecordFilter(const std::shared_ptr<TlsAgent>& agent)
- : agent_(agent),
+ TlsRecordFilter(const std::shared_ptr<TlsAgent>& a)
+ : agent_(a),
count_(0),
cipher_spec_(),
dropped_record_(false),
@@ -106,7 +120,8 @@ class TlsRecordFilter : public PacketFilter {
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
uint8_t* inner_content_type, DataBuffer* plaintext);
bool Protect(const TlsRecordHeader& header, uint8_t inner_content_type,
- const DataBuffer& plaintext, DataBuffer* ciphertext);
+ const DataBuffer& plaintext, DataBuffer* ciphertext,
+ size_t padding = 0);
protected:
// There are two filter functions which can be overriden. Both are
@@ -130,6 +145,8 @@ class TlsRecordFilter : public PacketFilter {
return KEEP;
}
+ bool is_dtls13() const;
+
private:
static void CipherSpecChanged(void* arg, PRBool sending,
ssl3CipherSpec* newSpec);
@@ -183,13 +200,11 @@ inline std::ostream& operator<<(std::ostream& stream,
// records and that they don't span records or anything crazy like that.
class TlsHandshakeFilter : public TlsRecordFilter {
public:
- TlsHandshakeFilter(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent), handshake_types_(), preceding_fragment_() {}
- TlsHandshakeFilter(const std::shared_ptr<TlsAgent>& agent,
+ TlsHandshakeFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a), handshake_types_(), preceding_fragment_() {}
+ TlsHandshakeFilter(const std::shared_ptr<TlsAgent>& a,
const std::set<uint8_t>& types)
- : TlsRecordFilter(agent),
- handshake_types_(types),
- preceding_fragment_() {}
+ : TlsRecordFilter(a), handshake_types_(types), preceding_fragment_() {}
// This filter can be set to be selective based on handshake message type. If
// this function isn't used (or the set is empty), then all handshake messages
@@ -243,12 +258,12 @@ class TlsHandshakeFilter : public TlsRecordFilter {
// Make a copy of the first instance of a handshake message.
class TlsHandshakeRecorder : public TlsHandshakeFilter {
public:
- TlsHandshakeRecorder(const std::shared_ptr<TlsAgent>& agent,
+ TlsHandshakeRecorder(const std::shared_ptr<TlsAgent>& a,
uint8_t handshake_type)
- : TlsHandshakeFilter(agent, {handshake_type}), buffer_() {}
- TlsHandshakeRecorder(const std::shared_ptr<TlsAgent>& agent,
+ : TlsHandshakeFilter(a, {handshake_type}), buffer_() {}
+ TlsHandshakeRecorder(const std::shared_ptr<TlsAgent>& a,
const std::set<uint8_t>& handshake_types)
- : TlsHandshakeFilter(agent, handshake_types), buffer_() {}
+ : TlsHandshakeFilter(a, handshake_types), buffer_() {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
@@ -265,10 +280,10 @@ class TlsHandshakeRecorder : public TlsHandshakeFilter {
// Replace all instances of a handshake message.
class TlsInspectorReplaceHandshakeMessage : public TlsHandshakeFilter {
public:
- TlsInspectorReplaceHandshakeMessage(const std::shared_ptr<TlsAgent>& agent,
+ TlsInspectorReplaceHandshakeMessage(const std::shared_ptr<TlsAgent>& a,
uint8_t handshake_type,
const DataBuffer& replacement)
- : TlsHandshakeFilter(agent, {handshake_type}), buffer_(replacement) {}
+ : TlsHandshakeFilter(a, {handshake_type}), buffer_(replacement) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
@@ -281,10 +296,10 @@ class TlsInspectorReplaceHandshakeMessage : public TlsHandshakeFilter {
// Make a copy of each record of a given type.
class TlsRecordRecorder : public TlsRecordFilter {
public:
- TlsRecordRecorder(const std::shared_ptr<TlsAgent>& agent, uint8_t ct)
- : TlsRecordFilter(agent), filter_(true), ct_(ct), records_() {}
- TlsRecordRecorder(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent),
+ TlsRecordRecorder(const std::shared_ptr<TlsAgent>& a, uint8_t ct)
+ : TlsRecordFilter(a), filter_(true), ct_(ct), records_() {}
+ TlsRecordRecorder(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a),
filter_(false),
ct_(content_handshake), // dummy (<optional> is C++14)
records_() {}
@@ -306,9 +321,9 @@ class TlsRecordRecorder : public TlsRecordFilter {
// Make a copy of the complete conversation.
class TlsConversationRecorder : public TlsRecordFilter {
public:
- TlsConversationRecorder(const std::shared_ptr<TlsAgent>& agent,
+ TlsConversationRecorder(const std::shared_ptr<TlsAgent>& a,
DataBuffer& buffer)
- : TlsRecordFilter(agent), buffer_(buffer) {}
+ : TlsRecordFilter(a), buffer_(buffer) {}
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
@@ -321,8 +336,7 @@ class TlsConversationRecorder : public TlsRecordFilter {
// Make a copy of the records
class TlsHeaderRecorder : public TlsRecordFilter {
public:
- TlsHeaderRecorder(const std::shared_ptr<TlsAgent>& agent)
- : TlsRecordFilter(agent) {}
+ TlsHeaderRecorder(const std::shared_ptr<TlsAgent>& a) : TlsRecordFilter(a) {}
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output);
@@ -359,15 +373,15 @@ typedef std::function<bool(TlsParser* parser, const TlsVersioned& header)>
class TlsExtensionFilter : public TlsHandshakeFilter {
public:
- TlsExtensionFilter(const std::shared_ptr<TlsAgent>& agent)
- : TlsHandshakeFilter(agent,
+ TlsExtensionFilter(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a,
{kTlsHandshakeClientHello, kTlsHandshakeServerHello,
kTlsHandshakeHelloRetryRequest,
kTlsHandshakeEncryptedExtensions}) {}
- TlsExtensionFilter(const std::shared_ptr<TlsAgent>& agent,
+ TlsExtensionFilter(const std::shared_ptr<TlsAgent>& a,
const std::set<uint8_t>& types)
- : TlsHandshakeFilter(agent, types) {}
+ : TlsHandshakeFilter(a, types) {}
static bool FindExtensions(TlsParser* parser, const HandshakeHeader& header);
@@ -388,9 +402,9 @@ class TlsExtensionFilter : public TlsHandshakeFilter {
class TlsExtensionCapture : public TlsExtensionFilter {
public:
- TlsExtensionCapture(const std::shared_ptr<TlsAgent>& agent, uint16_t ext,
+ TlsExtensionCapture(const std::shared_ptr<TlsAgent>& a, uint16_t ext,
bool last = false)
- : TlsExtensionFilter(agent),
+ : TlsExtensionFilter(a),
extension_(ext),
captured_(false),
last_(last),
@@ -413,9 +427,9 @@ class TlsExtensionCapture : public TlsExtensionFilter {
class TlsExtensionReplacer : public TlsExtensionFilter {
public:
- TlsExtensionReplacer(const std::shared_ptr<TlsAgent>& agent,
- uint16_t extension, const DataBuffer& data)
- : TlsExtensionFilter(agent), extension_(extension), data_(data) {}
+ TlsExtensionReplacer(const std::shared_ptr<TlsAgent>& a, uint16_t extension,
+ const DataBuffer& data)
+ : TlsExtensionFilter(a), extension_(extension), data_(data) {}
PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
DataBuffer* output) override;
@@ -427,9 +441,8 @@ class TlsExtensionReplacer : public TlsExtensionFilter {
class TlsExtensionDropper : public TlsExtensionFilter {
public:
- TlsExtensionDropper(const std::shared_ptr<TlsAgent>& agent,
- uint16_t extension)
- : TlsExtensionFilter(agent), extension_(extension) {}
+ TlsExtensionDropper(const std::shared_ptr<TlsAgent>& a, uint16_t extension)
+ : TlsExtensionFilter(a), extension_(extension) {}
PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer&, DataBuffer*) override;
@@ -439,9 +452,9 @@ class TlsExtensionDropper : public TlsExtensionFilter {
class TlsExtensionInjector : public TlsHandshakeFilter {
public:
- TlsExtensionInjector(const std::shared_ptr<TlsAgent>& agent, uint16_t ext,
+ TlsExtensionInjector(const std::shared_ptr<TlsAgent>& a, uint16_t ext,
const DataBuffer& data)
- : TlsHandshakeFilter(agent), extension_(ext), data_(data) {}
+ : TlsHandshakeFilter(a), extension_(ext), data_(data) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
@@ -453,7 +466,6 @@ class TlsExtensionInjector : public TlsHandshakeFilter {
const DataBuffer data_;
};
-class TlsAgent;
typedef std::function<void(void)> VoidFunction;
class AfterRecordN : public TlsRecordFilter {
@@ -495,6 +507,22 @@ class TlsClientHelloVersionChanger : public TlsHandshakeFilter {
std::weak_ptr<TlsAgent> server_;
};
+// Damage a record.
+class TlsRecordLastByteDamager : public TlsRecordFilter {
+ public:
+ TlsRecordLastByteDamager(const std::shared_ptr<TlsAgent>& a)
+ : TlsRecordFilter(a) {}
+
+ protected:
+ PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& data,
+ DataBuffer* changed) override {
+ *changed = data;
+ changed->data()[changed->len() - 1]++;
+ return CHANGE;
+ }
+};
+
// This class selectively drops complete writes. This relies on the fact that
// writes in libssl are on record boundaries.
class SelectiveDropFilter : public PacketFilter {
@@ -515,16 +543,16 @@ class SelectiveDropFilter : public PacketFilter {
// datagram, we just drop one.
class SelectiveRecordDropFilter : public TlsRecordFilter {
public:
- SelectiveRecordDropFilter(const std::shared_ptr<TlsAgent>& agent,
+ SelectiveRecordDropFilter(const std::shared_ptr<TlsAgent>& a,
uint32_t pattern, bool enabled = true)
- : TlsRecordFilter(agent), pattern_(pattern), counter_(0) {
+ : TlsRecordFilter(a), pattern_(pattern), counter_(0) {
if (!enabled) {
Disable();
}
}
- SelectiveRecordDropFilter(const std::shared_ptr<TlsAgent>& agent,
+ SelectiveRecordDropFilter(const std::shared_ptr<TlsAgent>& a,
std::initializer_list<size_t> records)
- : SelectiveRecordDropFilter(agent, ToPattern(records), true) {}
+ : SelectiveRecordDropFilter(a, ToPattern(records), true) {}
void Reset(uint32_t pattern) {
counter_ = 0;
@@ -551,10 +579,9 @@ class SelectiveRecordDropFilter : public TlsRecordFilter {
// Set the version number in the ClientHello.
class TlsClientHelloVersionSetter : public TlsHandshakeFilter {
public:
- TlsClientHelloVersionSetter(const std::shared_ptr<TlsAgent>& agent,
+ TlsClientHelloVersionSetter(const std::shared_ptr<TlsAgent>& a,
uint16_t version)
- : TlsHandshakeFilter(agent, {kTlsHandshakeClientHello}),
- version_(version) {}
+ : TlsHandshakeFilter(a, {kTlsHandshakeClientHello}), version_(version) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
@@ -567,8 +594,8 @@ class TlsClientHelloVersionSetter : public TlsHandshakeFilter {
// Damages the last byte of a handshake message.
class TlsLastByteDamager : public TlsHandshakeFilter {
public:
- TlsLastByteDamager(const std::shared_ptr<TlsAgent>& agent, uint8_t type)
- : TlsHandshakeFilter(agent), type_(type) {}
+ TlsLastByteDamager(const std::shared_ptr<TlsAgent>& a, uint8_t type)
+ : TlsHandshakeFilter(a), type_(type) {}
PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
const DataBuffer& input, DataBuffer* output) override {
@@ -588,9 +615,9 @@ class TlsLastByteDamager : public TlsHandshakeFilter {
class SelectedCipherSuiteReplacer : public TlsHandshakeFilter {
public:
- SelectedCipherSuiteReplacer(const std::shared_ptr<TlsAgent>& agent,
+ SelectedCipherSuiteReplacer(const std::shared_ptr<TlsAgent>& a,
uint16_t suite)
- : TlsHandshakeFilter(agent, {kTlsHandshakeServerHello}),
+ : TlsHandshakeFilter(a, {kTlsHandshakeServerHello}),
cipher_suite_(suite) {}
protected:
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.cc b/security/nss/gtests/ssl_gtest/tls_protect.cc
index 6c945f66eb..c715a36a6b 100644
--- a/security/nss/gtests/ssl_gtest/tls_protect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_protect.cc
@@ -54,17 +54,17 @@ bool AeadCipher::AeadInner(bool decrypt, void *params, size_t param_length,
return rv == SECSuccess;
}
-bool AeadCipherAesGcm::Aead(bool decrypt, uint64_t seq, const uint8_t *in,
- size_t inlen, uint8_t *out, size_t *outlen,
- size_t maxlen) {
+bool AeadCipherAesGcm::Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len,
+ uint64_t seq, const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t *outlen, size_t maxlen) {
CK_GCM_PARAMS aeadParams;
unsigned char nonce[12];
memset(&aeadParams, 0, sizeof(aeadParams));
aeadParams.pIv = nonce;
aeadParams.ulIvLen = sizeof(nonce);
- aeadParams.pAAD = NULL;
- aeadParams.ulAADLen = 0;
+ aeadParams.pAAD = const_cast<uint8_t *>(hdr);
+ aeadParams.ulAADLen = hdr_len;
aeadParams.ulTagBits = 128;
FormatNonce(seq, nonce);
@@ -72,7 +72,8 @@ bool AeadCipherAesGcm::Aead(bool decrypt, uint64_t seq, const uint8_t *in,
in, inlen, out, outlen, maxlen);
}
-bool AeadCipherChacha20Poly1305::Aead(bool decrypt, uint64_t seq,
+bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t *hdr,
+ size_t hdr_len, uint64_t seq,
const uint8_t *in, size_t inlen,
uint8_t *out, size_t *outlen,
size_t maxlen) {
@@ -82,8 +83,8 @@ bool AeadCipherChacha20Poly1305::Aead(bool decrypt, uint64_t seq,
memset(&aeadParams, 0, sizeof(aeadParams));
aeadParams.pNonce = nonce;
aeadParams.ulNonceLen = sizeof(nonce);
- aeadParams.pAAD = NULL;
- aeadParams.ulAADLen = 0;
+ aeadParams.pAAD = const_cast<uint8_t *>(hdr);
+ aeadParams.ulAADLen = hdr_len;
aeadParams.ulTagLen = 16;
FormatNonce(seq, nonce);
@@ -91,9 +92,9 @@ bool AeadCipherChacha20Poly1305::Aead(bool decrypt, uint64_t seq,
in, inlen, out, outlen, maxlen);
}
-bool TlsCipherSpec::Init(uint16_t epoch, SSLCipherAlgorithm cipher,
+bool TlsCipherSpec::Init(uint16_t epoc, SSLCipherAlgorithm cipher,
PK11SymKey *key, const uint8_t *iv) {
- epoch_ = epoch;
+ epoch_ = epoc;
switch (cipher) {
case ssl_calg_aes_gcm:
aead_.reset(new AeadCipherAesGcm());
@@ -114,10 +115,12 @@ bool TlsCipherSpec::Unprotect(const TlsRecordHeader &header,
// Make space.
plaintext->Allocate(ciphertext.len());
+ auto header_bytes = header.header();
size_t len;
bool ret =
- aead_->Aead(true, header.sequence_number(), ciphertext.data(),
- ciphertext.len(), plaintext->data(), &len, plaintext->len());
+ aead_->Aead(true, header_bytes.data(), header_bytes.len(),
+ header.sequence_number(), ciphertext.data(), ciphertext.len(),
+ plaintext->data(), &len, plaintext->len());
if (!ret) return false;
plaintext->Truncate(len);
@@ -133,9 +136,13 @@ bool TlsCipherSpec::Protect(const TlsRecordHeader &header,
ciphertext->Allocate(plaintext.len() +
32); // Room for any plausible auth tag
size_t len;
+
+ DataBuffer header_bytes;
+ (void)header.WriteHeader(&header_bytes, 0, plaintext.len() + 16);
bool ret =
- aead_->Aead(false, header.sequence_number(), plaintext.data(),
- plaintext.len(), ciphertext->data(), &len, ciphertext->len());
+ aead_->Aead(false, header_bytes.data(), header_bytes.len(),
+ header.sequence_number(), plaintext.data(), plaintext.len(),
+ ciphertext->data(), &len, ciphertext->len());
if (!ret) return false;
ciphertext->Truncate(len);
diff --git a/security/nss/gtests/ssl_gtest/tls_protect.h b/security/nss/gtests/ssl_gtest/tls_protect.h
index 93ffd63227..6f129a4eb6 100644
--- a/security/nss/gtests/ssl_gtest/tls_protect.h
+++ b/security/nss/gtests/ssl_gtest/tls_protect.h
@@ -23,8 +23,9 @@ class AeadCipher {
virtual ~AeadCipher();
bool Init(PK11SymKey *key, const uint8_t *iv);
- virtual bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
- uint8_t *out, size_t *outlen, size_t maxlen) = 0;
+ virtual bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len,
+ uint64_t seq, const uint8_t *in, size_t inlen, uint8_t *out,
+ size_t *outlen, size_t maxlen) = 0;
protected:
void FormatNonce(uint64_t seq, uint8_t *nonce);
@@ -42,8 +43,9 @@ class AeadCipherChacha20Poly1305 : public AeadCipher {
AeadCipherChacha20Poly1305() : AeadCipher(CKM_NSS_CHACHA20_POLY1305) {}
protected:
- bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
- uint8_t *out, size_t *outlen, size_t maxlen);
+ bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len, uint64_t seq,
+ const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
+ size_t maxlen);
};
class AeadCipherAesGcm : public AeadCipher {
@@ -51,8 +53,9 @@ class AeadCipherAesGcm : public AeadCipher {
AeadCipherAesGcm() : AeadCipher(CKM_AES_GCM) {}
protected:
- bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,
- uint8_t *out, size_t *outlen, size_t maxlen);
+ bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len, uint64_t seq,
+ const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
+ size_t maxlen);
};
// Our analog of ssl3CipherSpec