--- a/old-configure.in
+++ b/old-configure.in
@@ -1910,17 +1910,17 @@ dnl = If NSS was not detected in the sys
dnl = use the one in the source tree (mozilla/security/nss)
dnl ========================================================
MOZ_ARG_WITH_BOOL(system-nss,
[ --with-system-nss Use system installed NSS],
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
- AM_PATH_NSS(3.34, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+ AM_PATH_NSS(3.35, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_SYSTEM_NSS"; then
NSS_LIBS="$NSS_LIBS -lcrmf"
else
NSS_CFLAGS="-I${DIST}/include/nss"
case "${OS_ARCH}" in
# Only few platforms have been tested with GYP
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -70,17 +70,17 @@ namespace {
// does not impact other normal sockets not using the flags.)
//
// Their current definitions are:
//
// bits 0-2 (mask 0x07) specify the max tls version
// 0 means no override 1->4 are 1.0, 1.1, 1.2, 1.3, 4->7 unused
// bits 3-5 (mask 0x38) specify the tls fallback limit
// 0 means no override, values 1->4 match prefs
-// bit 6 (mask 0x40) specifies use of SSL_AltServerHelloType on handshake
+// bit 6 (mask 0x40) specifies use of SSL_AltHandshakeType on handshake
enum {
kTLSProviderFlagMaxVersion10 = 0x01,
kTLSProviderFlagMaxVersion11 = 0x02,
kTLSProviderFlagMaxVersion12 = 0x03,
kTLSProviderFlagMaxVersion13 = 0x04,
};
@@ -89,17 +89,17 @@ static uint32_t getTLSProviderFlagMaxVer
return (flags & 0x07);
}
static uint32_t getTLSProviderFlagFallbackLimit(uint32_t flags)
{
return (flags & 0x38) >> 3;
}
-static bool getTLSProviderFlagAltServerHello(uint32_t flags)
+static bool getTLSProviderFlagAltHandshake(uint32_t flags)
{
return (flags & 0x40);
}
#define MAX_ALPN_LENGTH 255
void
getSiteKey(const nsACString& hostName, uint16_t port,
@@ -2596,23 +2596,23 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
range.max = SSL_LIBRARY_VERSION_TLS_1_3;
} else {
MOZ_LOG(gPIPNSSLog, LogLevel::Error,
("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n",
fd, versionFlags));
}
}
- // enabling alternative server hello
- if (getTLSProviderFlagAltServerHello(infoObject->GetProviderTlsFlags())) {
+ // enabling alternative handshake
+ if (getTLSProviderFlagAltHandshake(infoObject->GetProviderTlsFlags())) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("[%p] nsSSLIOLayerSetOptions: Use AltServerHello\n", fd));
- if (SECSuccess != SSL_UseAltServerHelloType(fd, PR_TRUE)) {
+ ("[%p] nsSSLIOLayerSetOptions: Use AltHandshake\n", fd));
+ if (SECSuccess != SSL_UseAltHandshakeType(fd, PR_TRUE)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Error,
- ("[%p] nsSSLIOLayerSetOptions: Use AltServerHello failed\n", fd));
+ ("[%p] nsSSLIOLayerSetOptions: Use AltHandshake failed\n", fd));
// continue on default path
}
}
if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
(range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to BE_CONSERVATIVE flag\n",
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_34_BETA1
+72ddcd9b1621
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -1,11 +0,0 @@
-Functions changes summary: 0 Removed, 0 Changed, 4 Added functions
-Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
-
-4 Added functions:
-
- 'function SECItem* SEC_CreateSignatureAlgorithmParameters(SECItem*, SECOidTag, SECOidTag, const SECItem*, const SECKEYPrivateKey*)' {SEC_CreateSignatureAlgorithmParameters@@NSS_3.34}
- 'function SECStatus SEC_DerSignDataWithAlgorithmID(SECItem*, const unsigned char*, int, SECKEYPrivateKey*, SECAlgorithmID*)' {SEC_DerSignDataWithAlgorithmID@@NSS_3.34}
- 'function SECStatus SEC_SignDataWithAlgorithmID(SECItem*, const unsigned char*, int, SECKEYPrivateKey*, SECAlgorithmID*)' {SEC_SignDataWithAlgorithmID@@NSS_3.34}
- 'function void SGN_NewContextWithAlgorithmID(SECAlgorithmID*, SECKEYPrivateKey*)' {SGN_NewContextWithAlgorithmID@@NSS_3.34}
-
-
--- a/security/nss/automation/abi-check/expected-report-libssl3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libssl3.so.txt
@@ -1,15 +0,0 @@
-Functions changes summary: 0 Removed, 1 Changed, 0 Added function
-Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
-
-1 function with some indirect sub-type change:
-
- [C]'function SECStatus SSL_GetChannelInfo(SSLChannelInfo*, PRUintn)' at sslinfo.c:26:1 has some indirect sub-type changes:
- parameter 1 of type 'SSLChannelInfo*' has sub-type changes:
- in pointed to type 'typedef SSLChannelInfo' at sslt.h:288:1:
- underlying type 'struct SSLChannelInfoStr' at sslt.h:229:1 changed:
- type size changed from 896 to 960 bits
- 2 data member insertions:
- 'SSLNamedGroup SSLChannelInfoStr::originalKeaGroup', at offset 864 (in bits) at sslt.h:281:1
- 'PRBool SSLChannelInfoStr::resumed', at offset 896 (in bits) at sslt.h:284:1
-
-
--- a/security/nss/automation/abi-check/previous-nss-release
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -1,1 +1,1 @@
-NSS_3_33_BRANCH
+NSS_3_34_BRANCH
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -247,17 +247,17 @@ PrintParameterUsage(void)
fprintf(stderr, "%-20s Require the use of FFDHE supported groups [RFC7919]\n", "-H");
fprintf(stderr, "%-20s Read from a file instead of stdin\n", "-A");
fprintf(stderr, "%-20s Allow 0-RTT data (TLS 1.3 only)\n", "-Z");
fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
"%-20s The following values are valid:\n"
"%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
"-I", "", "");
- fprintf(stderr, "%-20s Enable alternate content type for TLS 1.3 ServerHello\n", "-X alt-server-hello");
+ fprintf(stderr, "%-20s Enable alternative TLS 1.3 handshake\n", "-X alt-server-hello");
}
static void
Usage(const char *progName)
{
PrintUsageHeader(progName);
PrintParameterUsage();
exit(1);
@@ -1178,17 +1178,17 @@ run_client(void)
SECU_PrintError(progName, "error enabling 0-RTT");
error = 1;
goto done;
}
}
/* Alternate ServerHello content type (TLS 1.3 only) */
if (enableAltServerHello) {
- rv = SSL_UseAltServerHelloType(s, PR_TRUE);
+ rv = SSL_UseAltHandshakeType(s, PR_TRUE);
if (rv != SECSuccess) {
SECU_PrintError(progName, "error enabling alternate ServerHello type");
error = 1;
goto done;
}
}
/* require the use of fixed finite-field DH groups */
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
/*
* A dummy header file that is a dependency for all the object files.
* Used to force a full recompilation of NSS in Mozilla's Tinderbox
* depend builds. See comments in rules.mk.
*/
#error "Do not include this header file."
-
--- a/security/nss/gtests/common/util.h
+++ b/security/nss/gtests/common/util.h
@@ -5,17 +5,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef util_h__
#define util_h__
#include <cassert>
#include <vector>
-std::vector<uint8_t> hex_string_to_bytes(std::string s) {
+static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < s.length(); i += 2) {
bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16));
}
return bytes;
}
#endif // util_h__
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -6,16 +6,17 @@ CORE_DEPTH = ../..
DEPTH = ../..
MODULE = nss
CPPSRCS = \
pk11_aeskeywrap_unittest.cc \
pk11_chacha20poly1305_unittest.cc \
pk11_curve25519_unittest.cc \
pk11_ecdsa_unittest.cc \
+ pk11_encrypt_derive_unittest.cc \
pk11_export_unittest.cc \
pk11_pbkdf2_unittest.cc \
pk11_prf_unittest.cc \
pk11_prng_unittest.cc \
pk11_rsapss_unittest.cc \
pk11_der_private_key_import_unittest.cc \
$(NULL)
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
@@ -0,0 +1,210 @@
+/* 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 "pk11pub.h"
+#include "nssutil.h"
+#include <stdio.h>
+#include "prerror.h"
+#include "nss.h"
+#include "gtest/gtest.h"
+#include "scoped_ptrs.h"
+#include "cpputil.h"
+#include "databuffer.h"
+#include "util.h"
+
+#define MAX_KEY_SIZE 24
+
+namespace nss_test {
+
+static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+static const uint8_t kInput[] = {
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc,
+ 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
+
+class EncryptDeriveTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
+ public:
+ void TestEncryptDerive() {
+ ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(),
+ derive_param(), encrypt_mech(),
+ CKA_DECRYPT, keysize()));
+ ASSERT_TRUE(derived_key);
+
+ uint8_t derived_key_data[MAX_KEY_SIZE];
+ ASSERT_GE(sizeof(derived_key_data), keysize());
+ GetKeyData(derived_key, derived_key_data, keysize());
+ RemoveChecksum(derived_key_data);
+
+ uint8_t reference_key_data[MAX_KEY_SIZE];
+ unsigned int reference_len = 0;
+ SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(),
+ reference_key_data, &reference_len, keysize(),
+ kInput, keysize());
+ ASSERT_EQ(SECSuccess, rv);
+ ASSERT_EQ(keysize(), static_cast<size_t>(reference_len));
+ RemoveChecksum(reference_key_data);
+
+ EXPECT_EQ(DataBuffer(reference_key_data, keysize()),
+ DataBuffer(derived_key_data, keysize()));
+ }
+
+ protected:
+ unsigned int keysize() const { return 16; }
+
+ private:
+ CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }
+
+ CK_MECHANISM_TYPE derive_mech() const {
+ switch (encrypt_mech()) {
+ case CKM_DES3_ECB:
+ return CKM_DES3_ECB_ENCRYPT_DATA;
+ case CKM_DES3_CBC:
+ return CKM_DES3_CBC_ENCRYPT_DATA;
+ case CKM_AES_ECB:
+ return CKM_AES_ECB_ENCRYPT_DATA;
+ case CKM_AES_CBC:
+ return CKM_AES_CBC_ENCRYPT_DATA;
+ case CKM_CAMELLIA_ECB:
+ return CKM_CAMELLIA_ECB_ENCRYPT_DATA;
+ case CKM_CAMELLIA_CBC:
+ return CKM_CAMELLIA_CBC_ENCRYPT_DATA;
+ case CKM_SEED_ECB:
+ return CKM_SEED_ECB_ENCRYPT_DATA;
+ case CKM_SEED_CBC:
+ return CKM_SEED_CBC_ENCRYPT_DATA;
+ default:
+ ADD_FAILURE() << "Unknown mechanism";
+ break;
+ }
+ return CKM_INVALID_MECHANISM;
+ }
+
+ SECItem* derive_param() const {
+ static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
+ static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
+ static CK_KEY_DERIVATION_STRING_DATA string_data;
+ static SECItem param = {siBuffer, NULL, 0};
+
+ switch (encrypt_mech()) {
+ case CKM_DES3_ECB:
+ case CKM_AES_ECB:
+ case CKM_CAMELLIA_ECB:
+ case CKM_SEED_ECB:
+ string_data.pData = toUcharPtr(kInput);
+ string_data.ulLen = keysize();
+ param.data = reinterpret_cast<uint8_t*>(&string_data);
+ param.len = sizeof(string_data);
+ break;
+
+ case CKM_DES3_CBC:
+ des_data.pData = toUcharPtr(kInput);
+ des_data.length = keysize();
+ PORT_Memcpy(des_data.iv, kIv, 8);
+ param.data = reinterpret_cast<uint8_t*>(&des_data);
+ param.len = sizeof(des_data);
+ break;
+
+ case CKM_AES_CBC:
+ case CKM_CAMELLIA_CBC:
+ case CKM_SEED_CBC:
+ aes_data.pData = toUcharPtr(kInput);
+ aes_data.length = keysize();
+ PORT_Memcpy(aes_data.iv, kIv, keysize());
+ param.data = reinterpret_cast<uint8_t*>(&aes_data);
+ param.len = sizeof(aes_data);
+ break;
+
+ default:
+ ADD_FAILURE() << "Unknown mechanism";
+ break;
+ }
+ return ¶m;
+ }
+
+ SECItem* encrypt_param() const {
+ static SECItem param = {siBuffer, NULL, 0};
+
+ switch (encrypt_mech()) {
+ case CKM_DES3_ECB:
+ case CKM_AES_ECB:
+ case CKM_CAMELLIA_ECB:
+ case CKM_SEED_ECB:
+ // No parameter needed here.
+ break;
+
+ case CKM_DES3_CBC:
+ case CKM_AES_CBC:
+ case CKM_CAMELLIA_CBC:
+ case CKM_SEED_CBC:
+ param.data = toUcharPtr(kIv);
+ param.len = keysize();
+ break;
+
+ default:
+ ADD_FAILURE() << "Unknown mechanism";
+ break;
+ }
+ return ¶m;
+ }
+
+ virtual void SetUp() {
+ slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
+ ASSERT_TRUE(slot_);
+
+ key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
+ keysize(), NULL,
+ CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
+ ASSERT_TRUE(key_);
+ }
+
+ void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
+ ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
+ SECItem* data = PK11_GetKeyData(key.get());
+ ASSERT_TRUE(data);
+ ASSERT_EQ(max_len, static_cast<size_t>(data->len));
+ PORT_Memcpy(buf, data->data, data->len);
+ }
+
+ // Remove checksum if the key is a 3DES key.
+ void RemoveChecksum(uint8_t* key_data) const {
+ if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
+ return;
+ }
+ for (size_t i = 0; i < keysize(); ++i) {
+ key_data[i] &= 0xfe;
+ }
+ }
+
+ ScopedPK11SlotInfo slot_;
+ ScopedPK11SymKey key_;
+};
+
+TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); }
+
+static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {
+ CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC,
+ CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC, CKM_SEED_ECB, CKM_SEED_CBC};
+
+INSTANTIATE_TEST_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
+ ::testing::ValuesIn(kEncryptDeriveMechanisms));
+
+// This class handles the case where 3DES takes a 192-bit key
+// where all 24 octets will be used.
+class EncryptDerive3Test : public EncryptDeriveTest {
+ protected:
+ unsigned int keysize() const { return 24; }
+};
+
+TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); }
+
+static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
+ CKM_DES3_CBC};
+
+INSTANTIATE_TEST_CASE_P(Encrypt3DeriveTests, EncryptDerive3Test,
+ ::testing::ValuesIn(kDES3EncryptDeriveMechanisms));
+
+} // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -11,16 +11,17 @@
'target_name': 'pk11_gtest',
'type': 'executable',
'sources': [
'pk11_aeskeywrap_unittest.cc',
'pk11_aes_gcm_unittest.cc',
'pk11_chacha20poly1305_unittest.cc',
'pk11_curve25519_unittest.cc',
'pk11_ecdsa_unittest.cc',
+ 'pk11_encrypt_derive_unittest.cc',
'pk11_pbkdf2_unittest.cc',
'pk11_prf_unittest.cc',
'pk11_prng_unittest.cc',
'pk11_rsapss_unittest.cc',
'pk11_der_private_key_import_unittest.cc',
'<(DEPTH)/gtests/common/gtests.cc'
],
'dependencies': [
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -35,22 +35,22 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom
}
ssl3_InitState(ss);
ssl3_RestartHandshakeHashes(ss);
// Ensure we don't overrun hs.client_random.
rnd_len = PR_MIN(SSL3_RANDOM_LENGTH, rnd_len);
- // Zero the client_random struct.
- PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+ // Zero the client_random.
+ PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
// Copy over the challenge bytes.
size_t offset = SSL3_RANDOM_LENGTH - rnd_len;
- PORT_Memcpy(&ss->ssl3.hs.client_random.rand[offset], rnd, rnd_len);
+ PORT_Memcpy(ss->ssl3.hs.client_random + offset, rnd, rnd_len);
// Rehash the SSLv2 client hello message.
return ssl3_UpdateHandshakeHashes(ss, msg, msg_len);
}
PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
sslSocket *ss = ssl_FindSocket(fd);
return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -9,16 +9,17 @@ MODULE = nss
# These sources have access to libssl internals
CSRCS = \
libssl_internals.c \
$(NULL)
CPPSRCS = \
ssl_0rtt_unittest.cc \
ssl_agent_unittest.cc \
+ ssl_alths_unittest.cc \
ssl_auth_unittest.cc \
ssl_cert_ext_unittest.cc \
ssl_ciphersuite_unittest.cc \
ssl_damage_unittest.cc \
ssl_dhe_unittest.cc \
ssl_drop_unittest.cc \
ssl_ecdh_unittest.cc \
ssl_ems_unittest.cc \
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_alths_unittest.cc
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <memory>
+#include <vector>
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+static const uint32_t kServerHelloVersionAlt = SSL_LIBRARY_VERSION_TLS_1_2;
+static const uint16_t kServerHelloVersionRegular =
+ 0x7f00 | TLS_1_3_DRAFT_VERSION;
+
+class AltHandshakeTest : public TlsConnectStreamTls13 {
+ protected:
+ void SetUp() {
+ TlsConnectStreamTls13::SetUp();
+ client_ccs_recorder_ =
+ std::make_shared<TlsRecordRecorder>(kTlsChangeCipherSpecType);
+ server_handshake_recorder_ =
+ std::make_shared<TlsRecordRecorder>(kTlsHandshakeType);
+ server_ccs_recorder_ =
+ std::make_shared<TlsRecordRecorder>(kTlsChangeCipherSpecType);
+ server_hello_recorder_ =
+ std::make_shared<TlsInspectorRecordHandshakeMessage>(
+ kTlsHandshakeServerHello);
+ }
+
+ void SetAltHandshakeTypeEnabled() {
+ client_->SetAltHandshakeTypeEnabled();
+ server_->SetAltHandshakeTypeEnabled();
+ }
+
+ void InstallFilters() {
+ client_->SetPacketFilter(client_ccs_recorder_);
+ auto chain = std::make_shared<ChainedPacketFilter>(ChainedPacketFilterInit(
+ {server_handshake_recorder_, server_ccs_recorder_,
+ server_hello_recorder_}));
+ server_->SetPacketFilter(chain);
+ }
+
+ void CheckServerHelloRecordVersion(uint16_t record_version) {
+ ASSERT_EQ(record_version,
+ server_handshake_recorder_->record(0).header.version());
+ }
+
+ void CheckServerHelloVersion(uint16_t server_hello_version) {
+ uint32_t ver;
+ ASSERT_TRUE(server_hello_recorder_->buffer().Read(0, 2, &ver));
+ ASSERT_EQ(server_hello_version, ver);
+ }
+
+ void CheckForRegularHandshake() {
+ EXPECT_EQ(0U, client_ccs_recorder_->count());
+ EXPECT_EQ(0U, server_ccs_recorder_->count());
+ CheckServerHelloVersion(kServerHelloVersionRegular);
+ CheckServerHelloRecordVersion(SSL_LIBRARY_VERSION_TLS_1_0);
+ }
+
+ void CheckForAltHandshake() {
+ EXPECT_EQ(1U, client_ccs_recorder_->count());
+ EXPECT_EQ(1U, server_ccs_recorder_->count());
+ CheckServerHelloVersion(kServerHelloVersionAlt);
+ CheckServerHelloRecordVersion(SSL_LIBRARY_VERSION_TLS_1_2);
+ }
+
+ std::shared_ptr<TlsRecordRecorder> client_ccs_recorder_;
+ std::shared_ptr<TlsRecordRecorder> server_handshake_recorder_;
+ std::shared_ptr<TlsRecordRecorder> server_ccs_recorder_;
+ std::shared_ptr<TlsInspectorRecordHandshakeMessage> server_hello_recorder_;
+};
+
+TEST_F(AltHandshakeTest, ClientOnly) {
+ client_->SetAltHandshakeTypeEnabled();
+ InstallFilters();
+ Connect();
+ CheckForRegularHandshake();
+}
+
+TEST_F(AltHandshakeTest, ServerOnly) {
+ server_->SetAltHandshakeTypeEnabled();
+ InstallFilters();
+ Connect();
+ CheckForRegularHandshake();
+}
+
+TEST_F(AltHandshakeTest, Enabled) {
+ SetAltHandshakeTypeEnabled();
+ InstallFilters();
+ Connect();
+ CheckForAltHandshake();
+}
+
+TEST_F(AltHandshakeTest, ZeroRtt) {
+ SetAltHandshakeTypeEnabled();
+ SetupForZeroRtt();
+ SetAltHandshakeTypeEnabled();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+
+ InstallFilters();
+
+ ExpectResumption(RESUME_TICKET);
+ ZeroRttSendReceive(true, true);
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ CheckForAltHandshake();
+}
+
+// Neither client nor server has the extension prior to resumption, so the
+// client doesn't send a CCS before its 0-RTT data.
+TEST_F(AltHandshakeTest, DisabledBeforeZeroRtt) {
+ SetupForZeroRtt();
+ SetAltHandshakeTypeEnabled();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+
+ InstallFilters();
+
+ ExpectResumption(RESUME_TICKET);
+ ZeroRttSendReceive(true, true);
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ EXPECT_EQ(0U, client_ccs_recorder_->count());
+ EXPECT_EQ(1U, server_ccs_recorder_->count());
+ CheckServerHelloVersion(kServerHelloVersionAlt);
+}
+
+// Both use the alternative in the initial handshake but only the server enables
+// it on resumption.
+TEST_F(AltHandshakeTest, ClientDisabledAfterZeroRtt) {
+ SetAltHandshakeTypeEnabled();
+ SetupForZeroRtt();
+ server_->SetAltHandshakeTypeEnabled();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+
+ InstallFilters();
+
+ ExpectResumption(RESUME_TICKET);
+ ZeroRttSendReceive(true, true);
+ Handshake();
+ ExpectEarlyDataAccepted(true);
+ CheckConnected();
+
+ CheckForRegularHandshake();
+}
+
+// If the alternative handshake isn't negotiated after 0-RTT, and the client has
+// it enabled, it will send a ChangeCipherSpec. The server chokes on it if it
+// hasn't negotiated the alternative handshake.
+TEST_F(AltHandshakeTest, ServerDisabledAfterZeroRtt) {
+ SetAltHandshakeTypeEnabled();
+ SetupForZeroRtt();
+ client_->SetAltHandshakeTypeEnabled();
+ client_->Set0RttEnabled(true);
+ server_->Set0RttEnabled(true);
+
+ client_->ExpectSendAlert(kTlsAlertEndOfEarlyData);
+ client_->Handshake(); // Send ClientHello (and CCS)
+
+ server_->Handshake(); // Consume the ClientHello, which is OK.
+ client_->ExpectResumption();
+ client_->Handshake(); // Read the server handshake.
+ EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+
+ // Now the server reads the CCS instead of more handshake messages.
+ ExpectAlert(server_, kTlsAlertBadRecordMac);
+ server_->Handshake();
+ EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
+ client_->Handshake(); // Consume the alert.
+ EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
+}
+
+} // nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -1074,20 +1074,16 @@ TEST_P(TlsBogusExtensionTest13, AddBogus
TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
server_->ConfigNamedGroups(groups);
Run(kTlsHandshakeHelloRetryRequest);
}
-TEST_P(TlsBogusExtensionTest13, AddVersionExtensionServerHello) {
- Run(kTlsHandshakeServerHello, ssl_tls13_supported_versions_xtn);
-}
-
TEST_P(TlsBogusExtensionTest13, AddVersionExtensionEncryptedExtensions) {
Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_supported_versions_xtn);
}
TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificate) {
Run(kTlsHandshakeCertificate, ssl_tls13_supported_versions_xtn);
}
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -10,16 +10,17 @@
{
'target_name': 'ssl_gtest',
'type': 'executable',
'sources': [
'libssl_internals.c',
'selfencrypt_unittest.cc',
'ssl_0rtt_unittest.cc',
'ssl_agent_unittest.cc',
+ 'ssl_alths_unittest.cc',
'ssl_auth_unittest.cc',
'ssl_cert_ext_unittest.cc',
'ssl_ciphersuite_unittest.cc',
'ssl_damage_unittest.cc',
'ssl_dhe_unittest.cc',
'ssl_drop_unittest.cc',
'ssl_ecdh_unittest.cc',
'ssl_ems_unittest.cc',
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -6,17 +6,16 @@
#include <functional>
#include <memory>
#include <vector>
#include "secerr.h"
#include "ssl.h"
#include "sslerr.h"
#include "sslproto.h"
-#include "ssl3prot.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
#include "scoped_ptrs.h"
@@ -99,19 +98,19 @@ class HelloTruncator : public TlsHandsha
};
// Verify that when NSS reports that an alert is sent, it is actually sent.
TEST_P(TlsConnectGeneric, CaptureAlertServer) {
client_->SetPacketFilter(std::make_shared<HelloTruncator>());
auto alert_recorder = std::make_shared<TlsAlertRecorder>();
server_->SetPacketFilter(alert_recorder);
- ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+ ConnectExpectAlert(server_, kTlsAlertDecodeError);
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
- EXPECT_EQ(kTlsAlertIllegalParameter, alert_recorder->description());
+ EXPECT_EQ(kTlsAlertDecodeError, alert_recorder->description());
}
TEST_P(TlsConnectGenericPre13, CaptureAlertClient) {
server_->SetPacketFilter(std::make_shared<HelloTruncator>());
auto alert_recorder = std::make_shared<TlsAlertRecorder>();
client_->SetPacketFilter(alert_recorder);
ConnectExpectAlert(client_, kTlsAlertDecodeError);
@@ -302,52 +301,16 @@ TEST_F(TlsConnectStreamTls13, Tls13Faile
TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
client_->SetShortHeadersEnabled();
server_->SetShortHeadersEnabled();
client_->ExpectShortHeaders();
server_->ExpectShortHeaders();
Connect();
}
-TEST_F(TlsConnectStreamTls13, ClientAltHandshakeType) {
- client_->SetAltHandshakeTypeEnabled();
- auto filter = std::make_shared<TlsHeaderRecorder>();
- server_->SetPacketFilter(filter);
- Connect();
- ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
-}
-
-TEST_F(TlsConnectStreamTls13, ServerAltHandshakeType) {
- server_->SetAltHandshakeTypeEnabled();
- auto filter = std::make_shared<TlsHeaderRecorder>();
- server_->SetPacketFilter(filter);
- Connect();
- ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
-}
-
-TEST_F(TlsConnectStreamTls13, BothAltHandshakeType) {
- client_->SetAltHandshakeTypeEnabled();
- server_->SetAltHandshakeTypeEnabled();
- auto header_filter = std::make_shared<TlsHeaderRecorder>();
- auto sh_filter = std::make_shared<TlsInspectorRecordHandshakeMessage>(
- kTlsHandshakeServerHello);
- std::vector<std::shared_ptr<PacketFilter>> filters = {header_filter,
- sh_filter};
- auto chained = std::make_shared<ChainedPacketFilter>(filters);
- server_->SetPacketFilter(chained);
- header_filter->SetAgent(server_.get());
- header_filter->EnableDecryption();
- Connect();
- ASSERT_EQ(kTlsAltHandshakeType, header_filter->header(0)->content_type());
- ASSERT_EQ(kTlsHandshakeType, header_filter->header(1)->content_type());
- uint32_t ver;
- ASSERT_TRUE(sh_filter->buffer().Read(0, 2, &ver));
- ASSERT_EQ((uint32_t)(0x7a00 | TLS_1_3_DRAFT_VERSION), ver);
-}
-
INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGeneric,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGeneric,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus));
--- a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
@@ -5,16 +5,18 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nss.h"
#include "ssl.h"
#include "sslimpl.h"
#include "databuffer.h"
#include "gtest_utils.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
namespace nss_test {
const static size_t kMacSize = 20;
class TlsPaddingTest
: public ::testing::Test,
public ::testing::WithParamInterface<std::tuple<size_t, bool>> {
@@ -46,18 +48,18 @@ class TlsPaddingTest
}
void Unpad(bool expect_success) {
std::cerr << "Content length=" << plaintext_len_
<< " padding length=" << pad_len_
<< " total length=" << plaintext_.len() << std::endl;
std::cerr << "Plaintext: " << plaintext_ << std::endl;
sslBuffer s;
- s.buf = const_cast<unsigned char *>(
- static_cast<const unsigned char *>(plaintext_.data()));
+ s.buf = const_cast<unsigned char*>(
+ static_cast<const unsigned char*>(plaintext_.data()));
s.len = plaintext_.len();
SECStatus rv = ssl_RemoveTLSCBCPadding(&s, kMacSize);
if (expect_success) {
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(plaintext_len_, static_cast<size_t>(s.len));
} else {
EXPECT_EQ(SECFailure, rv);
}
@@ -94,16 +96,85 @@ TEST_P(TlsPaddingTest, FirstByteOfPadWro
TEST_P(TlsPaddingTest, LastByteOfPadWrong) {
if (pad_len_) {
plaintext_.Write(plaintext_.len() - 2,
plaintext_.data()[plaintext_.len() - 1] + 1, 1);
Unpad(false);
}
}
+class RecordReplacer : public TlsRecordFilter {
+ public:
+ RecordReplacer(size_t size)
+ : TlsRecordFilter(), enabled_(false), size_(size) {}
+
+ 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_);
+
+ for (size_t i = 0; i < size_; ++i) {
+ changed->data()[i] = i & 0xff;
+ }
+
+ enabled_ = false;
+ return CHANGE;
+ }
+
+ void Enable() { enabled_ = true; }
+
+ private:
+ bool enabled_;
+ size_t size_;
+};
+
+TEST_F(TlsConnectStreamTls13, LargeRecord) {
+ EnsureTlsSetup();
+
+ const size_t record_limit = 16384;
+ auto replacer = std::make_shared<RecordReplacer>(record_limit);
+ client_->SetTlsRecordFilter(replacer);
+ replacer->EnableDecryption();
+ Connect();
+
+ replacer->Enable();
+ client_->SendData(10);
+ WAIT_(server_->received_bytes() == record_limit, 2000);
+ ASSERT_EQ(record_limit, server_->received_bytes());
+}
+
+TEST_F(TlsConnectStreamTls13, TooLargeRecord) {
+ EnsureTlsSetup();
+
+ const size_t record_limit = 16384;
+ auto replacer = std::make_shared<RecordReplacer>(record_limit + 1);
+ client_->SetTlsRecordFilter(replacer);
+ replacer->EnableDecryption();
+ Connect();
+
+ replacer->Enable();
+ ExpectAlert(server_, kTlsAlertRecordOverflow);
+ client_->SendData(10); // This is expanded.
+
+ uint8_t buf[record_limit + 2];
+ PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+ EXPECT_GT(0, rv);
+ EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, PORT_GetError());
+
+ // Read the server alert.
+ rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
+ EXPECT_GT(0, rv);
+ EXPECT_EQ(SSL_ERROR_RECORD_OVERFLOW_ALERT, PORT_GetError());
+}
+
const static size_t kContentSizesArr[] = {
1, kMacSize - 1, kMacSize, 30, 31, 32, 36, 256, 257, 287, 288};
auto kContentSizes = ::testing::ValuesIn(kContentSizesArr);
const static bool kTrueFalseArr[] = {true, false};
auto kTrueFalse = ::testing::ValuesIn(kTrueFalseArr);
INSTANTIATE_TEST_CASE_P(TlsPadding, TlsPaddingTest,
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -382,17 +382,17 @@ void TlsAgent::SetShortHeadersEnabled()
SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd());
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SetAltHandshakeTypeEnabled() {
EXPECT_TRUE(EnsureTlsSetup());
- SECStatus rv = SSL_UseAltServerHelloType(ssl_fd(), true);
+ SECStatus rv = SSL_UseAltHandshakeType(ssl_fd(), PR_TRUE);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
vrange_.min = minver;
vrange_.max = maxver;
if (ssl_fd()) {
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -358,16 +358,25 @@ PacketFilter::Action TlsInspectorReplace
if (header.handshake_type() == handshake_type_) {
*output = buffer_;
return CHANGE;
}
return KEEP;
}
+PacketFilter::Action TlsRecordRecorder::FilterRecord(
+ const TlsRecordHeader& header, const DataBuffer& input,
+ DataBuffer* output) {
+ if (!filter_ || (header.content_type() == ct_)) {
+ records_.push_back({header, input});
+ }
+ return KEEP;
+}
+
PacketFilter::Action TlsConversationRecorder::FilterRecord(
const TlsRecordHeader& header, const DataBuffer& input,
DataBuffer* output) {
buffer_.Append(input);
return KEEP;
}
PacketFilter::Action TlsHeaderRecorder::FilterRecord(
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -58,16 +58,21 @@ class TlsRecordHeader : public TlsVersio
// Return the offset of the end of the write.
size_t Write(DataBuffer* buffer, size_t offset, const DataBuffer& body) const;
private:
uint8_t content_type_;
uint64_t sequence_number_;
};
+struct TlsRecord {
+ const TlsRecordHeader header;
+ const DataBuffer buffer;
+};
+
// Abstract filter that operates on entire (D)TLS records.
class TlsRecordFilter : public PacketFilter {
public:
TlsRecordFilter() : agent_(nullptr), count_(0), cipher_spec_() {}
void SetAgent(const TlsAgent* agent) { agent_ = agent; }
const TlsAgent* agent() const { return agent_; }
@@ -216,16 +221,38 @@ class TlsInspectorReplaceHandshakeMessag
const DataBuffer& input,
DataBuffer* output);
private:
uint8_t handshake_type_;
DataBuffer buffer_;
};
+class TlsRecordRecorder : public TlsRecordFilter {
+ public:
+ TlsRecordRecorder(uint8_t ct) : filter_(true), ct_(ct), records_() {}
+ TlsRecordRecorder()
+ : filter_(false),
+ ct_(content_handshake), // dummy (<optional> is C++14)
+ records_() {}
+ virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output);
+
+ size_t count() const { return records_.size(); }
+ void Clear() { records_.clear(); }
+
+ const TlsRecord& record(size_t i) const { return records_[i]; }
+
+ private:
+ bool filter_;
+ uint8_t ct_;
+ std::vector<TlsRecord> records_;
+};
+
// Make a copy of the complete conversation.
class TlsConversationRecorder : public TlsRecordFilter {
public:
TlsConversationRecorder(DataBuffer& buffer) : buffer_(buffer) {}
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output);
@@ -242,21 +269,26 @@ class TlsHeaderRecorder : public TlsReco
DataBuffer* output);
const TlsRecordHeader* header(size_t index);
private:
std::vector<TlsRecordHeader> headers_;
};
// Runs multiple packet filters in series.
+typedef std::initializer_list<std::shared_ptr<PacketFilter>>
+ ChainedPacketFilterInit;
+
+// Runs multiple packet filters in series.
class ChainedPacketFilter : public PacketFilter {
public:
ChainedPacketFilter() {}
ChainedPacketFilter(const std::vector<std::shared_ptr<PacketFilter>> filters)
: filters_(filters.begin(), filters.end()) {}
+ ChainedPacketFilter(ChainedPacketFilterInit il) : filters_(il) {}
virtual ~ChainedPacketFilter() {}
virtual PacketFilter::Action Filter(const DataBuffer& input,
DataBuffer* output);
// Takes ownership of the filter.
void Add(std::shared_ptr<PacketFilter> filter) { filters_.push_back(filter); }
--- a/security/nss/lib/freebl/poly1305.h
+++ b/security/nss/lib/freebl/poly1305.h
@@ -3,16 +3,18 @@
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FREEBL_POLY1305_H_
#define FREEBL_POLY1305_H_
+#include "stddef.h"
+
typedef unsigned char poly1305_state[512];
/* Poly1305Init sets up |state| so that it can be used to calculate an
* authentication tag with the one-time key |key|. Note that |key| is a
* one-time key and therefore there is no `reset' method because that would
* enable several messages to be authenticated with the same key. */
extern void Poly1305Init(poly1305_state* state, const unsigned char key[32]);
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,19 +17,19 @@
/*
* NSS's major version, minor version, patch level, build number, and whether
* this is a beta release.
*
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define NSS_VERSION "3.34" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION "3.35" _NSS_CUSTOMIZED " Beta"
#define NSS_VMAJOR 3
-#define NSS_VMINOR 34
+#define NSS_VMINOR 35
#define NSS_VPATCH 0
#define NSS_VBUILD 0
#define NSS_BETA PR_TRUE
#ifndef RC_INVOKED
#include "seccomon.h"
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -416,21 +416,30 @@ static const struct mechanismList mechan
{ CKM_IDEA_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_IDEA_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_IDEA_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
{ CKM_IDEA_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
{ CKM_IDEA_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
#endif
/* --------------------- Secret Key Operations ------------------------ */
{ CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
- { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_GENERATE }, PR_FALSE },
- { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
- { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_GENERATE }, PR_FALSE },
- { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
+ { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
{ CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_AES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_CAMELLIA_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_CAMELLIA_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_SEED_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+ { CKM_SEED_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+
/* ---------------------- SSL Key Derivations ------------------------- */
{ CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
{ CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
{ CKM_SSL3_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
{ CKM_SSL3_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
{ CKM_SSL3_MD5_MAC, { 0, 16, CKF_DERIVE }, PR_FALSE },
{ CKM_SSL3_SHA1_MAC, { 0, 20, CKF_DERIVE }, PR_FALSE },
{ CKM_MD5_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -1519,18 +1519,17 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSes
rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
maxout, context->padBuf, context->blockSize);
if (rv != SECSuccess)
return sftk_MapDecryptError(PORT_GetError());
pPart += padoutlen;
maxout -= padoutlen;
}
/* now save the final block for the next decrypt or the final */
- PORT_Memcpy(context->padBuf, &pEncryptedPart[ulEncryptedPartLen -
- context->blockSize],
+ PORT_Memcpy(context->padBuf, &pEncryptedPart[ulEncryptedPartLen - context->blockSize],
context->blockSize);
context->padDataLength = context->blockSize;
ulEncryptedPartLen -= context->padDataLength;
}
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pPart, &outlen,
maxout, pEncryptedPart, ulEncryptedPartLen);
@@ -6237,16 +6236,53 @@ sftk_ANSI_X9_63_kdf(CK_BYTE **key, CK_UL
else if (kdf == CKD_SHA512_KDF)
return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo,
SharedInfoLen, SHA512_HashBuf, SHA512_LENGTH);
else
return CKR_MECHANISM_INVALID;
}
/*
+ * Handle the derive from a block encryption cipher
+ */
+CK_RV
+sftk_DeriveEncrypt(SFTKCipher encrypt, void *cipherInfo,
+ int blockSize, SFTKObject *key, CK_ULONG keySize,
+ unsigned char *data, CK_ULONG len)
+{
+ /* large enough for a 512-bit key */
+ unsigned char tmpdata[SFTK_MAX_DERIVE_KEY_SIZE];
+ SECStatus rv;
+ unsigned int outLen;
+ CK_RV crv;
+
+ if ((len % blockSize) != 0) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ if (len > SFTK_MAX_DERIVE_KEY_SIZE) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ if (keySize && (len < keySize)) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ if (keySize == 0) {
+ keySize = len;
+ }
+
+ rv = (*encrypt)(cipherInfo, &tmpdata, &outLen, len, data, len);
+ if (rv != SECSuccess) {
+ crv = sftk_MapCryptError(PORT_GetError());
+ return crv;
+ }
+
+ crv = sftk_forceAttribute(key, CKA_VALUE, tmpdata, keySize);
+ return crv;
+}
+
+/*
* SSL Key generation given pre master secret
*/
#define NUM_MIXERS 9
static const char *const mixers[NUM_MIXERS] = {
"A",
"BB",
"CCC",
"DDDD",
@@ -6894,16 +6930,182 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
}
MD5_DestroyContext(md5, PR_TRUE);
SHA1_DestroyContext(sha, PR_TRUE);
sftk_FreeObject(key);
key = NULL;
break;
}
+ case CKM_DES3_ECB_ENCRYPT_DATA:
+ case CKM_DES3_CBC_ENCRYPT_DATA: {
+ void *cipherInfo;
+ unsigned char des3key[MAX_DES3_KEY_SIZE];
+ CK_DES_CBC_ENCRYPT_DATA_PARAMS *desEncryptPtr;
+ int mode;
+ unsigned char *iv;
+ unsigned char *data;
+ CK_ULONG len;
+
+ if (mechanism == CKM_DES3_ECB_ENCRYPT_DATA) {
+ stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+ pMechanism->pParameter;
+ mode = NSS_DES_EDE3;
+ iv = NULL;
+ data = stringPtr->pData;
+ len = stringPtr->ulLen;
+ } else {
+ mode = NSS_DES_EDE3_CBC;
+ desEncryptPtr =
+ (CK_DES_CBC_ENCRYPT_DATA_PARAMS *)
+ pMechanism->pParameter;
+ iv = desEncryptPtr->iv;
+ data = desEncryptPtr->pData;
+ len = desEncryptPtr->length;
+ }
+ if (att->attrib.ulValueLen == 16) {
+ PORT_Memcpy(des3key, att->attrib.pValue, 16);
+ PORT_Memcpy(des3key + 16, des3key, 8);
+ } else if (att->attrib.ulValueLen == 24) {
+ PORT_Memcpy(des3key, att->attrib.pValue, 24);
+ } else {
+ crv = CKR_KEY_SIZE_RANGE;
+ break;
+ }
+ cipherInfo = DES_CreateContext(des3key, iv, mode, PR_TRUE);
+ PORT_Memset(des3key, 0, 24);
+ if (cipherInfo == NULL) {
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ crv = sftk_DeriveEncrypt((SFTKCipher)DES_Encrypt,
+ cipherInfo, 8, key, keySize,
+ data, len);
+ DES_DestroyContext(cipherInfo, PR_TRUE);
+ break;
+ }
+
+ case CKM_AES_ECB_ENCRYPT_DATA:
+ case CKM_AES_CBC_ENCRYPT_DATA: {
+ void *cipherInfo;
+ CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+ int mode;
+ unsigned char *iv;
+ unsigned char *data;
+ CK_ULONG len;
+
+ if (mechanism == CKM_AES_ECB_ENCRYPT_DATA) {
+ mode = NSS_AES;
+ iv = NULL;
+ stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
+ data = stringPtr->pData;
+ len = stringPtr->ulLen;
+ } else {
+ aesEncryptPtr =
+ (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)pMechanism->pParameter;
+ mode = NSS_AES_CBC;
+ iv = aesEncryptPtr->iv;
+ data = aesEncryptPtr->pData;
+ len = aesEncryptPtr->length;
+ }
+
+ cipherInfo = AES_CreateContext((unsigned char *)att->attrib.pValue,
+ iv, mode, PR_TRUE,
+ att->attrib.ulValueLen, 16);
+ if (cipherInfo == NULL) {
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ crv = sftk_DeriveEncrypt((SFTKCipher)AES_Encrypt,
+ cipherInfo, 16, key, keySize,
+ data, len);
+ AES_DestroyContext(cipherInfo, PR_TRUE);
+ break;
+ }
+
+ case CKM_CAMELLIA_ECB_ENCRYPT_DATA:
+ case CKM_CAMELLIA_CBC_ENCRYPT_DATA: {
+ void *cipherInfo;
+ CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+ int mode;
+ unsigned char *iv;
+ unsigned char *data;
+ CK_ULONG len;
+
+ if (mechanism == CKM_CAMELLIA_ECB_ENCRYPT_DATA) {
+ stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+ pMechanism->pParameter;
+ aesEncryptPtr = NULL;
+ mode = NSS_CAMELLIA;
+ data = stringPtr->pData;
+ len = stringPtr->ulLen;
+ iv = NULL;
+ } else {
+ stringPtr = NULL;
+ aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
+ pMechanism->pParameter;
+ mode = NSS_CAMELLIA_CBC;
+ iv = aesEncryptPtr->iv;
+ data = aesEncryptPtr->pData;
+ len = aesEncryptPtr->length;
+ }
+
+ cipherInfo = Camellia_CreateContext((unsigned char *)att->attrib.pValue,
+ iv, mode, PR_TRUE,
+ att->attrib.ulValueLen);
+ if (cipherInfo == NULL) {
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ crv = sftk_DeriveEncrypt((SFTKCipher)Camellia_Encrypt,
+ cipherInfo, 16, key, keySize,
+ data, len);
+ Camellia_DestroyContext(cipherInfo, PR_TRUE);
+ break;
+ }
+
+ case CKM_SEED_ECB_ENCRYPT_DATA:
+ case CKM_SEED_CBC_ENCRYPT_DATA: {
+ void *cipherInfo;
+ CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+ int mode;
+ unsigned char *iv;
+ unsigned char *data;
+ CK_ULONG len;
+
+ if (mechanism == CKM_SEED_ECB_ENCRYPT_DATA) {
+ mode = NSS_SEED;
+ stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+ pMechanism->pParameter;
+ aesEncryptPtr = NULL;
+ data = stringPtr->pData;
+ len = stringPtr->ulLen;
+ iv = NULL;
+ } else {
+ mode = NSS_SEED_CBC;
+ aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
+ pMechanism->pParameter;
+ iv = aesEncryptPtr->iv;
+ data = aesEncryptPtr->pData;
+ len = aesEncryptPtr->length;
+ }
+
+ cipherInfo = SEED_CreateContext((unsigned char *)att->attrib.pValue,
+ iv, mode, PR_TRUE);
+ if (cipherInfo == NULL) {
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ crv = sftk_DeriveEncrypt((SFTKCipher)SEED_Encrypt,
+ cipherInfo, 16, key, keySize,
+ data, len);
+ SEED_DestroyContext(cipherInfo, PR_TRUE);
+ break;
+ }
+
case CKM_CONCATENATE_BASE_AND_KEY: {
SFTKObject *newKey;
crv = sftk_DeriveSensitiveCheck(sourceKey, key);
if (crv != CKR_OK)
break;
session = sftk_SessionFromHandle(hSession);
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
/*
* Softoken's major version, minor version, patch level, build number,
* and whether this is a beta release.
*
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define SOFTOKEN_VERSION "3.34" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION "3.35" SOFTOKEN_ECC_STRING " Beta"
#define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 34
+#define SOFTOKEN_VMINOR 35
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_TRUE
#endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/softoken/softoknt.h
+++ b/security/nss/lib/softoken/softoknt.h
@@ -4,16 +4,19 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _SOFTOKNT_H_
#define _SOFTOKNT_H_
#define NSS_SOFTOKEN_DEFAULT_CHUNKSIZE 2048
+#define DES_BLOCK_SIZE 8 /* bytes */
+#define MAX_DES3_KEY_SIZE 24 /* DES_BLOCK_SIZE * 3 */
+#define SFTK_MAX_DERIVE_KEY_SIZE 64
/*
* FIPS 140-2 auditing
*/
typedef enum {
NSS_AUDIT_ERROR = 3, /* errors */
NSS_AUDIT_WARNING = 2, /* warning messages */
NSS_AUDIT_INFO = 1 /* informational messages */
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1,9 +1,8 @@
-
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* SSL3 Protocol
*
* 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/. */
@@ -1042,16 +1041,29 @@ Null_Cipher(void *ctx, unsigned char *ou
}
return SECSuccess;
}
/*
* SSL3 Utility functions
*/
+static void
+ssl_SetSpecVersions(sslSocket *ss, ssl3CipherSpec *spec)
+{
+ spec->version = ss->version;
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ tls13_SetSpecRecordVersion(ss, spec);
+ } else if (IS_DTLS(ss)) {
+ spec->recordVersion = dtls_TLSVersionToDTLSVersion(ss->version);
+ } else {
+ spec->recordVersion = ss->version;
+ }
+}
+
/* allowLargerPeerVersion controls whether the function will select the
* highest enabled SSL version or fail when peerVersion is greater than the
* highest enabled version.
*
* If allowLargerPeerVersion is true, peerVersion is the peer's highest
* enabled version rather than the peer's selected version.
*/
SECStatus
@@ -1091,49 +1103,48 @@ ssl_ClientReadVersion(sslSocket *ss, PRU
}
#ifdef TLS_1_3_DRAFT_VERSION
if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
(void)SSL3_SendAlert(ss, alert_fatal, protocol_version);
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
- if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3) || (ss->opt.enableAltHandshaketype &&
- (temp == tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)))) {
+ if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
+ v = SSL_LIBRARY_VERSION_TLS_1_3;
+ } else if (temp == tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
+ if (!ss->opt.enableAltHandshaketype || IS_DTLS(ss)) {
+ (void)SSL3_SendAlert(ss, alert_fatal, protocol_version);
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ return SECFailure;
+ }
+ ss->ssl3.hs.altHandshakeType = PR_TRUE;
v = SSL_LIBRARY_VERSION_TLS_1_3;
} else {
v = (SSL3ProtocolVersion)temp;
}
#else
v = (SSL3ProtocolVersion)temp;
#endif
if (IS_DTLS(ss)) {
/* If this fails, we get 0 back and the next check to fails. */
v = dtls_DTLSVersionToTLSVersion(v);
}
- PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange));
- if (ss->vrange.min > v || ss->vrange.max < v) {
- (void)SSL3_SendAlert(ss, alert_fatal,
- (v > SSL_LIBRARY_VERSION_3_0) ? protocol_version
- : handshake_failure);
- PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
- return SECFailure;
- }
*version = v;
return SECSuccess;
}
static SECStatus
-ssl3_GetNewRandom(SSL3Random *random)
+ssl3_GetNewRandom(SSL3Random random)
{
SECStatus rv;
- rv = PK11_GenerateRandom(random->rand, SSL3_RANDOM_LENGTH);
+ rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
}
return rv;
}
/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
SECStatus
@@ -1447,19 +1458,19 @@ ssl3_ComputeDHKeyHash(sslSocket *ss, SSL
hashBuf = buf;
} else {
hashBuf = PORT_Alloc(bufLen);
if (!hashBuf) {
return SECFailure;
}
}
- memcpy(hashBuf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
+ memcpy(hashBuf, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
pBuf = hashBuf + SSL3_RANDOM_LENGTH;
- memcpy(pBuf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
+ memcpy(pBuf, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
pBuf += SSL3_RANDOM_LENGTH;
pBuf = ssl_EncodeUintX(dh_p.len, 2, pBuf);
memcpy(pBuf, dh_p.data, dh_p.len);
pBuf += dh_p.len;
pBuf = ssl_EncodeUintX(dh_g.len, 2, pBuf);
memcpy(pBuf, dh_g.data, dh_g.len);
pBuf += dh_g.len;
pBuf = ssl_EncodeUintX(yLen, 2, pBuf);
@@ -1575,17 +1586,17 @@ ssl3_SetupPendingCipherSpec(sslSocket *s
/* This hack provides maximal interoperability with SSL 3 servers. */
cwSpec = ss->ssl3.cwSpec;
if (cwSpec->mac_def->mac == mac_null) {
/* SSL records are not being MACed. */
cwSpec->version = ss->version;
}
- pwSpec->version = ss->version;
+ ssl_SetSpecVersions(ss, ss->ssl3.pwSpec);
isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x",
SSL_GETPID(), ss->fd, suite));
suite_def = ssl_LookupCipherSuiteDef(suite);
if (suite_def == NULL) {
ssl_ReleaseSpecWriteLock(ss);
@@ -1770,61 +1781,58 @@ ssl3_InitCompressionContext(ssl3CipherSp
}
/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data
* which is included in the MAC or AEAD additional data) to |out| and returns
* its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
* definition of the AEAD additional data.
*
* TLS pseudo-header includes the record's version field, SSL's doesn't. Which
- * pseudo-header defintiion to use should be decided based on the version of
+ * pseudo-header definition to use should be decided based on the version of
* the protocol that was negotiated when the cipher spec became current, NOT
* based on the version value in the record itself, and the decision is passed
* to this function as the |includesVersion| argument. But, the |version|
* argument should be the record's version value.
*/
-static unsigned int
-ssl3_BuildRecordPseudoHeader(unsigned char *out,
+static SECStatus
+ssl3_BuildRecordPseudoHeader(PRUint8 *out, DTLSEpoch epoch,
sslSequenceNumber seq_num,
SSL3ContentType type,
PRBool includesVersion,
SSL3ProtocolVersion version,
PRBool isDTLS,
int length)
{
- out[0] = (unsigned char)(seq_num >> 56);
- out[1] = (unsigned char)(seq_num >> 48);
+ if (isDTLS) {
+ out[0] = (unsigned char)(epoch >> 8);
+ out[1] = (unsigned char)(epoch >> 0);
+ } else {
+ out[0] = (unsigned char)(seq_num >> 56);
+ out[1] = (unsigned char)(seq_num >> 48);
+ }
out[2] = (unsigned char)(seq_num >> 40);
out[3] = (unsigned char)(seq_num >> 32);
out[4] = (unsigned char)(seq_num >> 24);
out[5] = (unsigned char)(seq_num >> 16);
out[6] = (unsigned char)(seq_num >> 8);
out[7] = (unsigned char)(seq_num >> 0);
out[8] = type;
/* SSL3 MAC doesn't include the record's version field. */
if (!includesVersion) {
out[9] = MSB(length);
out[10] = LSB(length);
return 11;
}
-
/* TLS MAC and AEAD additional data include version. */
- if (isDTLS) {
- SSL3ProtocolVersion dtls_version;
-
- dtls_version = dtls_TLSVersionToDTLSVersion(version);
- out[9] = MSB(dtls_version);
- out[10] = LSB(dtls_version);
- } else {
- out[9] = MSB(version);
- out[10] = LSB(version);
- }
+ out[9] = MSB(version);
+ out[10] = LSB(version);
out[11] = MSB(length);
out[12] = LSB(length);
+ PRINT_BUF(50, (NULL, "Pseudoheader", out, 13));
return 13;
}
static SECStatus
ssl3_AESGCM(ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
int *outlen,
@@ -2368,17 +2376,16 @@ ssl3_ClientAuthTokenPresent(sslSessionID
return isPresent;
}
/* Caller must hold the spec read lock. */
SECStatus
ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec,
PRBool isServer,
PRBool isDTLS,
- PRBool capRecordVersion,
SSL3ContentType type,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf)
{
const ssl3BulkCipherDef *cipher_def;
SECStatus rv;
PRUint32 macLen = 0;
@@ -2425,18 +2432,18 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
&outlen, wrBuf->space - ivLen, pIn, contentLen);
if (rv != SECSuccess)
return rv;
pIn = wrBuf->buf + ivLen;
contentLen = outlen;
}
pseudoHeaderLen = ssl3_BuildRecordPseudoHeader(
- pseudoHeader, cwSpec->write_seq_num, type,
- cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version,
+ pseudoHeader, cwSpec->epoch, cwSpec->write_seq_num, type,
+ cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion,
isDTLS, contentLen);
PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader));
if (cipher_def->type == type_aead) {
const int nonceLen = cipher_def->explicit_nonce_size;
const int tagLen = cipher_def->tag_size;
if (nonceLen + contentLen + tagLen > wrBuf->space) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -2537,24 +2544,22 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
wrBuf->len += cipherBytesPart2;
}
}
return SECSuccess;
}
SECStatus
-ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
- PRBool capRecordVersion, SSL3ContentType type,
+ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
{
const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
PRUint16 headerLen;
sslBuffer protBuf;
- SSL3ProtocolVersion version = cwSpec->version;
PRBool isTLS13;
PRUint8 *ptr = wrBuf->buf;
SECStatus rv;
if (ss->ssl3.hs.shortHeaders) {
PORT_Assert(!IS_DTLS(ss));
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
headerLen = TLS13_RECORD_HEADER_LENGTH_SHORT;
@@ -2578,17 +2583,17 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
#ifdef UNSAFE_FUZZER_MODE
rv = Null_Cipher(NULL, protBuf.buf, (int *)&protBuf.len, protBuf.space,
pIn, contentLen);
#else
if (isTLS13) {
rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf);
} else {
rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer,
- IS_DTLS(ss), capRecordVersion, type,
+ IS_DTLS(ss), type,
pIn, contentLen, &protBuf);
}
#endif
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024));
@@ -2602,35 +2607,27 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
if (isTLS13 && cipher_def->calg != ssl_calg_null) {
*ptr++ = content_application_data;
} else
#endif
{
*ptr++ = type;
}
+ ptr = ssl_EncodeUintX(cwSpec->recordVersion, 2, ptr);
if (IS_DTLS(ss)) {
- version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
- version = dtls_TLSVersionToDTLSVersion(version);
-
- ptr = ssl_EncodeUintX(version, 2, ptr);
- ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr);
- } else {
- if (capRecordVersion || isTLS13) {
- version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
- }
- ptr = ssl_EncodeUintX(version, 2, ptr);
+ ptr = ssl_EncodeUintX(cwSpec->epoch, 2, ptr);
+ ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 6, ptr);
}
(void)ssl_EncodeUintX(protBuf.len, 2, ptr);
}
++cwSpec->write_seq_num;
return SECSuccess;
}
-
/* Process the plain text before sending it.
* Returns the number of bytes of plaintext that were successfully sent
* plus the number of bytes of plaintext that were copied into the
* output (write) buffer.
* Returns SECFailure on a hard IO error, memory error, or crypto error.
* Does NOT return SECWouldBlock.
*
* Notes on the use of the private ssl flags:
@@ -2641,65 +2638,43 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
* then buffer remaining bytes of ciphertext into pending buf,
* and continue to do that for all succssive records until all
* bytes are used.
* ssl_SEND_FLAG_FORCE_INTO_BUFFER
* As above, except this suppresses all write attempts, and forces
* all ciphertext into the pending ciphertext buffer.
* ssl_SEND_FLAG_USE_EPOCH (for DTLS)
* Forces the use of the provided epoch
- * ssl_SEND_FLAG_CAP_RECORD_VERSION
- * Caps the record layer version number of TLS ClientHello to { 3, 1 }
- * (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore
- * ClientHello.client_version and use the record layer version number
- * (TLSPlaintext.version) instead when negotiating protocol versions. In
- * addition, if the record layer version number of ClientHello is { 3, 2 }
- * (TLS 1.1) or higher, these servers reset the TCP connections. Lastly,
- * some F5 BIG-IP servers hang if a record containing a ClientHello has a
- * version greater than { 3, 1 } and a length greater than 255. Set this
- * flag to work around such servers.
*/
PRInt32
ssl3_SendRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */
SSL3ContentType type,
const PRUint8 *pIn, /* input buffer */
PRInt32 nIn, /* bytes of input */
PRInt32 flags)
{
sslBuffer *wrBuf = &ss->sec.writeBuf;
SECStatus rv;
PRInt32 totalSent = 0;
- PRBool capRecordVersion;
ssl3CipherSpec *spec;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
nIn));
PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
return SECFailure;
}
- capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
-
- if (capRecordVersion) {
- /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
- * TLS initial ClientHello. */
- PORT_Assert(!IS_DTLS(ss));
- PORT_Assert(!ss->firstHsDone);
- PORT_Assert(type == content_handshake);
- PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
- }
-
if (ss->ssl3.initialized == PR_FALSE) {
/* This can happen on a server if the very first incoming record
** looks like a defective ssl3 record (e.g. too long), and we're
** trying to send an alert.
*/
PR_ASSERT(type == content_alert);
ssl3_InitState(ss);
}
@@ -2740,29 +2715,29 @@ ssl3_SendRecord(sslSocket *ss,
SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
SSL_GETPID(), ss->fd, spaceNeeded));
goto spec_locked_loser; /* sslBuffer_Grow set error code. */
}
}
if (numRecords == 2) {
sslBuffer secondRecord;
- rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
+ rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, type,
pIn, 1, wrBuf);
if (rv != SECSuccess)
goto spec_locked_loser;
PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
wrBuf->buf, wrBuf->len));
secondRecord.buf = wrBuf->buf + wrBuf->len;
secondRecord.len = 0;
secondRecord.space = wrBuf->space - wrBuf->len;
- rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
+ rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, type,
pIn + 1, contentLen - 1, &secondRecord);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
secondRecord.buf, secondRecord.len));
wrBuf->len += secondRecord.len;
}
} else {
if (cwSpec) {
@@ -2771,18 +2746,17 @@ ssl3_SendRecord(sslSocket *ss,
PORT_Assert(IS_DTLS(ss) &&
(type == content_handshake ||
type == content_change_cipher_spec));
spec = cwSpec;
} else {
spec = ss->ssl3.cwSpec;
}
- rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion,
- type, pIn, contentLen, wrBuf);
+ rv = ssl_ProtectRecord(ss, spec, type, pIn, contentLen, wrBuf);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data:",
wrBuf->buf, wrBuf->len));
}
}
spec_locked_loser:
ssl_ReleaseSpecReadLock(ss); /************************************/
@@ -2975,40 +2949,33 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt
* This function returns SECSuccess or SECFailure, never SECWouldBlock.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Called from ssl3_FlushHandshake
*/
static SECStatus
ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
{
- static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER |
- ssl_SEND_FLAG_CAP_RECORD_VERSION;
+ static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
PRInt32 count = -1;
SECStatus rv;
- SSL3ContentType ct = content_handshake;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
return SECSuccess;
/* only these flags are allowed */
PORT_Assert(!(flags & ~allowedFlags));
if ((flags & ~allowedFlags) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- /* Maybe send the first message with alt handshake type. */
- if (ss->ssl3.hs.altHandshakeType) {
- ct = content_alt_handshake;
- ss->ssl3.hs.altHandshakeType = PR_FALSE;
- }
- count = ssl3_SendRecord(ss, NULL, ct,
+ count = ssl3_SendRecord(ss, NULL, content_handshake,
ss->sec.ci.sendBuf.buf,
ss->sec.ci.sendBuf.len, flags);
if (count < 0) {
int err = PORT_GetError();
PORT_Assert(err != PR_WOULD_BLOCK_ERROR);
if (err == PR_WOULD_BLOCK_ERROR) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
}
@@ -3407,45 +3374,59 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
* Called from ssl3_HandleServerHelloDone,
* ssl3_HandleClientHello,
* and ssl3_HandleFinished
*
* Acquires and releases spec write lock, to protect switching the current
* and pending write spec pointers.
*/
-static SECStatus
-ssl3_SendChangeCipherSpecs(sslSocket *ss)
+SECStatus
+ssl3_SendChangeCipherSpecsInt(sslSocket *ss)
{
PRUint8 change = change_cipher_spec_choice;
- ssl3CipherSpec *pwSpec;
SECStatus rv;
- PRInt32 sent;
SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record",
SSL_GETPID(), ss->fd));
+ rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error code set by ssl3_FlushHandshake */
+ }
+
+ if (!IS_DTLS(ss)) {
+ PRInt32 sent;
+ sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec,
+ &change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (sent < 0) {
+ return SECFailure; /* error code set by ssl3_SendRecord */
+ }
+ } else {
+ SECStatus rv;
+ rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_SendChangeCipherSpecs(sslSocket *ss)
+{
+ ssl3CipherSpec *pwSpec;
+ SECStatus rv;
+
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
- if (rv != SECSuccess) {
- return rv; /* error code set by ssl3_FlushHandshake */
- }
- if (!IS_DTLS(ss)) {
- sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, &change, 1,
- ssl_SEND_FLAG_FORCE_INTO_BUFFER);
- if (sent < 0) {
- return (SECStatus)sent; /* error code set by ssl3_SendRecord */
- }
- } else {
- rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
- if (rv != SECSuccess) {
- return rv;
- }
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ if (rv != SECSuccess) {
+ return rv; /* Error code set. */
}
/* swap the pending and current write specs. */
ssl_GetSpecWriteLock(ss); /**************************************/
pwSpec = ss->ssl3.pwSpec;
ss->ssl3.pwSpec = ss->ssl3.cwSpec;
ss->ssl3.cwSpec = pwSpec;
@@ -3659,18 +3640,16 @@ ssl3_ComputeMasterSecretFinish(sslSocket
**
** Called from: ssl3_ComputeMasterSecret
*/
static SECStatus
ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
PK11SymKey **msp)
{
ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
- unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random;
- unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random;
PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
PRBool isTLS12 =
(PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/*
* Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
* which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
* data into a 48-byte value, and does not expect to return the version.
*/
@@ -3709,19 +3688,19 @@ ssl3_ComputeMasterSecretInt(sslSocket *s
keyFlags = 0;
}
if (!isDH) {
pms_version_ptr = &pms_version;
}
master_params.pVersion = pms_version_ptr;
- master_params.RandomInfo.pClientRandom = cr;
+ master_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
- master_params.RandomInfo.pServerRandom = sr;
+ master_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
if (isTLS12) {
master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
} else {
/* prfHashMechanism is not relevant with this PRF */
master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
}
@@ -3861,19 +3840,17 @@ ssl3_DeriveMasterSecret(sslSocket *ss, P
* Caller MUST hold the specWriteLock, and SSL3HandshakeLock.
* ssl3_InitPendingCipherSpec does that.
*
*/
static SECStatus
ssl3_DeriveConnectionKeys(sslSocket *ss)
{
ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
- unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random;
- unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random;
- PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
PRBool isTLS12 =
(PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
PK11SlotInfo *slot = NULL;
PK11SymKey *symKey = NULL;
void *pwArg = ss->pkcs11PinArg;
int keySize;
CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a
@@ -3904,19 +3881,19 @@ ssl3_DeriveConnectionKeys(sslSocket *ss)
pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
/* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
key_material_params.ulIVSizeInBits = 0;
memset(pwSpec->client.write_iv, 0, cipher_def->iv_size);
memset(pwSpec->server.write_iv, 0, cipher_def->iv_size);
}
key_material_params.bIsExport = PR_FALSE;
- key_material_params.RandomInfo.pClientRandom = cr;
+ key_material_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
- key_material_params.RandomInfo.pServerRandom = sr;
+ key_material_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
key_material_params.pReturnedKeyMaterial = &returnedKeys;
returnedKeys.pIVClient = pwSpec->client.write_iv;
returnedKeys.pIVServer = pwSpec->server.write_iv;
keySize = cipher_def->key_size;
if (skipKeysAndIVs) {
@@ -4934,16 +4911,28 @@ ssl_ClientHelloTypeName(sslClientHelloTy
CHTYPE(renegotiation); /* TLS <= 1.2 only */
}
PORT_Assert(0);
return NULL;
}
#undef CHTYPE
#endif
+PR_STATIC_ASSERT(SSL3_SESSIONID_BYTES == SSL3_RANDOM_LENGTH);
+static void
+ssl_MakeFakeSid(sslSocket *ss, PRUint8 *buf)
+{
+ PRUint8 x = 0x5a;
+ int i;
+ for (i = 0; i < SSL3_SESSIONID_BYTES; ++i) {
+ x += ss->ssl3.hs.client_random[i];
+ buf[i] = x;
+ }
+}
+
/* Called from ssl3_HandleHelloRequest(),
* ssl3_RedoHandshake()
* ssl_BeginClientHandshake (when resuming ssl3 session)
* dtls_HandleHelloVerifyRequest(with resending=PR_TRUE)
*
* The |type| argument indicates what is going on here:
* - client_hello_initial is set for the very first ClientHello
* - client_hello_retry indicates that this is a second attempt after receiving
@@ -5245,21 +5234,24 @@ ssl3_SendClientHello(sslSocket *ss, sslC
/* count compression methods */
numCompressionMethods = 0;
for (i = 0; i < ssl_compression_method_count; i++) {
if (ssl_CompressionEnabled(ss, ssl_compression_methods[i]))
numCompressionMethods++;
}
length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH +
- 1 + (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3
- ? 0
- : sid->u.ssl3.sessionIDLength) +
+ 1 + /* session id length */
2 + num_suites * sizeof(ssl3CipherSuite) +
1 + numCompressionMethods + total_exten_len;
+ if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ length += sid->u.ssl3.sessionIDLength;
+ } else if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
+ length += SSL3_SESSIONID_BYTES;
+ }
if (IS_DTLS(ss)) {
length += 1 + ss->ssl3.hs.cookie.len;
}
if (total_exten_len > 0) {
ssl3_CalculatePaddingExtLen(ss, length);
if (ss->xtnData.paddingLen) {
total_exten_len += 4 + ss->xtnData.paddingLen;
@@ -5293,38 +5285,45 @@ ssl3_SendClientHello(sslSocket *ss, sslC
if (sid->u.ssl3.lock) {
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
return rv; /* err set by ssl3_AppendHandshake* */
}
/* Generate a new random if this is the first attempt. */
if (type == client_hello_initial) {
- rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
+ rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
if (rv != SECSuccess) {
if (sid->u.ssl3.lock) {
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
return rv; /* err set by GetNewRandom. */
}
}
- rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random,
+ rv = ssl3_AppendHandshake(ss, ss->ssl3.hs.client_random,
SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
if (sid->u.ssl3.lock) {
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
return rv; /* err set by ssl3_AppendHandshake* */
}
- if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
+ if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
rv = ssl3_AppendHandshakeVariable(
ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
- else
+ } else if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
+ /* We're faking session resumption, so rather than create new
+ * randomness, just mix up the client random a little. */
+ PRUint8 buf[SSL3_SESSIONID_BYTES];
+ ssl_MakeFakeSid(ss, buf);
+ rv = ssl3_AppendHandshakeVariable(ss, buf, SSL3_SESSIONID_BYTES, 1);
+ } else {
rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+ }
if (rv != SECSuccess) {
if (sid->u.ssl3.lock) {
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
return rv; /* err set by ssl3_AppendHandshake* */
}
if (IS_DTLS(ss)) {
@@ -5458,19 +5457,16 @@ ssl3_SendClientHello(sslSocket *ss, sslC
if (ss->ssl3.hs.sendingSCSV) {
/* Since we sent the SCSV, pretend we sent empty RI extension. */
TLSExtensionData *xtnData = &ss->xtnData;
xtnData->advertised[xtnData->numAdvertised++] =
ssl_renegotiation_info_xtn;
}
flags = 0;
- if (!ss->firstHsDone && !IS_DTLS(ss)) {
- flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
- }
rv = ssl3_FlushHandshake(ss, flags);
if (rv != SECSuccess) {
return rv; /* error code set by ssl3_FlushHandshake */
}
if (version >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = tls13_MaybeDo0RTTHandshake(ss);
if (rv != SECSuccess) {
@@ -6551,52 +6547,96 @@ done:
if (buf.data)
PORT_Free(buf.data);
return rv;
}
/* Once a cipher suite has been selected, make sure that the necessary secondary
* information is properly set. */
SECStatus
-ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
- PRBool initHashes)
-{
- ss->ssl3.hs.cipher_suite = chosenSuite;
- ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(chosenSuite);
+ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes)
+{
+ ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
if (!ss->ssl3.hs.suite_def) {
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
if (!initHashes) {
return SECSuccess;
}
- /* Now we've have a cipher suite, initialize the handshake hashes. */
+ /* Now we have a cipher suite, initialize the handshake hashes. */
return ssl3_InitHandshakeHashes(ss);
}
+/* Once a cipher suite has been selected, make sure that the necessary secondary
+ * information is properly set. */
+SECStatus
+ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
+ PRBool initHashes)
+{
+ ss->ssl3.hs.cipher_suite = chosenSuite;
+ return ssl3_SetupCipherSuite(ss, initHashes);
+}
+
+SECStatus
+ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version,
+ ssl3CipherSuite suite, PRBool initHashes)
+{
+ int i;
+
+ i = ssl3_config_match_init(ss);
+ PORT_Assert(i > 0);
+ if (i <= 0) {
+ return SECFailure;
+ }
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i];
+ if (suite == suiteCfg->cipher_suite) {
+ SSLVersionRange vrange = { version, version };
+ if (!config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
+ /* config_match already checks whether the cipher suite is
+ * acceptable for the version, but the check is repeated here
+ * in order to give a more precise error code. */
+ if (!ssl3_CipherSuiteAllowedForVersionRange(suite, &vrange)) {
+ PORT_SetError(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION);
+ } else {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ }
+ return SECFailure;
+ }
+ break;
+ }
+ }
+ if (i >= ssl_V3_SUITES_IMPLEMENTED) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+
+ ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)suite;
+ return ssl3_SetupCipherSuite(ss, initHashes);
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 ServerHello message.
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
- PRUint32 temp;
- PRBool suite_found = PR_FALSE;
- int i;
+ PRUint32 cipher;
int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
SECStatus rv;
SECItem sidBytes = { siBuffer, NULL, 0 };
- PRBool isTLS = PR_FALSE;
SSL3AlertDescription desc = illegal_parameter;
+ TLSExtension *versionExtension;
#ifndef TLS_1_3_DRAFT_VERSION
SSL3ProtocolVersion downgradeCheckVersion;
#endif
SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -6617,21 +6657,101 @@ ssl3_HandleServerHello(sslSocket *ss, PR
CERT_DestroyCertificate(ss->ssl3.clientCertificate);
ss->ssl3.clientCertificate = NULL;
}
if (ss->ssl3.clientPrivateKey != NULL) {
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
}
+ /* Note that if we are doing the alternative handshake for TLS 1.3, this
+ * will set the version to TLS 1.2. We will amend that once all other
+ * fields have been read. */
rv = ssl_ClientReadVersion(ss, &b, &length, &ss->version);
if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
+ rv = ssl3_ConsumeHandshake(
+ ss, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+ if (sidBytes.len > SSL3_SESSIONID_BYTES) {
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_0)
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+ }
+
+ /* Read the cipher suite. */
+ rv = ssl3_ConsumeHandshakeNumber(ss, &cipher, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+
+ /* Compression method. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ PRUint32 compression;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &compression, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+ if (compression != ssl_compression_null) {
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ goto alert_loser;
+ }
+ }
+
+ /* Parse extensions. */
+ if (length != 0) {
+ PRUint32 extensionLength;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert already sent */
+ }
+ if (extensionLength != length) {
+ desc = decode_error;
+ goto alert_loser;
+ }
+ rv = ssl3_ParseExtensions(ss, &b, &length);
+ if (rv != SECSuccess) {
+ goto alert_loser; /* malformed */
+ }
+ }
+
+ /* Update the version based on the extension, as necessary. */
+ versionExtension = ssl3_FindExtension(ss, ssl_tls13_supported_versions_xtn);
+ if (versionExtension) {
+ rv = ssl_ClientReadVersion(ss, &versionExtension->data.data,
+ &versionExtension->data.len,
+ &ss->version);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser; /* An alert is sent by ssl_ClientReadVersion */
+ }
+ }
+
+ PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange));
+ /* Check that the version is within the configured range. */
+ if (ss->vrange.min > ss->version || ss->vrange.max < ss->version) {
+ desc = (ss->version > SSL_LIBRARY_VERSION_3_0)
+ ? protocol_version
+ : handshake_failure;
+ errCode = SSL_ERROR_UNSUPPORTED_VERSION;
+ goto alert_loser;
+ }
+
/* The server didn't pick 1.3 although we either received a
* HelloRetryRequest, or we prepared to send early app data. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
if (ss->ssl3.hs.helloRetry) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
@@ -6648,24 +6768,16 @@ ssl3_HandleServerHello(sslSocket *ss, PR
* in the first handshake. This isn't really the best place for
* us to be getting this version number, but it's what we have.
* (1294697). */
if (ss->firstHsDone && (ss->version != ss->ssl3.crSpec->version)) {
desc = illegal_parameter;
errCode = SSL_ERROR_UNSUPPORTED_VERSION;
goto alert_loser;
}
- ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
- isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
-
- rv = ssl3_ConsumeHandshake(
- ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
- if (rv != SECSuccess) {
- goto loser; /* alert has been sent */
- }
#ifndef TLS_1_3_DRAFT_VERSION
/* Check the ServerHello.random per
* [draft-ietf-tls-tls13-11 Section 6.3.1.1].
*
* TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check
* that the top eight octets are not equal to either of these values.
* TLS 1.2 clients SHOULD also perform this check if the ServerHello
@@ -6675,138 +6787,74 @@ ssl3_HandleServerHello(sslSocket *ss, PR
* Disable this test during the TLS 1.3 draft version period.
*/
downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
: ss->vrange.max;
if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
downgradeCheckVersion > ss->version) {
/* Both sections use the same sentinel region. */
- unsigned char *downgrade_sentinel =
- ss->ssl3.hs.server_random.rand +
+ PRUint8 *downgrade_sentinel =
+ ss->ssl3.hs.server_random +
SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
if (!PORT_Memcmp(downgrade_sentinel,
tls13_downgrade_random,
sizeof(tls13_downgrade_random)) ||
!PORT_Memcmp(downgrade_sentinel,
tls12_downgrade_random,
sizeof(tls12_downgrade_random))) {
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
}
}
#endif
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
- if (rv != SECSuccess) {
- goto loser; /* alert has been sent */
- }
- if (sidBytes.len > SSL3_SESSIONID_BYTES) {
- if (isTLS)
- desc = decode_error;
- goto alert_loser; /* malformed. */
- }
- }
-
- /* find selected cipher suite in our list. */
- rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length);
- if (rv != SECSuccess) {
- goto loser; /* alert has been sent */
- }
- i = ssl3_config_match_init(ss);
- PORT_Assert(i > 0);
- if (i <= 0) {
+ /* Finally, now all the version-related checks have passed. */
+ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
+ /* Update the write cipher spec to match the version. */
+ if (!ss->firstHsDone) {
+ ssl_GetSpecWriteLock(ss);
+ ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+ ssl_ReleaseSpecWriteLock(ss);
+ }
+
+ /* Check that the session ID is as expected. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ PRUint8 buf[SSL3_SESSIONID_BYTES];
+ unsigned int expectedSidLen;
+ if (ss->ssl3.hs.altHandshakeType) {
+ expectedSidLen = SSL3_SESSIONID_BYTES;
+ ssl_MakeFakeSid(ss, buf);
+ } else {
+ expectedSidLen = 0;
+ }
+ if (sidBytes.len != expectedSidLen ||
+ PORT_Memcmp(buf, sidBytes.data, expectedSidLen) != 0) {
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ goto alert_loser;
+ }
+ }
+
+ /* Set compression (to be removed soon), and cipher suite. */
+ ss->ssl3.hs.compression = ssl_compression_null;
+ rv = ssl_ClientSetCipherSuite(ss, ss->version, cipher,
+ PR_TRUE /* init hashes */);
+ if (rv != SECSuccess) {
errCode = PORT_GetError();
goto loser;
}
- for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
- ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
- if (temp == suite->cipher_suite) {
- SSLVersionRange vrange = { ss->version, ss->version };
- if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
- /* config_match already checks whether the cipher suite is
- * acceptable for the version, but the check is repeated here
- * in order to give a more precise error code. */
- if (!ssl3_CipherSuiteAllowedForVersionRange(temp, &vrange)) {
- desc = handshake_failure;
- errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION;
- goto alert_loser;
- }
-
- break; /* failure */
- }
-
- suite_found = PR_TRUE;
- break; /* success */
- }
- }
- if (!suite_found) {
- desc = handshake_failure;
- errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
- goto alert_loser;
- }
-
- rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp, PR_TRUE);
- if (rv != SECSuccess) {
- desc = internal_error;
- errCode = PORT_GetError();
+
+ rv = ssl3_HandleParsedExtensions(ss, server_hello);
+ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
+ if (rv != SECSuccess) {
goto alert_loser;
}
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- /* find selected compression method in our list. */
- rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 1, &b, &length);
- if (rv != SECSuccess) {
- goto loser; /* alert has been sent */
- }
- suite_found = PR_FALSE;
- for (i = 0; i < ssl_compression_method_count; i++) {
- if (temp == ssl_compression_methods[i]) {
- if (!ssl_CompressionEnabled(ss, ssl_compression_methods[i])) {
- break; /* failure */
- }
- suite_found = PR_TRUE;
- break; /* success */
- }
- }
- if (!suite_found) {
- desc = handshake_failure;
- errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP;
- goto alert_loser;
- }
- ss->ssl3.hs.compression = (SSLCompressionMethod)temp;
- } else {
- ss->ssl3.hs.compression = ssl_compression_null;
- }
-
- /* Note that if !isTLS and the extra stuff is not extensions, we
- * do NOT goto alert_loser.
- * There are some old SSL 3.0 implementations that do send stuff
- * after the end of the server hello, and we deliberately ignore
- * such stuff in the interest of maximal interoperability (being
- * "generous in what you accept").
- * Update: Starting in NSS 3.12.6, we handle the renegotiation_info
- * extension in SSL 3.0.
- */
- if (length != 0) {
- SECItem extensions;
- rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length);
- if (rv != SECSuccess || length != 0) {
- if (isTLS)
- goto alert_loser;
- } else {
- rv = ssl3_HandleExtensions(ss, &extensions.data,
- &extensions.len, server_hello);
- if (rv != SECSuccess)
- goto alert_loser;
- }
- }
-
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = tls13_HandleServerHelloPart2(ss);
if (rv != SECSuccess) {
errCode = PORT_GetError();
goto loser;
}
} else {
rv = ssl3_HandleServerHelloPart2(ss, &sidBytes, &errCode);
@@ -7923,16 +7971,17 @@ ssl3_NewSessionID(sslSocket *ss, PRBool
sid->version = ss->version;
sid->sigScheme = ssl_sig_none;
sid->u.ssl3.keys.resumable = PR_TRUE;
sid->u.ssl3.policy = SSL_ALLOWED;
sid->u.ssl3.clientWriteKey = NULL;
sid->u.ssl3.serverWriteKey = NULL;
sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
+ sid->u.ssl3.altHandshakeType = ss->ssl3.hs.altHandshakeType;
if (is_server) {
SECStatus rv;
int pid = SSL_GETPID();
sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
sid->u.ssl3.sessionID[0] = (pid >> 8) & 0xff;
sid->u.ssl3.sessionID[1] = pid & 0xff;
@@ -8339,17 +8388,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
ss->clientHelloVersion = version =
dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp);
} else {
ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
}
/* Grab the client random data. */
rv = ssl3_ConsumeHandshake(
- ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
+ ss, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed */
}
/* Grab the client's SID, if present. */
rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed */
@@ -8379,24 +8428,25 @@ ssl3_HandleClientHello(sslSocket *ss, PR
* we are restarting a previous session until extensions have been
* parsed, since we might have received a SessionTicket extension.
* Note: we allow extensions even when negotiating SSL3 for the sake
* of interoperability (and backwards compatibility).
*/
if (length) {
/* Get length of hello extensions */
- PRUint32 extension_length;
- rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length);
+ PRUint32 extensionLength;
+ rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* alert already sent */
}
- if (extension_length != length) {
- ssl3_DecodeError(ss); /* send alert */
- goto loser;
+ if (extensionLength != length) {
+ errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
+ desc = decode_error;
+ goto alert_loser;
}
rv = ssl3_ParseExtensions(ss, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed */
}
}
@@ -8417,27 +8467,44 @@ ssl3_HandleClientHello(sslSocket *ss, PR
PR_TRUE);
if (rv != SECSuccess) {
desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
: handshake_failure;
errCode = SSL_ERROR_UNSUPPORTED_VERSION;
goto alert_loser;
}
}
+
+ if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+ goto alert_loser;
+ }
+
isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
-
- /* You can't resume TLS 1.3 like this. */
- if (isTLS13 && sidBytes.len) {
- goto alert_loser;
+ /* Update the write spec to match the selected version. */
+ if (!ss->firstHsDone) {
+ ssl_GetSpecWriteLock(ss);
+ ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+ ssl_ReleaseSpecWriteLock(ss);
+ }
+
+ if (ss->ssl3.hs.altHandshakeType) {
+ rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
}
/* Generate the Server Random now so it is available
* when we process the ClientKeyShare in TLS 1.3 */
- rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random);
+ rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
if (rv != SECSuccess) {
errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
goto loser;
}
#ifndef TLS_1_3_DRAFT_VERSION
/*
* [draft-ietf-tls-tls13-11 Section 6.3.1.1].
@@ -8453,18 +8520,18 @@ ssl3_HandleClientHello(sslSocket *ss, PR
*
* 44 4F 57 4E 47 52 44 00
*
* TODO(ekr@rtfm.com): Note this change was not added in the SSLv2
* compat processing code since that will most likely be removed before
* we ship the final version of TLS 1.3. Bug 1306672.
*/
if (ss->vrange.max > ss->version) {
- unsigned char *downgrade_sentinel =
- ss->ssl3.hs.server_random.rand +
+ PRUint8 *downgrade_sentinel =
+ ss->ssl3.hs.server_random +
SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
switch (ss->vrange.max) {
case SSL_LIBRARY_VERSION_TLS_1_3:
PORT_Memcpy(downgrade_sentinel,
tls13_downgrade_random,
sizeof(tls13_downgrade_random));
break;
@@ -8477,16 +8544,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
/* Do not change random. */
break;
}
}
#endif
/* Now parse the rest of the extensions. */
rv = ssl3_HandleParsedExtensions(ss, client_hello);
+ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
goto loser; /* malformed */
}
/* If the ClientHello version is less than our maximum version, check for a
* TLS_FALLBACK_SCSV and reject the connection if found. */
if (ss->vrange.max > ss->version) {
for (i = 0; i + 1 < suites.len; i += 2) {
@@ -8517,26 +8585,18 @@ ssl3_HandleClientHello(sslSocket *ss, PR
PRUint8 *b2 = (PRUint8 *)emptyRIext;
PRUint32 L2 = sizeof emptyRIext;
(void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello);
break;
}
}
}
- /* This is a second check for TLS 1.3 and re-handshake to stop us
- * from re-handshake up to TLS 1.3, so it happens after version
- * negotiation. */
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- if (ss->firstHsDone) {
- desc = unexpected_message;
- errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
- goto alert_loser;
- }
- } else {
+ /* The check for renegotiation in TLS 1.3 is earlier. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
if (ss->firstHsDone &&
(ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) &&
!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
desc = no_renegotiation;
level = alert_warning;
errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
goto alert_loser;
@@ -9119,16 +9179,21 @@ ssl3_HandleV2ClientHello(sslSocket *ss,
if (rv != SECSuccess) {
/* send back which ever alert client will understand. */
desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
: handshake_failure;
errCode = SSL_ERROR_UNSUPPORTED_VERSION;
goto alert_loser;
}
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
+ if (!ss->firstHsDone) {
+ ssl_GetSpecWriteLock(ss);
+ ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+ ssl_ReleaseSpecWriteLock(ss);
+ }
/* if we get a non-zero SID, just ignore it. */
if (length != total) {
SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d",
SSL_GETPID(), ss->fd, length, total));
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
goto alert_loser;
@@ -9141,22 +9206,21 @@ ssl3_HandleV2ClientHello(sslSocket *ss,
rand_length > SSL_MAX_CHALLENGE_BYTES) {
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
goto alert_loser;
}
PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH);
- PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
- PORT_Memcpy(
- &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length],
- random, rand_length);
-
- PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0],
+ PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(&ss->ssl3.hs.client_random[SSL3_RANDOM_LENGTH - rand_length],
+ random, rand_length);
+
+ PRINT_BUF(60, (ss, "client random:", ss->ssl3.hs.client_random,
SSL3_RANDOM_LENGTH));
i = ssl3_config_match_init(ss);
if (i <= 0) {
errCode = PORT_GetError(); /* error code is already set. */
goto alert_loser;
}
/* Select a cipher suite.
@@ -9298,68 +9362,82 @@ ssl3_SendServerHello(sslSocket *ss)
sid = ss->sec.ci.sid;
extensions_len = ssl3_CallHelloExtensionSenders(
ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]);
if (extensions_len > 0)
extensions_len += 2; /* Add sizeof total extension length */
- /* TLS 1.3 doesn't use the session_id or compression_method
- * fields in the ServerHello. */
length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH;
+
+ /* Adjust for session ID. In TLS 1.3 proper it isn't even present. In the
+ * alternative TLS 1.3 handshake, it is copied from the client. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- length += 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength);
+ length += 1; /* Session ID Length */
+ if (sid) {
+ length += sid->u.ssl3.sessionIDLength;
+ }
+ } else if (ss->ssl3.hs.altHandshakeType) {
+ length += 1 + ss->ssl3.hs.fakeSid.len;
}
length += sizeof(ssl3CipherSuite);
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- length += 1; /* Compression */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ ss->ssl3.hs.altHandshakeType) {
+ length += 1; /* Compression. */
}
length += extensions_len;
rv = ssl3_AppendHandshakeHeader(ss, server_hello, length);
if (rv != SECSuccess) {
return rv; /* err set by AppendHandshake. */
}
if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
version = dtls_TLSVersionToDTLSVersion(ss->version);
- } else {
- version = ss->ssl3.hs.altHandshakeType ? tls13_EncodeAltDraftVersion(ss->version) : tls13_EncodeDraftVersion(ss->version);
+ } else if (ss->ssl3.hs.altHandshakeType) {
+ version = SSL_LIBRARY_VERSION_TLS_1_2;
+ } else {
+ version = tls13_EncodeDraftVersion(ss->version);
}
rv = ssl3_AppendHandshakeNumber(ss, version, 2);
if (rv != SECSuccess) {
return rv; /* err set by AppendHandshake. */
}
/* Random already generated in ssl3_HandleClientHello */
rv = ssl3_AppendHandshake(
- ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
+ ss, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
return rv; /* err set by AppendHandshake. */
}
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
if (sid) {
rv = ssl3_AppendHandshakeVariable(
ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
} else {
rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
}
- if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
- }
+ } else if (ss->ssl3.hs.altHandshakeType) {
+ rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.fakeSid.data,
+ ss->ssl3.hs.fakeSid.len, 1);
+ SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
+ }
+ if (rv != SECSuccess) {
+ return SECFailure; /* err set by AppendHandshake. */
}
rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2);
if (rv != SECSuccess) {
return rv; /* err set by AppendHandshake. */
}
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1);
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ ss->ssl3.hs.altHandshakeType) {
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_compression_null, 1);
if (rv != SECSuccess) {
return rv; /* err set by AppendHandshake. */
}
}
if (extensions_len) {
PRInt32 sent_len;
extensions_len -= 2;
@@ -11188,17 +11266,17 @@ ssl3_RecordKeyLog(sslSocket *ss, const c
/* There could be multiple, concurrent writers to the
* keylog, so we have to do everything in a single call to
* fwrite. */
strcpy(buf, label);
offset = strlen(label);
buf[offset++] += ' ';
- hexEncode(buf + offset, ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+ hexEncode(buf + offset, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
offset += SSL3_RANDOM_LENGTH * 2;
buf[offset++] = ' ';
hexEncode(buf + offset, keyData->data, keyData->len);
offset += keyData->len * 2;
buf[offset++] = '\n';
PORT_Assert(offset == len);
@@ -11557,16 +11635,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
ss->xtnData.nextProto.data) {
if (SECITEM_CopyItem(
NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
return SECFailure; /* error already set. */
}
}
+ sid->u.ssl3.altHandshakeType = ss->ssl3.hs.altHandshakeType;
ssl_GetSpecReadLock(ss); /*************************************/
/* Copy the master secret (wrapped or unwrapped) into the sid */
if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
sid->u.ssl3.keys.wrapped_master_secret_len =
ss->ssl3.crSpec->msItem.len;
memcpy(sid->u.ssl3.keys.wrapped_master_secret,
@@ -12371,17 +12450,17 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3
/* XXX For many AEAD ciphers, the plaintext is shorter than the
* ciphertext by a fixed byte count, but it is not true in general.
* Each AEAD cipher should provide a function that returns the
* plaintext length for a given ciphertext. */
unsigned int decryptedLen =
cText->buf->len - cipher_def->explicit_nonce_size -
cipher_def->tag_size;
headerLen = ssl3_BuildRecordPseudoHeader(
- header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+ header, crSpec->epoch, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen);
PORT_Assert(headerLen <= sizeof(header));
rv = crSpec->aead(
ss->sec.isServer ? &crSpec->client : &crSpec->server,
PR_TRUE, /* do decrypt */
plaintext->buf, /* out */
(int *)&plaintext->len, /* outlen */
plaintext->space, /* maxout */
@@ -12420,17 +12499,18 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3
} else {
good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
plaintext, macSize));
}
}
/* compute the MAC */
headerLen = ssl3_BuildRecordPseudoHeader(
- header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+ header, crSpec->epoch,
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
rType, isTLS, cText->version, IS_DTLS(ss),
plaintext->len - crSpec->mac_size);
PORT_Assert(headerLen <= sizeof(header));
if (cipher_def->type == type_block) {
rv = ssl3_ComputeRecordMACConstantTime(
crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
plaintext->buf, plaintext->len, originalLen,
hash, &hashBytes);
@@ -12611,21 +12691,36 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
if (rv != SECSuccess) {
ssl_ReleaseSpecReadLock(ss); /***************************/
SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
/* Clear the temp buffer used for decompression upon failure. */
sslBuffer_Clear(&temp_buf);
+ /* Zero the input so that we don't process it again. */
+ databuf->len = 0;
+
+ /* Ignore a CCS if the alternative handshake is negotiated. Note that
+ * this will fail if the server fails to negotiate the alternative
+ * handshake type in a 0-RTT session that is resumed from a session that
+ * did negotiate it. We don't care about that corner case right now. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ cText->type == content_change_cipher_spec &&
+ ss->ssl3.hs.ws != idle_handshake &&
+ ss->ssl3.hs.altHandshakeType &&
+ cText->buf->len == 1 &&
+ cText->buf->buf[0] == change_cipher_spec_choice) {
+ /* Ignore the error. */
+ return SECSuccess;
+ }
if (IS_DTLS(ss) ||
(ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
/* Silently drop the packet */
- databuf->len = 0; /* Needed to ensure data not left around */
return SECSuccess;
} else {
int errCode = PORT_GetError();
SSL3_SendAlert(ss, alert_fatal, alert);
/* Reset the error code in case SSL3_SendAlert called
* PORT_SetError(). */
PORT_SetError(errCode);
return SECFailure;
@@ -12704,17 +12799,17 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
}
sslBuffer_Clear(&temp_buf);
}
/*
** Having completed the decompression, check the length again.
*/
- if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) {
+ if (isTLS && databuf->len > MAX_FRAGMENT_LENGTH) {
SSL3_SendAlert(ss, alert_fatal, record_overflow);
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
}
/* Application data records are processed by the caller of this
** function, not by this function.
*/
@@ -12854,17 +12949,37 @@ ssl3_InitState(sslSocket *ss)
ssl_InitSecState(&ss->sec);
ssl_GetSpecWriteLock(ss);
ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0];
ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1];
ssl3_InitCipherSpec(ss->ssl3.crSpec);
ssl3_InitCipherSpec(ss->ssl3.prSpec);
- ss->ssl3.crSpec->version = ss->ssl3.prSpec->version = ss->vrange.max;
+ ss->ssl3.crSpec->version = ss->vrange.max;
+ if (IS_DTLS(ss)) {
+ ss->ssl3.crSpec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+ } else {
+ /* For new connections, cap the record layer version number of TLS
+ * ClientHello to { 3, 1 } (TLS 1.0). Some TLS 1.0 servers (which seem
+ * to use F5 BIG-IP) ignore ClientHello.client_version and use the
+ * record layer version number (TLSPlaintext.version) instead when
+ * negotiating protocol versions. In addition, if the record layer
+ * version number of ClientHello is { 3, 2 } (TLS 1.1) or higher, these
+ * servers reset the TCP connections. Lastly, some F5 BIG-IP servers
+ * hang if a record containing a ClientHello has a version greater than
+ * { 3, 1 } and a length greater than 255. Set this flag to work around
+ * such servers.
+ *
+ * We bump the version up when we settle on a version. Before producing
+ * an initial ServerHello, or when processing it.
+ */
+ ss->ssl3.crSpec->recordVersion = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0,
+ ss->vrange.max);
+ }
ssl_ReleaseSpecWriteLock(ss);
ss->ssl3.hs.sendingSCSV = PR_FALSE;
ss->ssl3.hs.preliminaryInfo = 0;
ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
ssl3_ResetExtensionData(&ss->xtnData);
PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions);
@@ -13223,16 +13338,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
sslBuffer_Clear(&ss->ssl3.hs.messages);
}
/* free the SSL3Buffer (msg_body) */
PORT_Free(ss->ssl3.hs.msg_body.buf);
SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE);
+ SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
if (ss->ssl3.hs.certificateRequest) {
PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
ss->ssl3.hs.certificateRequest = NULL;
}
/* free up the CipherSpecs */
ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/);
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -106,17 +106,17 @@ ssl_ECPubKey2NamedGroup(const SECKEYPubl
return NULL;
}
/* Caller must set hiLevel error code. */
static SECStatus
ssl3_ComputeECDHKeyHash(SSLHashType hashAlg,
SECItem ec_params, SECItem server_ecpoint,
- SSL3Random *client_rand, SSL3Random *server_rand,
+ PRUint8 *client_rand, PRUint8 *server_rand,
SSL3Hashes *hashes)
{
PRUint8 *hashBuf;
PRUint8 *pBuf;
SECStatus rv = SECSuccess;
unsigned int bufLen;
/*
* We only support named curves (the appropriate checks are made before this
@@ -592,18 +592,18 @@ ssl3_HandleECDHServerKeyExchange(sslSock
/* failures after this point are not malformed handshakes. */
/* TLS: send decrypt_error if signature failed. */
desc = isTLS ? decrypt_error : handshake_failure;
/*
* check to make sure the hash is signed by right guy
*/
rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point,
- &ss->ssl3.hs.client_random,
- &ss->ssl3.hs.server_random,
+ ss->ssl3.hs.client_random,
+ ss->ssl3.hs.server_random,
&hashes);
if (rv != SECSuccess) {
errCode =
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto alert_loser;
}
rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signature);
@@ -706,18 +706,18 @@ ssl3_SendECDHServerKeyExchange(sslSocket
if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme);
} else {
/* Use ssl_hash_none to represent the MD5+SHA1 combo. */
hashAlg = ssl_hash_none;
}
rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params,
pubKey->u.ec.publicValue,
- &ss->ssl3.hs.client_random,
- &ss->ssl3.hs.server_random,
+ ss->ssl3.hs.client_random,
+ ss->ssl3.hs.server_random,
&hashes);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto loser;
}
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -797,17 +797,17 @@ ssl3_ClientHandleStatusRequestXtn(const
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
return SECSuccess;
}
PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
-#define TLS_EX_SESS_TICKET_VERSION (0x0106)
+#define TLS_EX_SESS_TICKET_VERSION (0x0107)
/*
* Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
*/
SECStatus
ssl3_EncodeSessionTicket(sslSocket *ss,
const NewSessionTicket *ticket,
SECItem *ticket_data)
@@ -889,16 +889,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
+ 2 /* master_secret.length */
+ ms_item.len /* master_secret */
+ 1 /* client_auth_type */
+ cert_length /* cert */
+ 2 + srvName->len /* name len + length field */
+ 1 /* extendedMasterSecretUsed */
+ sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
+ sizeof(ticket->flags) /* ticket flags */
+ + 1 /* alt handshake type */
+ 1 + alpnSelection->len /* alpn value + length field */
+ 4; /* maxEarlyData */
if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL)
goto loser;
plaintext = plaintext_item;
@@ -1035,16 +1036,21 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
if (rv != SECSuccess)
goto loser;
if (alpnSelection->len) {
rv = ssl3_AppendToItem(&plaintext, alpnSelection->data,
alpnSelection->len);
if (rv != SECSuccess)
goto loser;
}
+ /* Alternative handshake type. */
+ rv = ssl3_AppendNumberToItem(
+ &plaintext, ss->sec.ci.sid->u.ssl3.altHandshakeType, 1);
+ if (rv != SECSuccess)
+ goto loser;
rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4);
if (rv != SECSuccess)
goto loser;
/* Check that we are totally full. */
PORT_Assert(plaintext.len == 0);
@@ -1301,16 +1307,24 @@ ssl_ParseSessionTicket(sslSocket *ss, co
rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->alpnSelection, 1,
&buffer, &len);
PORT_Assert(parsedTicket->alpnSelection.len < 256);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+ parsedTicket->altHandshakeType = temp;
+
rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
parsedTicket->maxEarlyData = temp;
#ifndef UNSAFE_FUZZER_MODE
@@ -1365,16 +1379,17 @@ ssl_CreateSIDFromTicket(sslSocket *ss, c
PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
parsedTicket->master_secret, parsedTicket->ms_length);
sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length;
sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech;
sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped;
sid->u.ssl3.masterValid = PR_TRUE;
sid->u.ssl3.keys.resumable = PR_TRUE;
sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed;
+ sid->u.ssl3.altHandshakeType = parsedTicket->altHandshakeType;
/* Copy over client cert from session ticket if there is one. */
if (parsedTicket->peer_cert.data != NULL) {
PORT_Assert(!sid->peerCert);
sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
&parsedTicket->peer_cert,
NULL, PR_FALSE, PR_TRUE);
if (!sid->peerCert) {
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -390,17 +390,18 @@ dtls_GatherData(sslSocket *ss, sslGather
*/
int
ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
{
int rv;
SSL3Ciphertext cText;
PRBool keepGoing = PR_TRUE;
- SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
+ SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
+ SSL_GETPID(), ss->fd));
/* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
* which requires the 1stHandshakeLock, which must be acquired before the
* RecvBufLock.
*/
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
@@ -503,17 +504,16 @@ ssl3_GatherCompleteHandshake(sslSocket *
} else {
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
}
if (IS_DTLS(ss)) {
sslSequenceNumber seq_num;
- cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
/* DTLS sequence number */
PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
cText.seq_num = PR_ntohll(seq_num);
}
cText.buf = &ss->gs.inbuf;
rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
}
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -146,19 +146,17 @@ typedef enum {
certificate_status = 22,
next_proto = 67
} SSL3HandshakeType;
typedef struct {
PRUint8 empty;
} SSL3HelloRequest;
-typedef struct {
- PRUint8 rand[SSL3_RANDOM_LENGTH];
-} SSL3Random;
+typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH];
typedef struct {
PRUint8 id[32];
PRUint8 length;
} SSL3SessionID;
typedef struct {
SSL3ProtocolVersion client_version;
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -17,21 +17,20 @@ SEC_BEGIN_PROTOS
* future NSS versions. Code that uses these functions needs to safeguard
* against the function not being available. */
#define SSL_EXPERIMENTAL_API(name, arglist, args) \
(SSL_GetExperimentalAPI(name) \
? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
: SECFailure)
-/* Allow the ServerHello to be record type 24. Experiment to test:
- * https://github.com/tlswg/tls13-spec/pull/1051
+/* Make the TLS 1.3 handshake mimic TLS 1.2 session resumption.
* This will either become part of the standard or be disabled
* after we have tested it.
*/
-#define SSL_UseAltServerHelloType(fd, enable) \
- SSL_EXPERIMENTAL_API("SSL_UseAltServerHelloType", \
+#define SSL_UseAltHandshakeType(fd, enable) \
+ SSL_EXPERIMENTAL_API("SSL_UseAltHandshakeType", \
(PRFileDesc * _fd, PRBool _enable), \
(fd, enable))
SEC_END_PROTOS
#endif /* __sslexp_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -224,18 +224,16 @@ struct sslSocketOpsStr {
int (*getpeername)(sslSocket *, PRNetAddr *);
int (*getsockname)(sslSocket *, PRNetAddr *);
};
/* Flags interpreted by ssl send functions. */
#define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
#define ssl_SEND_FLAG_NO_BUFFER 0x20000000
#define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
-#define ssl_SEND_FLAG_CAP_RECORD_VERSION \
- 0x04000000 /* TLS only */
#define ssl_SEND_FLAG_MASK 0x7f000000
/*
** A buffer object.
*/
struct sslBufferStr {
unsigned char *buf;
unsigned int len;
@@ -495,16 +493,17 @@ struct ssl3CipherSpecStr {
SSLDestroy destroyCompressContext;
void *compressContext;
SSLDestroy destroyDecompressContext;
void *decompressContext;
PK11SymKey *master_secret;
sslSequenceNumber write_seq_num;
sslSequenceNumber read_seq_num;
SSL3ProtocolVersion version;
+ SSL3ProtocolVersion recordVersion;
ssl3KeyMaterial client;
ssl3KeyMaterial server;
SECItem msItem;
DTLSEpoch epoch;
DTLSRecvdRecords recvdRecords;
/* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
* will be zero for everything but 0-RTT. */
PRUint32 earlyDataRemaining;
@@ -604,16 +603,18 @@ struct sslSessionIDStr {
** (used only in client).
*/
SECItem signedCertTimestamps;
/* The NPN/ALPN value negotiated in the original connection.
* Used for TLS 1.3. */
SECItem alpnSelection;
+ PRBool altHandshakeType;
+
/* This lock is lazily initialized by CacheSID when a sid is first
* cached. Before then, there is no need to lock anything because
* the sid isn't being shared by anything.
*/
PRRWLock *lock;
/* The lock must be held while reading or writing these members
* because they change while the sid is cached.
@@ -881,17 +882,18 @@ typedef struct SSL3HandshakeStateStr {
ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */
PRCList bufferedEarlyData; /* Buffered TLS 1.3 early data
* on server.*/
PRBool helloRetry; /* True if HelloRetryRequest has been sent
* or received. */
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
PRBool shortHeaders; /* Assigned if we are doing short headers. */
- PRBool altHandshakeType; /* Assigned if we are doing the wrapped handshake. */
+ PRBool altHandshakeType; /* Alternative ServerHello content type. */
+ SECItem fakeSid; /* ... (server) the SID the client used. */
} SSL3HandshakeState;
/*
** This is the "ssl3" struct, as in "ss->ssl3".
** note:
** usually, crSpec == cwSpec and prSpec == pwSpec.
** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
** But there are never more than 2 actual specs.
@@ -1017,16 +1019,17 @@ typedef struct SessionTicketStr {
PRUint8 master_secret[48];
PRBool extendedMasterSecretUsed;
ClientAuthenticationType client_auth_type;
SECItem peer_cert;
PRUint32 timestamp;
PRUint32 flags;
SECItem srvName; /* negotiated server name */
SECItem alpnSelection;
+ PRBool altHandshakeType;
PRUint32 maxEarlyData;
} SessionTicket;
/*
* SSL2 buffers used in SSL3.
* writeBuf in the SecurityInfo maintained by sslsecur.c is used
* to hold the data just about to be passed to the kernel
* sendBuf in the ConnectInfo maintained by sslcon.c is used
@@ -1648,16 +1651,20 @@ extern SECStatus ssl3_HandleHandshakeMes
extern void ssl3_DestroySSL3Info(sslSocket *ss);
extern SECStatus ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b,
PRUint32 *length,
SSL3ProtocolVersion *version);
extern SECStatus ssl3_NegotiateVersion(sslSocket *ss,
SSL3ProtocolVersion peerVersion,
PRBool allowLargerPeerVersion);
+extern SECStatus ssl_ClientSetCipherSuite(sslSocket *ss,
+ SSL3ProtocolVersion version,
+ ssl3CipherSuite suite,
+ PRBool initHashes);
extern SECStatus ssl_GetPeerInfo(sslSocket *ss);
/* ECDH functions */
extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss,
SECKEYPublicKey *svrPubKey);
extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss,
PRUint8 *b, PRUint32 length);
@@ -1821,16 +1828,17 @@ SECStatus ssl_GetCertificateRequestCAs(s
SECItem **namesp, unsigned int *nnamesp);
SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
PRUint32 *length, PLArenaPool *arena,
CERTDistNames *ca_list);
SECStatus ssl3_CompleteHandleCertificateRequest(
sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
unsigned int signatureSchemeCount, CERTDistNames *ca_list);
SECStatus ssl3_SendServerHello(sslSocket *ss);
+SECStatus ssl3_SendChangeCipherSpecsInt(sslSocket *ss);
SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
ssl3CipherSpec *spec,
SSL3Hashes *hashes,
PRUint32 sender);
SECStatus ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss,
const sslNamedGroupDef *ecGroup,
sslEphemeralKeyPair **keyPair);
SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -463,19 +463,19 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
if (hasContext) {
valLen += 2 /* PRUint16 length */ + contextLen;
}
val = PORT_Alloc(valLen);
if (!val) {
return SECFailure;
}
i = 0;
- PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(val + i, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
i += SSL3_RANDOM_LENGTH;
- PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(val + i, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
i += SSL3_RANDOM_LENGTH;
if (hasContext) {
val[i++] = contextLen >> 8;
val[i++] = contextLen;
PORT_Memcpy(val + i, context, contextLen);
i += contextLen;
}
PORT_Assert(i == valLen);
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -3870,17 +3870,17 @@ SSL_CanBypass(CERTCertificate *cert, SEC
{ \
"SSL_" #n, SSL_##n \
}
struct {
const char *const name;
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
- EXP(UseAltServerHelloType),
+ EXP(UseAltHandshakeType),
#endif
{ "", NULL }
};
#undef EXP
#undef PUB
void *
SSL_GetExperimentalAPI(const char *name)
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -128,19 +128,16 @@ const char keylogLabelClientTrafficSecre
const char keylogLabelServerTrafficSecret[] = "SERVER_TRAFFIC_SECRET_0";
const char keylogLabelExporterSecret[] = "EXPORTER_SECRET";
#define TRAFFIC_SECRET(ss, dir, name) ((ss->sec.isServer ^ \
(dir == CipherSpecWrite)) \
? ss->ssl3.hs.client##name \
: ss->ssl3.hs.server##name)
-const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0;
-const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1;
-
/* Belt and suspenders in case we ever add a TLS 1.4. */
PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
SSL_LIBRARY_VERSION_TLS_1_3);
/* Use this instead of FATAL_ERROR when no alert shall be sent. */
#define LOG_ERROR(ss, prError) \
do { \
SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
@@ -1723,17 +1720,19 @@ tls13_HandleHelloRetryRequest(sslSocket
ssl_ReleaseSpecWriteLock(ss);
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
}
/* Version. */
rv = ssl_ClientReadVersion(ss, &b, &length, &version);
if (rv != SECSuccess) {
- return SECFailure; /* alert already sent */
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
+ protocol_version);
+ return SECFailure;
}
if (version > ss->vrange.max || version < SSL_LIBRARY_VERSION_TLS_1_3) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
protocol_version);
return SECFailure;
}
/* Extensions. */
@@ -1936,16 +1935,23 @@ tls13_SendServerHelloSequence(sslSocket
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
rv = ssl3_SendServerHello(ss);
if (rv != SECSuccess) {
return rv; /* err code is set. */
}
+ if (ss->ssl3.hs.altHandshakeType) {
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+
rv = tls13_SendEncryptedServerSequence(ss);
if (rv != SECSuccess) {
err = PORT_GetError();
}
/* Even if we get an error, since the ServerHello was successfully
* serialized, we should give it a chance to reach the network. This gives
* the client a chance to perform the key exchange and decrypt the alert
* we're about to send. */
@@ -2699,37 +2705,74 @@ tls13_DeriveTrafficKeys(sslSocket *ss, s
*prkp = NULL;
}
return SECSuccess;
loser:
return SECFailure;
}
-static SECStatus
-tls13_SetupPendingCipherSpec(sslSocket *ss)
+void
+tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec)
{
- ssl3CipherSpec *pSpec;
+ const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0;
+ const SSL3ProtocolVersion kTlsAltRecordVersion = SSL_LIBRARY_VERSION_TLS_1_2;
+ const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+
+ /* Set the record version. */
+ if (IS_DTLS(ss)) {
+ spec->recordVersion = kDtlsRecordVersion;
+ } else if (spec->epoch == TrafficKeyEarlyApplicationData) {
+ /* For early data, the previous session determines the record type that
+ * is used (and not what this session might negotiate). */
+ if (ss->sec.ci.sid && ss->sec.ci.sid->u.ssl3.altHandshakeType) {
+ spec->recordVersion = kTlsAltRecordVersion;
+ } else {
+ spec->recordVersion = kTlsRecordVersion;
+ }
+ } else if (ss->ssl3.hs.altHandshakeType) {
+ spec->recordVersion = kTlsAltRecordVersion;
+ } else {
+ spec->recordVersion = kTlsRecordVersion;
+ }
+ SSL_TRC(10, ("%d: TLS13[%d]: Set record version to 0x%04x",
+ SSL_GETPID(), ss->fd, spec->recordVersion));
+}
+
+static SECStatus
+tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
+{
ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
- const ssl3BulkCipherDef *bulk = ssl_GetBulkCipherDef(
- ssl_LookupCipherSuiteDef(suite));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
ssl_GetSpecWriteLock(ss); /*******************************/
- pSpec = ss->ssl3.pwSpec;
+ spec = ss->ssl3.pwSpec;
/* Version isn't set when we send 0-RTT data. */
- pSpec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
+ spec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x",
SSL_GETPID(), ss->fd, suite));
- pSpec->cipher_def = bulk;
-
- ssl_ReleaseSpecWriteLock(ss); /*******************************/
+
+ spec->cipher_def = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
+ switch (spec->cipher_def->calg) {
+ case ssl_calg_aes_gcm:
+ spec->aead = tls13_AESGCM;
+ break;
+ case ssl_calg_chacha20:
+ spec->aead = tls13_ChaCha20Poly1305;
+ break;
+ default:
+ PORT_Assert(0);
+ return SECFailure;
+ break;
+ }
+
+ tls13_SetSpecRecordVersion(ss, spec);
return SECSuccess;
}
/* Install a new cipher spec for this direction. */
static SECStatus
tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
CipherSpecDirection direction, PRBool deleteSecret)
{
@@ -2749,39 +2792,16 @@ tls13_SetCipherSpec(sslSocket *ss, Traff
if (!spec) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
spec->refCt = 1;
PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs);
ss->ssl3.pwSpec = ss->ssl3.prSpec = spec;
- rv = tls13_SetupPendingCipherSpec(ss);
- if (rv != SECSuccess)
- return SECFailure;
-
- switch (spec->cipher_def->calg) {
- case calg_aes_gcm:
- spec->aead = tls13_AESGCM;
- break;
- case calg_chacha20:
- spec->aead = tls13_ChaCha20Poly1305;
- break;
- default:
- PORT_Assert(0);
- return SECFailure;
- break;
- }
-
- rv = tls13_DeriveTrafficKeys(ss, spec, type, direction,
- deleteSecret);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
/* We use the epoch for cipher suite identification, so increment
* it in both TLS and DTLS. */
if ((*specp)->epoch == PR_UINT16_MAX) {
return SECFailure;
}
spec->epoch = (PRUint16)type;
if (!IS_DTLS(ss)) {
@@ -2789,16 +2809,27 @@ tls13_SetCipherSpec(sslSocket *ss, Traff
} else {
/* The sequence number has the high 16 bits as the epoch. */
spec->read_seq_num = spec->write_seq_num =
(sslSequenceNumber)spec->epoch << 48;
dtls_InitRecvdRecords(&spec->recvdRecords);
}
+ /* This depends on spec having a valid direction and epoch. */
+ rv = tls13_SetupPendingCipherSpec(ss, spec);
+ if (rv != SECSuccess)
+ return SECFailure;
+
+ rv = tls13_DeriveTrafficKeys(ss, spec, type, direction,
+ deleteSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
if (type == TrafficKeyEarlyApplicationData) {
spec->earlyDataRemaining =
ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
}
/* Now that we've set almost everything up, finally cut over. */
ssl_GetSpecWriteLock(ss);
tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
@@ -3740,16 +3771,24 @@ tls13_SendClientSecondRound(sslSocket *s
return SECWouldBlock;
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
rv = tls13_SendEndOfEarlyData(ss);
if (rv != SECSuccess) {
return SECFailure; /* Error code already set. */
}
+ } else if (ss->ssl3.hs.zeroRttState == ssl_0rtt_none &&
+ ss->ssl3.hs.altHandshakeType) {
+ ssl_GetXmitBufLock(ss); /*******************************/
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ ssl_ReleaseXmitBufLock(ss); /*******************************/
+ if (rv != SECSuccess) {
+ return rv;
+ }
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
CipherSpecWrite, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
}
@@ -4041,17 +4080,18 @@ static const struct {
{ ssl_tls13_pre_shared_key_xtn, ExtensionSendClear },
{ ssl_tls13_early_data_xtn, ExtensionSendEncrypted },
{ ssl_next_proto_nego_xtn, ExtensionNotUsed },
{ ssl_renegotiation_info_xtn, ExtensionNotUsed },
{ ssl_signed_cert_timestamp_xtn, ExtensionSendCertificate },
{ ssl_cert_status_xtn, ExtensionSendCertificate },
{ ssl_tls13_ticket_early_data_info_xtn, ExtensionNewSessionTicket },
{ ssl_tls13_cookie_xtn, ExtensionSendHrr },
- { ssl_tls13_short_header_xtn, ExtensionSendClear }
+ { ssl_tls13_short_header_xtn, ExtensionSendClear },
+ { ssl_tls13_supported_versions_xtn, ExtensionSendClear }
};
PRBool
tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
{
unsigned int i;
PORT_Assert((message == client_hello) ||
@@ -4234,19 +4274,18 @@ tls13_UnprotectRecord(sslSocket *ss, SSL
SSL_TRC(3,
("%d: TLS13[%d]: record has invalid exterior content type=%d",
SSL_GETPID(), ss->fd, cText->type));
/* Do we need a better error here? */
PORT_SetError(SSL_ERROR_BAD_MAC_READ);
return SECFailure;
}
- /* Check the version number in the record */
- if ((IS_DTLS(ss) && cText->version != kDtlsRecordVersion) ||
- (!IS_DTLS(ss) && cText->version != kTlsRecordVersion)) {
+ /* Check the version number in the record. */
+ if (cText->version != crSpec->recordVersion) {
/* Do we need a better error here? */
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus version",
SSL_GETPID(), ss->fd));
return SECFailure;
}
/* Decrypt */
@@ -4359,36 +4398,50 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss
SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
/* Set the ALPN data as if it was negotiated. We check in the ServerHello
* handler that the server negotiates the same value. */
if (ss->sec.ci.sid->u.ssl3.alpnSelection.len) {
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
rv = SECITEM_CopyItem(NULL, &ss->xtnData.nextProto,
&ss->sec.ci.sid->u.ssl3.alpnSelection);
- if (rv != SECSuccess)
- return rv;
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ /* If the alternative handshake type option is enabled and the last session
+ * had the alternative handshake type, then send CCS. */
+ if (ss->opt.enableAltHandshaketype &&
+ ss->sec.ci.sid->u.ssl3.altHandshakeType) {
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendChangeCipherSpecsInt(ss);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
}
/* Cipher suite already set in tls13_SetupClientHello. */
ss->ssl3.hs.preliminaryInfo = 0;
rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
kHkdfLabelEarlyTrafficSecret,
keylogLabelClientEarlyTrafficSecret,
NULL,
&ss->ssl3.hs.clientEarlyTrafficSecret);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
return SECFailure;
+ }
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
CipherSpecWrite, PR_TRUE);
if (rv != SECSuccess) {
- return rv;
+ return SECFailure;
}
return SECSuccess;
}
PRInt32
tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len)
{
@@ -4499,17 +4552,17 @@ tls13_EncodeDraftVersion(SSL3ProtocolVer
return (PRUint16)version;
}
PRUint16
tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version)
{
#ifdef TLS_1_3_DRAFT_VERSION
if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
- return 0x7a00 | TLS_1_3_DRAFT_VERSION;
+ return 0x7e02;
}
#endif
return (PRUint16)version;
}
/* Pick the highest version we support that is also advertised. */
SECStatus
tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
@@ -4536,37 +4589,44 @@ tls13_NegotiateVersion(sslSocket *ss, co
for (offset = 0; offset < versions.len; offset += 2) {
PRUint16 supported =
(versions.data[offset] << 8) | versions.data[offset + 1];
if (supported == wire) {
ss->version = version;
return SECSuccess;
}
- if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss) &&
+ if (ss->opt.enableAltHandshaketype &&
+ !IS_DTLS(ss) &&
supported == alt_wire) {
+ rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+ ssl_tls13_supported_versions_xtn,
+ tls13_ServerSendSupportedVersionsXtn);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.altHandshakeType = PR_TRUE;
ss->version = version;
- ss->ssl3.hs.altHandshakeType = PR_TRUE;
return SECSuccess;
}
}
}
FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
return SECFailure;
}
SECStatus
-SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable)
+SSLExp_UseAltHandshakeType(PRFileDesc *fd, PRBool enable)
{
sslSocket *ss;
ss = ssl_FindSocket(fd);
- if (!ss) {
- SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltServerHelloType",
+ if (!ss || IS_DTLS(ss)) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltHandshakeType",
SSL_GETPID(), fd));
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ss->opt.enableAltHandshaketype = enable;
return SECSuccess;
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -80,11 +80,12 @@ PRInt32 tls13_Read0RttData(sslSocket *ss
SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
PRUint16 tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
-SECStatus SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable);
+SECStatus SSLExp_UseAltHandshakeType(PRFileDesc *fd, PRBool enable);
+void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
#endif /* __tls13con_h_ */
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -868,32 +868,37 @@ tls13_ClientHandleTicketEarlyDataInfoXtn
xtnData->max_early_data_size = PR_ntohl(utmp);
return SECSuccess;
}
/*
* struct {
+ * select (Handshake.msg_type) {
+ * case client_hello:
* ProtocolVersion versions<2..254>;
+ * case server_hello:
+ * ProtocolVersion version;
+ * };
* } SupportedVersions;
*/
PRInt32
tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes)
{
PRInt32 extensions_len;
PRUint16 version;
SECStatus rv;
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
return 0;
}
- SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension",
+ SSL_TRC(3, ("%d: TLS13[%d]: client send supported_versions extension",
SSL_GETPID(), ss->fd));
/* Extension type, extension len fiels, vector len field,
* length of the values. */
extensions_len = 2 + 2 + 1 +
2 * (ss->vrange.max - ss->vrange.min + 1);
if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
@@ -936,16 +941,60 @@ tls13_ClientSendSupportedVersionsXtn(con
xtnData->advertised[xtnData->numAdvertised++] =
ssl_tls13_supported_versions_xtn;
}
return extensions_len;
}
+PRInt32
+tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ PRBool append, PRUint32 maxBytes)
+{
+ SECStatus rv;
+ PRInt32 extensions_len;
+
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ PORT_Assert(0); /* Can't happen. */
+ return SECSuccess;
+ }
+ if (!ss->ssl3.hs.altHandshakeType) {
+ PORT_Assert(0); /* Can't happen. */
+ return SECSuccess;
+ }
+
+ SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
+ SSL_GETPID(), ss->fd));
+
+ extensions_len = 2 + 2 + 2; /* type, len, version */
+ if (maxBytes < (PRUint32)extensions_len) {
+ PORT_Assert(0);
+ return 0;
+ }
+
+ if (append) {
+ rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2);
+ if (rv != SECSuccess)
+ return -1;
+
+ rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2);
+ if (rv != SECSuccess)
+ return -1;
+
+ rv = ssl3_ExtAppendHandshakeNumber(
+ ss, tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+ if (rv != SECSuccess) {
+ return -1;
+ }
+ }
+ return extensions_len;
+}
+
/*
* struct {
* opaque cookie<1..2^16-1>;
* } Cookie;
*/
SECStatus
tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
{
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -48,16 +48,20 @@ PRInt32 tls13_ServerSendEarlyDataXtn(con
PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn(
const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
+PRInt32 tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ PRBool append,
+ PRUint32 maxBytes);
SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,19 +14,19 @@
/*
* NSS utilities's major version, minor version, patch level, build number,
* and whether this is a beta release.
*
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
-#define NSSUTIL_VERSION "3.34 Beta"
+#define NSSUTIL_VERSION "3.35 Beta"
#define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 34
+#define NSSUTIL_VMINOR 35
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_TRUE
SEC_BEGIN_PROTOS
/*
* Returns a const string of the UTIL library version.