diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-08-14 07:52:35 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-08-14 16:42:52 +0200 |
commit | ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9 (patch) | |
tree | 5e4677e52b9a349602f04135a44b3000c8baa97b /security/nss/gtests | |
parent | f44e99950fc25d16a3cdaffe26dadf7b58a9d38c (diff) | |
download | UXP-ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9.tar UXP-ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9.tar.gz UXP-ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9.tar.lz UXP-ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9.tar.xz UXP-ab1060037931158d3a8bf4c8f9f6cb4dbfe916e9.zip |
Update NSS to 3.38
- Added HACL*Poly1305 32-bit (INRIA/Microsoft)
- Updated to final TLS 1.3 draft version (28)
- Removed TLS 1.3 prerelease draft limit check
- Removed NPN code
- Enabled dev/urandom-only RNG on Linux with NSS_SEED_ONLY_DEV_URANDOM for non-standard environments
- Fixed several bugs with TLS 1.3 negotiation
- Updated internal certificate store
- Added support for the TLS Record Size Limit Extension.
- Fixed CVE-2018-0495
- Various security fixes in the ASN.1 code.
Diffstat (limited to 'security/nss/gtests')
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 e6b0c1157..ac9cca83f 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 28921cc94..2d73a4ab5 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 2e6f7f775..603bb6029 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 822df65b3..0e7fb5ed5 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 03f875466..6dc155bef 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 e12714e8d..72dbd5771 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 b14104371..8a12171a0 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 17b4ffe49..e43113de4 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 5d893bab3..8547e56d1 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 000000000..626516389 --- /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 08781af71..28fdc6631 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 f0c57e8b1..6be3b61f8 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 7f2b2840d..e2a30e6bc 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 fa2238be7..ec289bdd6 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 c2f582a93..5be62e506 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 cdafa7a84..b99461632 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 ee8906deb..e5b52ff06 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 3c7cd2ecf..12c6e8516 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 0453dabdb..6965e9ca7 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 f4940bf28..92947c2c7 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 99448321c..f0afc9118 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 e2a8d830a..17677713d 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 05ae87034..77b335e86 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 f1b78f52f..5adbd9dc7 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 3b8727850..53b11c61a 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 000000000..00651aec5 --- /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 eb78c0585..2cc98a327 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 e4a9e5aed..9ef19653b 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 e5fccc12b..ff4091b9a 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 f5ccf096b..42f1065f6 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 7f3c4a896..09d7801e9 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 728217851..d76b3526c 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 dbeb6b9d4..8327373ce 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 2f71caedb..9bed1ce1b 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 6cd6d5073..a93d0c6ee 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 8567b392f..68f6d21e9 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 7dffe7f8a..000494501 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 d34b13bcb..aa03cba70 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 1bbe190ab..effda4aa0 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 6c945f66e..c715a36a6 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 93ffd6322..6f129a4eb 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 |