summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEKR <ekr@rtfm.com>2015-01-10 21:25:38 +0000
committerEKR <ekr@rtfm.com>2015-01-10 21:25:38 +0000
commit8c9285302f210624f914e6501a3825ac08581855 (patch)
treed8f50658bb99b944bdcb230309ca7d34d4de1219
parent6b09a4887a8b9e97e689eea32ecf744982da937a (diff)
downloadnss-hg-8c9285302f210624f914e6501a3825ac08581855.tar.gz
Bug 1117022 - Implement draft-ietf-tls-session-hash [libssl]. r=mt
-rw-r--r--cmd/selfserv/selfserv.c18
-rw-r--r--cmd/tstclnt/tstclnt.c20
-rw-r--r--coreconf/rules.mk24
-rw-r--r--external_tests/ssl_gtest/Makefile5
-rw-r--r--external_tests/ssl_gtest/libssl_internals.c26
-rw-r--r--external_tests/ssl_gtest/libssl_internals.h17
-rw-r--r--external_tests/ssl_gtest/manifest.mn5
-rw-r--r--external_tests/ssl_gtest/ssl_loopback_unittest.cc213
-rw-r--r--external_tests/ssl_gtest/tls_agent.cc25
-rw-r--r--external_tests/ssl_gtest/tls_agent.h3
-rw-r--r--external_tests/ssl_gtest/tls_connect.cc20
-rw-r--r--external_tests/ssl_gtest/tls_connect.h6
-rw-r--r--external_tests/ssl_gtest/tls_filter.cc12
-rw-r--r--external_tests/ssl_gtest/tls_filter.h15
-rw-r--r--external_tests/ssl_gtest/tls_parser.h2
-rw-r--r--lib/ssl/SSLerrs.h6
-rw-r--r--lib/ssl/derive.c2
-rw-r--r--lib/ssl/ssl.h8
-rw-r--r--lib/ssl/ssl3con.c535
-rw-r--r--lib/ssl/ssl3ecc.c16
-rw-r--r--lib/ssl/ssl3ext.c116
-rw-r--r--lib/ssl/sslerr.h3
-rw-r--r--lib/ssl/sslimpl.h7
-rw-r--r--lib/ssl/sslinfo.c2
-rw-r--r--lib/ssl/sslsnce.c7
-rw-r--r--lib/ssl/sslsock.c14
-rw-r--r--lib/ssl/sslt.h9
27 files changed, 938 insertions, 198 deletions
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
index 81fb43d95..549fda53e 100644
--- a/cmd/selfserv/selfserv.c
+++ b/cmd/selfserv/selfserv.c
@@ -428,10 +428,11 @@ printSecurityInfo(PRFileDesc *fd)
suite.macBits, suite.macAlgorithmName);
FPRINTF(stderr,
"selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
- " Compression: %s\n",
+ " Compression: %s, Extended Master Secret: %s\n",
channel.authKeyBits, suite.authAlgorithmName,
channel.keaKeyBits, suite.keaTypeName,
- channel.compressionMethodName);
+ channel.compressionMethodName,
+ channel.extendedMasterSecretUsed ? "Yes": "No");
}
}
if (verbose) {
@@ -837,6 +838,8 @@ PRBool testbypass = PR_FALSE;
PRBool enableSessionTickets = PR_FALSE;
PRBool enableCompression = PR_FALSE;
PRBool failedToNegotiateName = PR_FALSE;
+PRBool enableExtendedMasterSecret = PR_FALSE;
+
static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
static int virtServerNameIndex = 1;
@@ -1942,6 +1945,13 @@ server_main(
}
}
+ if (enableExtendedMasterSecret) {
+ rv = SSL_OptionSet(model_sock, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+ if (rv != SECSuccess) {
+ errExit("error enabling extended master secret ");
+ }
+ }
+
for (kea = kt_rsa; kea < kt_kea_size; kea++) {
if (cert[kea] != NULL) {
secStatus = SSL_ConfigSecureServer(model_sock,
@@ -2218,7 +2228,7 @@ main(int argc, char **argv)
** numbers, then capital letters, then lower case, alphabetical.
*/
optstate = PL_CreateOptState(argc, argv,
- "2:A:BC:DEH:L:M:NP:RS:T:U:V:W:Ya:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
+ "2:A:BC:DEGH:L:M:NP:RS:T:U:V:W:Ya:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
++optionsFound;
switch(optstate->option) {
@@ -2234,6 +2244,8 @@ main(int argc, char **argv)
case 'E': disableStepDown = PR_TRUE; break;
case 'H': configureDHE = (PORT_Atoi(optstate->value) != 0); break;
+ case 'G': enableExtendedMasterSecret = PR_TRUE; break;
+
case 'I': /* reserved for OCSP multi-stapling */ break;
case 'L':
diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
index ddfadafd5..93a702220 100644
--- a/cmd/tstclnt/tstclnt.c
+++ b/cmd/tstclnt/tstclnt.c
@@ -129,10 +129,11 @@ void printSecurityInfo(PRFileDesc *fd)
suite.macBits, suite.macAlgorithmName);
FPRINTF(stderr,
"tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
- " Compression: %s\n",
+ " Compression: %s, Extended Master Secret: %s\n",
channel.authKeyBits, suite.authAlgorithmName,
channel.keaKeyBits, suite.keaTypeName,
- channel.compressionMethodName);
+ channel.compressionMethodName,
+ channel.extendedMasterSecretUsed ? "Yes": "No");
}
}
cert = SSL_RevealCert(fd);
@@ -231,6 +232,7 @@ static void PrintParameterUsage(void)
fprintf(stderr, "%-20s Enable compression.\n", "-z");
fprintf(stderr, "%-20s Enable false start.\n", "-g");
fprintf(stderr, "%-20s Enable the cert_status extension (OCSP stapling).\n", "-T");
+ fprintf(stderr, "%-20s Enable the extended master secret extension (session hash).\n", "-G");
fprintf(stderr, "%-20s Require fresh revocation info from side channel.\n"
"%-20s -F once means: require for server cert only\n"
"%-20s -F twice means: require for intermediates, too\n"
@@ -919,6 +921,7 @@ int main(int argc, char **argv)
int enableFalseStart = 0;
int enableCertStatus = 0;
int forceFallbackSCSV = 0;
+ int enableExtendedMasterSecret = 0;
PRSocketOptionData opt;
PRNetAddr addr;
PRPollDesc pollset[2];
@@ -967,7 +970,7 @@ int main(int argc, char **argv)
SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
optstate = PL_CreateOptState(argc, argv,
- "46BCDFKM:OR:STV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:xz");
+ "46BCDFGKM:OR:STV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:xz");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -989,6 +992,8 @@ int main(int argc, char **argv)
serverCertAuth.testFreshStatusFromSideChannel = PR_TRUE;
break;
+ case 'G': enableExtendedMasterSecret = PR_TRUE; break;
+
case 'I': /* reserved for OCSP multi-stapling */ break;
case 'O': serverCertAuth.shouldPause = PR_FALSE; break;
@@ -1386,6 +1391,15 @@ int main(int argc, char **argv)
return 1;
}
+ /* enable extended master secret mode */
+ if (enableExtendedMasterSecret) {
+ rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling extended master secret");
+ return 1;
+ }
+ }
+
SSL_SetPKCS11PinArg(s, &pwdata);
serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
diff --git a/coreconf/rules.mk b/coreconf/rules.mk
index 0a891ebc7..34b742a7f 100644
--- a/coreconf/rules.mk
+++ b/coreconf/rules.mk
@@ -424,12 +424,12 @@ $(OBJDIR)/$(PROG_PREFIX)%$(OBJ_SUFFIX): %.S
$(OBJDIR)/$(PROG_PREFIX)%: %.cpp
@$(MAKE_OBJDIR)
ifdef USE_NT_C_SYNTAX
- $(CCC) -Fo$@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -Fo$@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
ifdef NEED_ABSOLUTE_PATH
- $(CCC) -o $@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
- $(CCC) -o $@ -c $(CFLAGS) $<
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $<
endif
endif
@@ -440,16 +440,16 @@ $(OBJDIR)/$(PROG_PREFIX)%$(OBJ_SUFFIX): %.cc
$(MAKE_OBJDIR)
ifdef STRICT_CPLUSPLUS_SUFFIX
echo "#line 1 \"$<\"" | cat - $< > $(OBJDIR)/t_$*.cc
- $(CCC) -o $@ -c $(CFLAGS) $(OBJDIR)/t_$*.cc
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $(OBJDIR)/t_$*.cc
rm -f $(OBJDIR)/t_$*.cc
else
ifdef USE_NT_C_SYNTAX
- $(CCC) -Fo$@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -Fo$@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
ifdef NEED_ABSOLUTE_PATH
- $(CCC) -o $@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
- $(CCC) -o $@ -c $(CFLAGS) $<
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $<
endif
endif
endif #STRICT_CPLUSPLUS_SUFFIX
@@ -458,22 +458,22 @@ $(OBJDIR)/$(PROG_PREFIX)%$(OBJ_SUFFIX): %.cpp
@$(MAKE_OBJDIR)
ifdef STRICT_CPLUSPLUS_SUFFIX
echo "#line 1 \"$<\"" | cat - $< > $(OBJDIR)/t_$*.cc
- $(CCC) -o $@ -c $(CFLAGS) $(OBJDIR)/t_$*.cc
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $(OBJDIR)/t_$*.cc
rm -f $(OBJDIR)/t_$*.cc
else
ifdef USE_NT_C_SYNTAX
- $(CCC) -Fo$@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -Fo$@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
ifdef NEED_ABSOLUTE_PATH
- $(CCC) -o $@ -c $(CFLAGS) $(call core_abspath,$<)
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $(call core_abspath,$<)
else
- $(CCC) -o $@ -c $(CFLAGS) $<
+ $(CCC) -o $@ -c $(CFLAGS) $(CXXFLAGS) $<
endif
endif
endif #STRICT_CPLUSPLUS_SUFFIX
%.i: %.cpp
- $(CCC) -C -E $(CFLAGS) $< > $@
+ $(CCC) -C -E $(CFLAGS) $(CXXFLAGS) $< > $@
%.i: %.c
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
diff --git a/external_tests/ssl_gtest/Makefile b/external_tests/ssl_gtest/Makefile
index 61965a20a..7f36bffe4 100644
--- a/external_tests/ssl_gtest/Makefile
+++ b/external_tests/ssl_gtest/Makefile
@@ -43,6 +43,9 @@ include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
MKPROG = $(CCC)
+CXXFLAGS += -std=c++0x
+CFLAGS += -I$(CORE_DEPTH)/lib/ssl
+
include ../../cmd/platrules.mk
ifeq (WINNT,$(OS_ARCH))
@@ -55,6 +58,4 @@ ifeq (WINNT,$(OS_ARCH))
# Linking to winsock to get htonl
OS_LIBS += Ws2_32.lib
-else
- CFLAGS += -std=c++0x
endif
diff --git a/external_tests/ssl_gtest/libssl_internals.c b/external_tests/ssl_gtest/libssl_internals.c
new file mode 100644
index 000000000..db83ef694
--- /dev/null
+++ b/external_tests/ssl_gtest/libssl_internals.c
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This file contains functions for frobbing the internals of libssl */
+#include "libssl_internals.h"
+
+#include "seccomon.h"
+#include "ssl.h"
+#include "sslimpl.h"
+
+SECStatus
+SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd)
+{
+ sslSocket *ss = (sslSocket *)fd->secret;
+
+ if (!ss) {
+ return SECFailure;
+ }
+
+ ++ss->clientHelloVersion;
+
+ return SECSuccess;
+}
diff --git a/external_tests/ssl_gtest/libssl_internals.h b/external_tests/ssl_gtest/libssl_internals.h
new file mode 100644
index 000000000..db6d0af62
--- /dev/null
+++ b/external_tests/ssl_gtest/libssl_internals.h
@@ -0,0 +1,17 @@
+/* -*- 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/. */
+
+#ifndef libssl_internals_h_
+#define libssl_internals_h_
+
+#include "prio.h"
+#include "seccomon.h"
+
+SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd);
+
+#endif
+
+
diff --git a/external_tests/ssl_gtest/manifest.mn b/external_tests/ssl_gtest/manifest.mn
index 212aa39d6..ac5f3845e 100644
--- a/external_tests/ssl_gtest/manifest.mn
+++ b/external_tests/ssl_gtest/manifest.mn
@@ -6,6 +6,11 @@ CORE_DEPTH = ../..
DEPTH = ../..
MODULE = nss
+# These sources have access to libssl internals
+CSRCS = \
+ libssl_internals.c \
+ $(NULL)
+
CPPSRCS = \
ssl_loopback_unittest.cc \
ssl_extension_unittest.cc \
diff --git a/external_tests/ssl_gtest/ssl_loopback_unittest.cc b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
index 09303e715..8d9e40399 100644
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -7,9 +7,13 @@
#include "ssl.h"
#include "sslerr.h"
#include "sslproto.h"
-
#include <memory>
+extern "C" {
+// This is not something that should make you happy.
+#include "libssl_internals.h"
+}
+
#include "tls_parser.h"
#include "tls_filter.h"
#include "tls_connect.h"
@@ -17,6 +21,46 @@
namespace nss_test {
+uint8_t kBogusClientKeyExchange[] = {
+ 0x01, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+// When we see the ClientKeyExchange from |client|, increment the
+// ClientHelloVersion on |server|.
+class TlsInspectorClientHelloVersionChanger : public TlsHandshakeFilter {
+ public:
+ TlsInspectorClientHelloVersionChanger(TlsAgent* server) : server_(server) {}
+
+ virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
+ const DataBuffer& input, DataBuffer* output) {
+ if (handshake_type == kTlsHandshakeClientKeyExchange) {
+ EXPECT_EQ(
+ SECSuccess,
+ SSLInt_IncrementClientHandshakeVersion(server_->ssl_fd()));
+ }
+ return false;
+ }
+
+ private:
+ TlsAgent* server_;
+};
+
class TlsServerKeyExchangeEcdhe {
public:
bool Parse(const DataBuffer& buffer) {
@@ -317,6 +361,53 @@ TEST_P(TlsConnectStream, ConnectAndServerRenegotiate) {
CheckConnected();
}
+TEST_P(TlsConnectStream, ConnectStaticRSA) {
+ DisableDheCiphers();
+ Connect();
+ client_->CheckKEAType(ssl_kea_rsa);
+}
+
+// Test that a totally bogus EPMS is handled correctly.
+// This test is stream so we can catch the bad_record_mac alert.
+TEST_P(TlsConnectStream, ConnectStaticRSABogusCKE) {
+ DisableDheCiphers();
+ TlsInspectorReplaceHandshakeMessage* i1 =
+ new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
+ DataBuffer(
+ kBogusClientKeyExchange,
+ sizeof(kBogusClientKeyExchange)));
+ client_->SetPacketFilter(i1);
+ auto alert_recorder = new TlsAlertRecorder();
+ server_->SetPacketFilter(alert_recorder);
+ ConnectExpectFail();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+}
+
+// Test that a PMS with a bogus version number is handled correctly.
+// This test is stream so we can catch the bad_record_mac alert.
+TEST_P(TlsConnectStream, ConnectStaticRSABogusPMSVersionDetect) {
+ DisableDheCiphers();
+ client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+ server_));
+ auto alert_recorder = new TlsAlertRecorder();
+ server_->SetPacketFilter(alert_recorder);
+ ConnectExpectFail();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+}
+
+// Test that a PMS with a bogus version number is ignored when
+// rollback detection is disabled. This is a positive control for
+// ConnectStaticRSABogusPMSVersionDetect.
+TEST_P(TlsConnectGeneric, ConnectStaticRSABogusPMSVersionIgnore) {
+ DisableDheCiphers();
+ client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+ server_));
+ server_->DisableRollbackDetection();
+ Connect();
+}
+
TEST_P(TlsConnectStream, ConnectEcdhe) {
EnableSomeEcdheCiphers();
Connect();
@@ -429,6 +520,126 @@ TEST_P(TlsConnectStream, ShortRead) {
ASSERT_EQ(1200U, client_->received_bytes());
}
+TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecret) {
+ EnableExtendedMasterSecret();
+ Connect();
+ ResetRsa();
+ ExpectResumption(RESUME_SESSIONID);
+ EnableExtendedMasterSecret();
+ Connect();
+}
+
+
+TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretStaticRSA) {
+ DisableDheCiphers();
+ EnableExtendedMasterSecret();
+ Connect();
+}
+
+// This test is stream so we can catch the bad_record_mac alert.
+TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusCKE) {
+ DisableDheCiphers();
+ EnableExtendedMasterSecret();
+ TlsInspectorReplaceHandshakeMessage* inspect =
+ new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
+ DataBuffer(
+ kBogusClientKeyExchange,
+ sizeof(kBogusClientKeyExchange)));
+ client_->SetPacketFilter(inspect);
+ auto alert_recorder = new TlsAlertRecorder();
+ server_->SetPacketFilter(alert_recorder);
+ ConnectExpectFail();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+}
+
+// This test is stream so we can catch the bad_record_mac alert.
+TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
+ DisableDheCiphers();
+ EnableExtendedMasterSecret();
+ client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+ server_));
+ auto alert_recorder = new TlsAlertRecorder();
+ server_->SetPacketFilter(alert_recorder);
+ ConnectExpectFail();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+}
+
+TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
+ DisableDheCiphers();
+ EnableExtendedMasterSecret();
+ client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+ server_));
+ server_->DisableRollbackDetection();
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretECDHE) {
+ EnableExtendedMasterSecret();
+ EnableSomeEcdheCiphers();
+ Connect();
+
+ ResetRsa();
+ EnableExtendedMasterSecret();
+ EnableSomeEcdheCiphers();
+ ExpectResumption(RESUME_SESSIONID);
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretTicket) {
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+ EnableExtendedMasterSecret();
+ Connect();
+
+ ResetRsa();
+ ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+
+ EnableExtendedMasterSecret();
+ ExpectResumption(RESUME_TICKET);
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric,
+ ConnectExtendedMasterSecretClientOnly) {
+ client_->EnableExtendedMasterSecret();
+ ExpectExtendedMasterSecret(false);
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric,
+ ConnectExtendedMasterSecretServerOnly) {
+ server_->EnableExtendedMasterSecret();
+ ExpectExtendedMasterSecret(false);
+ Connect();
+}
+
+TEST_P(TlsConnectGeneric,
+ ConnectExtendedMasterSecretResumeWithout) {
+ EnableExtendedMasterSecret();
+ Connect();
+
+ ResetRsa();
+ server_->EnableExtendedMasterSecret();
+ auto alert_recorder = new TlsAlertRecorder();
+ server_->SetPacketFilter(alert_recorder);
+ ConnectExpectFail();
+ EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+ EXPECT_EQ(kTlsAlertHandshakeFailure, alert_recorder->description());
+}
+
+TEST_P(TlsConnectGeneric,
+ ConnectNormalResumeWithExtendedMasterSecret) {
+ ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
+ ExpectExtendedMasterSecret(false);
+ Connect();
+
+ ResetRsa();
+ EnableExtendedMasterSecret();
+ ExpectResumption(RESUME_NONE);
+ Connect();
+}
+
INSTANTIATE_TEST_CASE_P(VariantsStream10, TlsConnectGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
diff --git a/external_tests/ssl_gtest/tls_agent.cc b/external_tests/ssl_gtest/tls_agent.cc
index f6fb3ae47..3fb9374eb 100644
--- a/external_tests/ssl_gtest/tls_agent.cc
+++ b/external_tests/ssl_gtest/tls_agent.cc
@@ -408,6 +408,31 @@ void TlsAgent::Connected() {
SetState(STATE_CONNECTED);
}
+void TlsAgent::EnableExtendedMasterSecret() {
+ ASSERT_TRUE(EnsureTlsSetup());
+
+ SECStatus rv = SSL_OptionSet(ssl_fd_,
+ SSL_ENABLE_EXTENDED_MASTER_SECRET,
+ PR_TRUE);
+
+ ASSERT_EQ(SECSuccess, rv);
+}
+
+void TlsAgent::CheckExtendedMasterSecret(bool expected) {
+ ASSERT_EQ(expected, info_.extendedMasterSecretUsed)
+ << "unexpected extended master secret state for " << name_;
+}
+
+void TlsAgent::DisableRollbackDetection() {
+ ASSERT_TRUE(EnsureTlsSetup());
+
+ SECStatus rv = SSL_OptionSet(ssl_fd_,
+ SSL_ROLLBACK_DETECTION,
+ PR_FALSE);
+
+ ASSERT_EQ(SECSuccess, rv);
+}
+
void TlsAgent::Handshake() {
SECStatus rv = SSL_ForceHandshake(ssl_fd_);
if (rv == SECSuccess) {
diff --git a/external_tests/ssl_gtest/tls_agent.h b/external_tests/ssl_gtest/tls_agent.h
index 5e5901528..db0d25abe 100644
--- a/external_tests/ssl_gtest/tls_agent.h
+++ b/external_tests/ssl_gtest/tls_agent.h
@@ -91,6 +91,9 @@ class TlsAgent : public PollTarget {
void SendData(size_t bytes, size_t blocksize = 1024);
void ReadBytes();
void ResetSentBytes(); // Hack to test drops.
+ void EnableExtendedMasterSecret();
+ void CheckExtendedMasterSecret(bool expected);
+ void DisableRollbackDetection();
State state() const { return state_; }
diff --git a/external_tests/ssl_gtest/tls_connect.cc b/external_tests/ssl_gtest/tls_connect.cc
index 3e8a77d7d..536940c31 100644
--- a/external_tests/ssl_gtest/tls_connect.cc
+++ b/external_tests/ssl_gtest/tls_connect.cc
@@ -59,7 +59,8 @@ TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
server_(new TlsAgent("server", TlsAgent::SERVER, mode_, ssl_kea_rsa)),
version_(version),
expected_resumption_mode_(RESUME_NONE),
- session_ids_() {
+ session_ids_(),
+ expect_extended_master_secret_(false) {
std::cerr << "Version: " << mode_ << " " << VersionString(version_) << std::endl;
}
@@ -139,6 +140,12 @@ void TlsConnectTestBase::Handshake() {
5000);
}
+void TlsConnectTestBase::EnableExtendedMasterSecret() {
+ client_->EnableExtendedMasterSecret();
+ server_->EnableExtendedMasterSecret();
+ ExpectExtendedMasterSecret(true);
+}
+
void TlsConnectTestBase::Connect() {
server_->StartConnect();
client_->StartConnect();
@@ -176,6 +183,8 @@ void TlsConnectTestBase::CheckConnected() {
session_ids_.push_back(sid_c1);
CheckResumption(expected_resumption_mode_);
+ // Check whether the extended master secret extension was negotiated.
+ CheckExtendedMasterSecret();
}
void TlsConnectTestBase::ConnectExpectFail() {
@@ -258,6 +267,15 @@ void TlsConnectTestBase::SendReceive() {
ASSERT_EQ(50U, server_->received_bytes());
}
+void TlsConnectTestBase::ExpectExtendedMasterSecret(bool expected) {
+ expect_extended_master_secret_ = expected;
+}
+
+void TlsConnectTestBase::CheckExtendedMasterSecret() {
+ client_->CheckExtendedMasterSecret(expect_extended_master_secret_);
+ server_->CheckExtendedMasterSecret(expect_extended_master_secret_);
+}
+
TlsConnectGeneric::TlsConnectGeneric()
: TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
std::get<1>(GetParam())) {}
diff --git a/external_tests/ssl_gtest/tls_connect.h b/external_tests/ssl_gtest/tls_connect.h
index 90c72024c..3a4f2568c 100644
--- a/external_tests/ssl_gtest/tls_connect.h
+++ b/external_tests/ssl_gtest/tls_connect.h
@@ -62,15 +62,16 @@ class TlsConnectTestBase : public ::testing::Test {
void ExpectResumption(SessionResumptionMode expected);
void EnableSomeEcdheCiphers();
void DisableDheCiphers();
+ void EnableExtendedMasterSecret();
void ConfigureSessionCache(SessionResumptionMode client,
SessionResumptionMode server);
void EnableAlpn();
void EnableSrtp();
void CheckSrtp() const;
void SendReceive();
+ void ExpectExtendedMasterSecret(bool expected);
protected:
-
Mode mode_;
TlsAgent* client_;
TlsAgent* server_;
@@ -81,6 +82,9 @@ class TlsConnectTestBase : public ::testing::Test {
private:
void Reset(const std::string& server_name, SSLKEAType kea);
void CheckResumption(SessionResumptionMode expected);
+ void CheckExtendedMasterSecret();
+
+ bool expect_extended_master_secret_;
};
// A TLS-only test base.
diff --git a/external_tests/ssl_gtest/tls_filter.cc b/external_tests/ssl_gtest/tls_filter.cc
index 2430cfefd..07654eed7 100644
--- a/external_tests/ssl_gtest/tls_filter.cc
+++ b/external_tests/ssl_gtest/tls_filter.cc
@@ -187,6 +187,18 @@ bool TlsInspectorRecordHandshakeMessage::FilterHandshake(
return false;
}
+
+bool TlsInspectorReplaceHandshakeMessage::FilterHandshake(
+ uint16_t version, uint8_t handshake_type,
+ const DataBuffer& input, DataBuffer* output) {
+ if (handshake_type == handshake_type_) {
+ *output = buffer_;
+ return true;
+ }
+
+ return false;
+}
+
bool TlsAlertRecorder::FilterRecord(uint8_t content_type, uint16_t version,
const DataBuffer& input, DataBuffer* output) {
if (level_ == kTlsAlertFatal) { // already fatal
diff --git a/external_tests/ssl_gtest/tls_filter.h b/external_tests/ssl_gtest/tls_filter.h
index 49593b363..1eec64b26 100644
--- a/external_tests/ssl_gtest/tls_filter.h
+++ b/external_tests/ssl_gtest/tls_filter.h
@@ -75,6 +75,21 @@ class TlsInspectorRecordHandshakeMessage : public TlsHandshakeFilter {
DataBuffer buffer_;
};
+// Replace all instances of a handshake message.
+class TlsInspectorReplaceHandshakeMessage : public TlsHandshakeFilter {
+ public:
+ TlsInspectorReplaceHandshakeMessage(uint8_t handshake_type,
+ const DataBuffer& replacement)
+ : handshake_type_(handshake_type), buffer_(replacement) {}
+
+ virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
+ const DataBuffer& input, DataBuffer* output);
+
+ private:
+ uint8_t handshake_type_;
+ DataBuffer buffer_;
+};
+
// Records an alert. If an alert has already been recorded, it won't save the
// new alert unless the old alert is a warning and the new one is fatal.
class TlsAlertRecorder : public TlsRecordFilter {
diff --git a/external_tests/ssl_gtest/tls_parser.h b/external_tests/ssl_gtest/tls_parser.h
index a17933047..866f5fe12 100644
--- a/external_tests/ssl_gtest/tls_parser.h
+++ b/external_tests/ssl_gtest/tls_parser.h
@@ -27,11 +27,13 @@ const uint8_t kTlsHandshakeClientHello = 1;
const uint8_t kTlsHandshakeServerHello = 2;
const uint8_t kTlsHandshakeCertificate = 11;
const uint8_t kTlsHandshakeServerKeyExchange = 12;
+const uint8_t kTlsHandshakeClientKeyExchange = 16;
const uint8_t kTlsAlertWarning = 1;
const uint8_t kTlsAlertFatal = 2;
const uint8_t kTlsAlertUnexpectedMessage = 10;
+const uint8_t kTlsAlertBadRecordMac = 20;
const uint8_t kTlsAlertHandshakeFailure = 40;
const uint8_t kTlsAlertIllegalParameter = 47;
const uint8_t kTlsAlertDecodeError = 50;
diff --git a/lib/ssl/SSLerrs.h b/lib/ssl/SSLerrs.h
index da5616441..602839680 100644
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -434,3 +434,9 @@ ER3(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 134),
ER3(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 135),
"The peer used an unsupported combination of signature and hash algorithm.")
+
+ER3(SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 136),
+"The peer tried to resume without a correct extended_master_secret extension")
+
+ER3(SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET, (SSL_ERROR_BASE + 137),
+"The peer tried to resume with an unexpected extended_master_secret extension")
diff --git a/lib/ssl/derive.c b/lib/ssl/derive.c
index b7c38c30b..8b58b800d 100644
--- a/lib/ssl/derive.c
+++ b/lib/ssl/derive.c
@@ -431,7 +431,7 @@ key_and_mac_derive_fail:
* so isRSA is always true.
*/
SECStatus
-ssl3_MasterKeyDeriveBypass(
+ssl3_MasterSecretDeriveBypass(
ssl3CipherSpec * pwSpec,
const unsigned char * cr,
const unsigned char * sr,
diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h
index 40f8476d5..2a527693b 100644
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -196,6 +196,14 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_SERVER_DHE 29
+/* Use draft-ietf-tls-session-hash. Controls whether we offer the
+ * extended_master_secret extension which, when accepted, hashes
+ * the handshake transcript into the master secret. This option is
+ * disabled by default.
+ */
+#define SSL_ENABLE_EXTENDED_MASTER_SECRET 30
+
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 717ece17a..877f1fcb0 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -62,6 +62,10 @@ static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
const unsigned char *b,
unsigned int l);
static SECOidTag ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc);
+static SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
+ ssl3CipherSpec *spec,
+ SSL3Hashes *hashes,
+ PRUint32 sender);
static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
@@ -2177,7 +2181,11 @@ fail:
* Sets error code, but caller probably should override to disambiguate.
* NULL pms means re-use old master_secret.
*
- * This code is common to the bypass and PKCS11 execution paths.
+ * This code is common to the bypass and PKCS11 execution paths. For
+ * the bypass case, pms is NULL. If the old master secret is reused,
+ * pms is NULL and the master secret is already in either
+ * pwSpec->msItem.len (the bypass case) or pwSpec->master_secret.
+ *
* For the bypass case, pms is NULL.
*/
SECStatus
@@ -3583,13 +3591,70 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
return SECSuccess;
}
-/* This method uses PKCS11 to derive the MS from the PMS, where PMS
-** is a PKCS11 symkey. This is used in all cases except the
-** "triple bypass" with RSA key exchange.
-** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
+/* This method completes the derivation of the MS from the PMS.
+**
+** 1. Derive the MS, if possible, else return an error.
+**
+** 2. Check the version if |pms_version| is non-zero and if wrong,
+** return an error.
+**
+** 3. If |msp| is nonzero, return MS in |*msp|.
+
+** Called from:
+** ssl3_ComputeMasterSecretInt
+** tls_ComputeExtendedMasterSecretInt
*/
static SECStatus
-ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
+ssl3_ComputeMasterSecretFinish(sslSocket *ss,
+ CK_MECHANISM_TYPE master_derive,
+ CK_MECHANISM_TYPE key_derive,
+ CK_VERSION *pms_version,
+ SECItem *params, CK_FLAGS keyFlags,
+ PK11SymKey *pms, PK11SymKey **msp)
+{
+ PK11SymKey *ms = NULL;
+
+ ms = PK11_DeriveWithFlags(pms, master_derive,
+ params, key_derive,
+ CKA_DERIVE, 0, keyFlags);
+ if (!ms) {
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+
+ if (pms_version && ss->opt.detectRollBack) {
+ SSL3ProtocolVersion client_version;
+ client_version = pms_version->major << 8 | pms_version->minor;
+
+ if (IS_DTLS(ss)) {
+ client_version = dtls_DTLSVersionToTLSVersion(client_version);
+ }
+
+ if (client_version != ss->clientHelloVersion) {
+ /* Destroy MS. Version roll-back detected. */
+ PK11_FreeSymKey(ms);
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ if (msp) {
+ *msp = ms;
+ } else {
+ PK11_FreeSymKey(ms);
+ }
+
+ return SECSuccess;
+}
+
+/* Compute the ordinary (pre draft-ietf-tls-session-hash) master
+ ** secret and return it in |*msp|.
+ **
+ ** Called from: ssl3_ComputeMasterSecret
+ */
+static SECStatus
+ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
{
ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def;
@@ -3599,26 +3664,23 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
(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.
+ * data into a 48-byte value, and does not expect to return the version.
*/
PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
- SECStatus rv = SECFailure;
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;
CK_FLAGS keyFlags;
CK_VERSION pms_version;
+ CK_VERSION *pms_version_ptr = NULL;
/* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */
CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
unsigned int master_params_len;
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
- PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
if (isTLS12) {
if(isDH) master_derive = CKM_TLS12_MASTER_KEY_DERIVE_DH;
else master_derive = CKM_TLS12_MASTER_KEY_DERIVE;
@@ -3636,93 +3698,142 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
keyFlags = 0;
}
- if (pms || !pwSpec->master_secret) {
- if (isDH) {
- master_params.pVersion = NULL;
- } else {
- master_params.pVersion = &pms_version;
- }
- master_params.RandomInfo.pClientRandom = cr;
- master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
- master_params.RandomInfo.pServerRandom = sr;
- master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
- if (isTLS12) {
- master_params.prfHashMechanism = CKM_SHA256;
- master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
- } else {
- master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
- }
+ if (!isDH) {
+ pms_version_ptr = &pms_version;
+ }
- params.data = (unsigned char *) &master_params;
- params.len = master_params_len;
+ master_params.pVersion = pms_version_ptr;
+ master_params.RandomInfo.pClientRandom = cr;
+ master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+ master_params.RandomInfo.pServerRandom = sr;
+ master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+ if (isTLS12) {
+ master_params.prfHashMechanism = CKM_SHA256;
+ 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);
}
- if (pms != NULL) {
-#if defined(TRACE)
- if (ssl_trace >= 100) {
- SECStatus extractRV = PK11_ExtractKeyValue(pms);
- if (extractRV == SECSuccess) {
- SECItem * keyData = PK11_GetKeyData(pms);
- if (keyData && keyData->data && keyData->len) {
- ssl_PrintBuf(ss, "Pre-Master Secret",
- keyData->data, keyData->len);
- }
- }
- }
-#endif
- pwSpec->master_secret = PK11_DeriveWithFlags(pms, master_derive,
- &params, key_derive, CKA_DERIVE, 0, keyFlags);
- if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) {
- SSL3ProtocolVersion client_version;
- client_version = pms_version.major << 8 | pms_version.minor;
+ params.data = (unsigned char *) &master_params;
+ params.len = master_params_len;
- if (IS_DTLS(ss)) {
- client_version = dtls_DTLSVersionToTLSVersion(client_version);
- }
+ return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
+ pms_version_ptr, &params,
+ keyFlags, pms, msp);
+}
- if (client_version != ss->clientHelloVersion) {
- /* Destroy it. Version roll-back detected. */
- PK11_FreeSymKey(pwSpec->master_secret);
- pwSpec->master_secret = NULL;
- }
- }
- if (pwSpec->master_secret == NULL) {
- /* Generate a faux master secret in the same slot as the old one. */
- PK11SlotInfo * slot = PK11_GetSlotFromKey((PK11SymKey *)pms);
- PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
+/* Compute the draft-ietf-tls-session-hash master
+** secret and return it in |*msp|.
+**
+** Called from: ssl3_ComputeMasterSecret
+*/
+static SECStatus
+tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
+{
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+ CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params;
+ SSL3Hashes hashes;
+ /*
+ * Determine whether to use the DH/ECDH or RSA derivation modes.
+ */
+ /*
+ * TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
+ * mode. Bug 1198298 */
+ PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
+ (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
+ CK_MECHANISM_TYPE master_derive;
+ CK_MECHANISM_TYPE key_derive;
+ SECItem params;
+ const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY;
+ CK_VERSION pms_version;
+ CK_VERSION *pms_version_ptr = NULL;
+ SECStatus rv;
- PK11_FreeSlot(slot);
- if (fpms != NULL) {
- pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
- master_derive, &params, key_derive,
- CKA_DERIVE, 0, keyFlags);
- PK11_FreeSymKey(fpms);
- }
- }
+ rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0);
+ if (rv != SECSuccess) {
+ PORT_Assert(0); /* Should never fail */
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
}
- if (pwSpec->master_secret == NULL) {
- /* Generate a faux master secret from the internal slot. */
- PK11SlotInfo * slot = PK11_GetInternalSlot();
- PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
- PK11_FreeSlot(slot);
- if (fpms != NULL) {
- pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
- master_derive, &params, key_derive,
- CKA_DERIVE, 0, keyFlags);
- if (pwSpec->master_secret == NULL) {
- pwSpec->master_secret = fpms; /* use the fpms as the master. */
- fpms = NULL;
- }
- }
- if (fpms) {
- PK11_FreeSymKey(fpms);
- }
+ if (isDH) {
+ master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
+ } else {
+ master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
+ pms_version_ptr = &pms_version;
}
- if (pwSpec->master_secret == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
- return rv;
+
+ if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* TLS 1.2 */
+ extended_master_params.prfHashMechanism = CKM_SHA256;
+ key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
+ } else {
+ /* TLS < 1.2 */
+ extended_master_params.prfHashMechanism = CKM_TLS_PRF;
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
+ }
+
+ extended_master_params.pVersion = pms_version_ptr;
+ extended_master_params.pSessionHash = hashes.u.raw;
+ extended_master_params.ulSessionHashLen = hashes.len;
+
+ params.data = (unsigned char *) &extended_master_params;
+ params.len = sizeof extended_master_params;
+
+ return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
+ pms_version_ptr, &params,
+ keyFlags, pms, msp);
+}
+
+
+/* Wrapper method to compute the master secret and return it in |*msp|.
+**
+** Called from ssl3_ComputeMasterSecret
+*/
+static SECStatus
+ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
+ PK11SymKey **msp)
+{
+ PORT_Assert(pms != NULL);
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ return tls_ComputeExtendedMasterSecretInt(ss, pms, msp);
+ } else {
+ return ssl3_ComputeMasterSecretInt(ss, pms, msp);
+ }
+}
+
+/* This method uses PKCS11 to derive the MS from the PMS, where PMS
+** is a PKCS11 symkey. We call ssl3_ComputeMasterSecret to do the
+** computations and then modify the pwSpec->state as a side effect.
+**
+** This is used in all cases except the "triple bypass" with RSA key
+** exchange.
+**
+** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
+*/
+static SECStatus
+ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
+{
+ SECStatus rv;
+ PK11SymKey* ms = NULL;
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ if (pms) {
+ rv = ssl3_ComputeMasterSecret(ss, pms, &ms);
+ pwSpec->master_secret = ms;
+ if (rv != SECSuccess)
+ return rv;
}
+
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
SECItem * keydata;
@@ -3733,7 +3844,7 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
rv = PK11_ExtractKeyValue(pwSpec->master_secret);
if (rv != SECSuccess) {
return rv;
- }
+ }
/* This returns the address of the secItem inside the key struct,
* not a copy or a reference. So, there's no need to free it.
*/
@@ -3748,10 +3859,10 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
}
}
#endif
+
return SECSuccess;
}
-
/*
* Derive encryption and MAC Keys (and IVs) from master secret
* Sets a useful error code when returning SECFailure.
@@ -4584,11 +4695,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
/* compute them without PKCS11 */
PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
- if (!spec->msItem.data) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
sizeof(hashes->u.raw));
@@ -4607,15 +4713,15 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
#define md5cx ((MD5Context *)md5_cx)
#define shacx ((SHA1Context *)sha_cx)
- if (!spec->msItem.data) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx);
if (!isTLS) {
+ if (!spec->msItem.data) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
/* compute hashes for SSL3. */
unsigned char s[4];
@@ -4691,11 +4797,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
unsigned char stackBuf[1024];
unsigned char *stateBuf = NULL;
- if (!spec->master_secret) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
h = ss->ssl3.hs.sha;
stateBuf = PK11_SaveContextAlloc(h, stackBuf,
sizeof(stackBuf), &stateLen);
@@ -4735,11 +4836,6 @@ tls12_loser:
unsigned char md5StackBuf[256];
unsigned char shaStackBuf[512];
- if (!spec->master_secret) {
- PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
- return SECFailure;
- }
-
md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf,
sizeof md5StackBuf, &md5StateLen);
if (md5StateBuf == NULL) {
@@ -4757,6 +4853,11 @@ tls12_loser:
sha = ss->ssl3.hs.sha;
if (!isTLS) {
+ if (!spec->master_secret) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
/* compute hashes for SSL3. */
unsigned char s[4];
@@ -6005,14 +6106,6 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
}
}
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
isTLS ? enc_pms.len + 2 : enc_pms.len);
if (rv != SECSuccess) {
@@ -6027,6 +6120,15 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
rv = SECSuccess;
loser:
@@ -6096,14 +6198,6 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
SECKEY_DestroyPrivateKey(privKey);
privKey = NULL;
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
pubKey->u.dh.publicValue.len + 2);
if (rv != SECSuccess) {
@@ -6119,8 +6213,16 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
- rv = SECSuccess;
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ pms = NULL;
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ rv = SECSuccess;
loser:
@@ -6517,6 +6619,32 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECItem wrappedMS; /* wrapped master secret. */
+ /* [draft-ietf-tls-session-hash-06; Section 5.3]
+ *
+ * o If the original session did not use the "extended_master_secret"
+ * extension but the new ServerHello contains the extension, the
+ * client MUST abort the handshake.
+ */
+ if (!sid->u.ssl3.keys.extendedMasterSecretUsed &&
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ errCode = SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+
+ /*
+ * o If the original session used an extended master secret but the new
+ * ServerHello does not contain the "extended_master_secret"
+ * extension, the client SHOULD abort the handshake.
+ *
+ * TODO(ekr@rtfm.com): Add option to refuse to resume when EMS is not
+ * used at all (bug 1176526).
+ */
+ if (sid->u.ssl3.keys.extendedMasterSecretUsed &&
+ !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+
ss->sec.authAlgorithm = sid->authAlgorithm;
ss->sec.authKeyBits = sid->authKeyBits;
ss->sec.keaType = sid->keaType;
@@ -6618,7 +6746,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
}
- /* NULL value for PMS signifies re-use of the old MS */
+ /* NULL value for PMS because we are reusing the old MS */
rv = ssl3_InitPendingCipherSpec(ss, NULL);
if (rv != SECSuccess) {
goto alert_loser; /* err code was set */
@@ -6647,6 +6775,9 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
sid->u.ssl3.sessionIDLength = sidBytes.len;
PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
+ sid->u.ssl3.keys.extendedMasterSecretUsed =
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
+
ss->ssl3.hs.isResuming = PR_FALSE;
if (ss->ssl3.hs.kea_def->signKeyType != sign_null) {
/* All current cipher suites other than those with sign_null (i.e.,
@@ -7584,6 +7715,7 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
sid->u.ssl3.policy = SSL_ALLOWED;
sid->u.ssl3.clientWriteKey = NULL;
sid->u.ssl3.serverWriteKey = NULL;
+ sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
if (is_server) {
SECStatus rv;
@@ -8144,6 +8276,8 @@ compression_found:
/* If there are any failures while processing the old sid,
* we don't consider them to be errors. Instead, We just behave
* as if the client had sent us no sid to begin with, and make a new one.
+ * The exception here is attempts to resume extended_master_secret
+ * sessions without the extension, which causes an alert.
*/
if (sid != NULL) do {
ssl3CipherSpec *pwSpec;
@@ -8155,6 +8289,30 @@ compression_found:
break; /* not an error */
}
+ /* [draft-ietf-tls-session-hash-06; Section 5.3]
+ * o If the original session did not use the "extended_master_secret"
+ * extension but the new ClientHello contains the extension, then the
+ * server MUST NOT perform the abbreviated handshake. Instead, it
+ * SHOULD continue with a full handshake (as described in
+ * Section 5.2) to negotiate a new session.
+ *
+ * o If the original session used the "extended_master_secret"
+ * extension but the new ClientHello does not contain the extension,
+ * the server MUST abort the abbreviated handshake.
+ */
+ if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
+ if (!sid->u.ssl3.keys.extendedMasterSecretUsed) {
+ break; /* not an error */
+ }
+ } else {
+ if (sid->u.ssl3.keys.extendedMasterSecretUsed) {
+ /* Note: we do not destroy the session */
+ desc = handshake_failure;
+ errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
+ goto alert_loser;
+ }
+ }
+
if (ss->sec.ci.sid) {
if (ss->sec.uncache)
ss->sec.uncache(ss->sec.ci.sid);
@@ -8295,7 +8453,7 @@ compression_found:
haveSpecWriteLock = PR_FALSE;
}
- /* NULL value for PMS signifies re-use of the old MS */
+ /* NULL value for PMS because we are re-using the old MS */
rv = ssl3_InitPendingCipherSpec(ss, NULL);
if (rv != SECSuccess) {
errCode = PORT_GetError();
@@ -8486,6 +8644,8 @@ compression_found:
}
ss->sec.ci.sid = sid;
+ sid->u.ssl3.keys.extendedMasterSecretUsed =
+ ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
ss->ssl3.hs.isResuming = PR_FALSE;
ssl_GetXmitBufLock(ss);
rv = ssl3_SendServerHelloSequence(ss);
@@ -9496,7 +9656,6 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
PRUint32 length,
SECKEYPrivateKey *serverKey)
{
- PK11SymKey * pms;
#ifndef NO_PKCS11_BYPASS
unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
@@ -9541,6 +9700,13 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
+ /* We have not implemented a tls_ExtendedMasterKeyDeriveBypass
+ * and will not negotiate this extension in bypass mode. This
+ * assert just double-checks that.
+ */
+ PORT_Assert(
+ !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn));
+
/* TRIPLE BYPASS, get PMS directly from RSA decryption.
* Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer,
* then, check for version rollback attack, then
@@ -9568,8 +9734,8 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
}
}
/* have PMS, build MS without PKCS11 */
- rv = ssl3_MasterKeyDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
- PR_TRUE);
+ rv = ssl3_MasterSecretDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
+ PR_TRUE);
if (rv != SECSuccess) {
pwSpec->msItem.data = pwSpec->raw_master_secret;
pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
@@ -9579,46 +9745,101 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
} else
#endif
{
+ PK11SymKey *tmpPms[2] = {NULL, NULL};
+ PK11SlotInfo *slot;
+ int useFauxPms = 0;
+#define currentPms tmpPms[!useFauxPms]
+#define unusedPms tmpPms[useFauxPms]
+#define realPms tmpPms[1]
+#define fauxPms tmpPms[0]
+
#ifndef NO_PKCS11_BYPASS
double_bypass:
#endif
- /*
- * unwrap pms out of the incoming buffer
- * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
- * the unwrap. Rather, it is the mechanism with which the
- * unwrapped pms will be used.
- */
- pms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
- CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
- if (pms != NULL) {
- PRINT_BUF(60, (ss, "decrypted premaster secret:",
- PK11_GetKeyData(pms)->data,
- PK11_GetKeyData(pms)->len));
- } else {
- /* unwrap failed. Generate a bogus PMS and carry on. */
- PK11SlotInfo * slot = PK11_GetSlotFromPrivateKey(serverKey);
- ssl_GetSpecWriteLock(ss);
- pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
- ssl_ReleaseSpecWriteLock(ss);
- PK11_FreeSlot(slot);
- }
+ /*
+ * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1
+ * as we can within the constraints of the PKCS#11 interface.
+ *
+ * 1. Unconditionally generate a bogus PMS (what RFC 5246
+ * calls R).
+ * 2. Attempt the RSA decryption to recover the PMS (what
+ * RFC 5246 calls M).
+ * 3. Set PMS = (M == NULL) ? R : M
+ * 4. Use ssl3_ComputeMasterSecret(PMS) to attempt to derive
+ * the MS from PMS. This includes performing the version
+ * check and length check.
+ * 5. If either the initial RSA decryption failed or
+ * ssl3_ComputeMasterSecret(PMS) failed, then discard
+ * M and set PMS = R. Else, discard R and set PMS = M.
+ *
+ * We do two derivations here because we can't rely on having
+ * a function that only performs the PMS version and length
+ * check. The only redundant cost is that this runs the PRF,
+ * which isn't necessary here.
+ */
- if (pms == NULL) {
- /* last gasp. */
+ /* Generate the bogus PMS (R) */
+ slot = PK11_GetSlotFromPrivateKey(serverKey);
+ if (!PK11_DoesMechanism(slot, CKM_SSL3_MASTER_KEY_DERIVE)) {
+ slot = PK11_GetBestSlot(CKM_SSL3_MASTER_KEY_DERIVE, NULL);
+ if (!slot) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ ssl_GetSpecWriteLock(ss);
+ fauxPms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
+ ssl_ReleaseSpecWriteLock(ss);
+ PK11_FreeSlot(slot);
+
+ if (fauxPms == NULL) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
return SECFailure;
}
+ /*
+ * unwrap pms out of the incoming buffer
+ * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
+ * the unwrap. Rather, it is the mechanism with which the
+ * unwrapped pms will be used.
+ */
+ realPms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
+ CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
+ /* Temporarily use the PMS if unwrapping the real PMS fails. */
+ useFauxPms |= (realPms == NULL);
+
+ /* Attempt to derive the MS from the PMS. This is the only way to
+ * check the version field in the RSA PMS. If this fails, we
+ * then use the faux PMS in place of the PMS. Note that this
+ * operation should never fail if we are using the faux PMS
+ * since it is correctly formatted. */
+ rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL);
+
+ /* If we succeeded, then select the true PMS and discard the
+ * FPMS. Else, select the FPMS and select the true PMS */
+ useFauxPms |= (rv != SECSuccess);
+
+ if (unusedPms) {
+ PK11_FreeSymKey(unusedPms);
+ }
+
/* This step will derive the MS from the PMS, among other things. */
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms);
+ rv = ssl3_InitPendingCipherSpec(ss, currentPms);
+ PK11_FreeSymKey(currentPms);
}
if (rv != SECSuccess) {
SEND_ALERT
return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
}
+
+#undef currentPms
+#undef unusedPms
+#undef realPms
+#undef fauxPms
+
return SECSuccess;
}
diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c
index 5dbca1658..539ddbbab 100644
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -319,14 +319,6 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
SECKEY_DestroyPrivateKey(privKey);
privKey = NULL;
- rv = ssl3_InitPendingCipherSpec(ss, pms);
- PK11_FreeSymKey(pms); pms = NULL;
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
- goto loser;
- }
-
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
pubKey->u.ec.publicValue.len + 1);
if (rv != SECSuccess) {
@@ -343,6 +335,14 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms); pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
rv = SECSuccess;
loser:
diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c
index c45f29542..07d792944 100644
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -91,6 +91,12 @@ static PRInt32 ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
static SECStatus ssl3_ServerHandleDraftVersionXtn(sslSocket *ss, PRUint16 ex_type,
SECItem *data);
+static PRInt32 ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static SECStatus ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss,
+ PRUint16 ex_type,
+ SECItem *data);
+
/*
* Write bytes. Using this function means the SECItem structure
@@ -256,6 +262,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ -1, NULL }
};
@@ -270,6 +277,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ -1, NULL }
};
@@ -299,6 +307,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
{ ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
+ { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn},
/* any extra entries will appear as { 0, NULL } */
};
@@ -1182,6 +1191,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
+ cert_length /* cert */
+ 1 /* server name type */
+ srvNameLen /* name len + length field */
+ + 1 /* extendedMasterSecretUsed */
+ sizeof(ticket.ticket_lifetime_hint);
padding_length = AES_BLOCK_SIZE -
(ciphertext_length % AES_BLOCK_SIZE);
@@ -1280,6 +1290,11 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess) goto loser;
}
+ /* extendedMasterSecretUsed */
+ rv = ssl3_AppendNumberToItem(
+ &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1);
+ if (rv != SECSuccess) goto loser;
+
PORT_Assert(plaintext.len == padding_length);
for (i = 0; i < padding_length; i++)
plaintext.data[i] = (unsigned char)padding_length;
@@ -1637,9 +1652,10 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
goto loser;
}
- /* Read ticket_version (which is ignored for now.) */
+ /* Read ticket_version and reject if the version is wrong */
temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
- if (temp < 0) goto no_ticket;
+ if (temp != TLS_EX_SESS_TICKET_VERSION) goto no_ticket;
+
parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
/* Read SSLVersion. */
@@ -1740,6 +1756,13 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
parsed_session_ticket->srvName.type = nameType;
}
+ /* Read extendedMasterSecretUsed */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0)
+ goto no_ticket;
+ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+ parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
+
/* Done parsing. Check that all bytes have been consumed. */
if (buffer_len != padding_length)
goto no_ticket;
@@ -1786,6 +1809,8 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
parsed_session_ticket->ms_is_wrapped;
sid->u.ssl3.masterValid = PR_TRUE;
sid->u.ssl3.keys.resumable = PR_TRUE;
+ sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->
+ extendedMasterSecretUsed;
/* Copy over client cert from session ticket if there is one. */
if (parsed_session_ticket->peer_cert.data != NULL) {
@@ -2559,3 +2584,90 @@ ssl3_ServerHandleDraftVersionXtn(sslSocket * ss, PRUint16 ex_type,
return SECSuccess;
}
+
+static PRInt32
+ssl3_SendExtendedMasterSecretXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+
+ if (!ss->opt.enableExtendedMS) {
+ return 0;
+ }
+
+#ifndef NO_PKCS11_BYPASS
+ /* Extended MS can only be used w/o bypass mode */
+ if (ss->opt.bypassPKCS11) {
+ PORT_Assert(0);
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return -1;
+ }
+#endif
+
+ /* Always send the extension in this function, since the
+ * client always sends it and this function is only called on
+ * the server if we negotiated the extension. */
+ extension_length = 4; /* Type + length (0) */
+ if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+
+ if (append) {
+ SECStatus rv;
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_extended_master_secret_xtn;
+ }
+
+ return extension_length;
+
+loser:
+ return -1;
+}
+
+
+static SECStatus
+ssl3_HandleExtendedMasterSecretXtn(sslSocket * ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) {
+ return SECSuccess;
+ }
+
+ if (!ss->opt.enableExtendedMS) {
+ return SECSuccess;
+ }
+
+#ifndef NO_PKCS11_BYPASS
+ /* Extended MS can only be used w/o bypass mode */
+ if (ss->opt.bypassPKCS11) {
+ PORT_Assert(0);
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+ }
+#endif
+
+ if (data->len != 0) {
+ SSL_TRC(30, ("%d: SSL3[%d]: Bogus extended master secret extension",
+ SSL_GETPID(), ss->fd));
+ return SECFailure;
+ }
+
+ SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.",
+ SSL_GETPID(), ss->fd));
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ if (ss->sec.isServer) {
+ return ssl3_RegisterServerHelloExtensionSender(
+ ss, ex_type, ssl3_SendExtendedMasterSecretXtn);
+ }
+ return SECSuccess;
+}
diff --git a/lib/ssl/sslerr.h b/lib/ssl/sslerr.h
index 4e905438e..192a10758 100644
--- a/lib/ssl/sslerr.h
+++ b/lib/ssl/sslerr.h
@@ -205,6 +205,9 @@ SSL_ERROR_RX_SHORT_DTLS_READ = (SSL_ERROR_BASE + 133),
SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 134),
SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 135),
+SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 136),
+SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET = (SSL_ERROR_BASE + 137),
+
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index e155a0800..41b51d8a8 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -346,6 +346,7 @@ typedef struct sslOptionsStr {
unsigned int reuseServerECDHEKey : 1; /* 28 */
unsigned int enableFallbackSCSV : 1; /* 29 */
unsigned int enableServerDhe : 1; /* 30 */
+ unsigned int enableExtendedMS : 1; /* 31 */
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -518,6 +519,7 @@ typedef struct {
PRUint16 wrapped_master_secret_len;
PRUint8 msIsWrapped;
PRUint8 resumable;
+ PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
typedef struct {
@@ -1070,6 +1072,7 @@ typedef struct SessionTicketStr {
CK_MECHANISM_TYPE msWrapMech;
PRUint16 ms_length;
SSL3Opaque master_secret[48];
+ PRBool extendedMasterSecretUsed;
ClientIdentity client_identity;
SECItem peer_cert;
PRUint32 timestamp;
@@ -1595,7 +1598,7 @@ extern PRBool ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
extern SECStatus ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec * pwSpec,
const unsigned char * cr, const unsigned char * sr,
PRBool isTLS, PRBool isExport);
-extern SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec,
+extern SECStatus ssl3_MasterSecretDeriveBypass( ssl3CipherSpec * pwSpec,
const unsigned char * cr, const unsigned char * sr,
const SECItem * pms, PRBool isTLS, PRBool isRSA);
@@ -1846,7 +1849,7 @@ extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
/* Tell clients to consider tickets valid for this long. */
#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
-#define TLS_EX_SESS_TICKET_VERSION (0x0100)
+#define TLS_EX_SESS_TICKET_VERSION (0x0101)
extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data,
unsigned int length);
diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c
index d2df8c2ec..216ab0fa0 100644
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -67,6 +67,8 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.creationTime = sid->creationTime;
inf.lastAccessTime = sid->lastAccessTime;
inf.expirationTime = sid->expirationTime;
+ inf.extendedMasterSecretUsed = sid->u.ssl3.keys.extendedMasterSecretUsed;
+
if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
inf.sessionIDLength = SSL2_SESSIONID_BYTES;
memcpy(inf.sessionID, sid->u.ssl2.sessionID,
diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c
index 6d908c86e..16bfbe49b 100644
--- a/lib/ssl/sslsnce.c
+++ b/lib/ssl/sslsnce.c
@@ -120,14 +120,14 @@ struct sidCacheEntryStr {
/* 2 */ ssl3CipherSuite cipherSuite;
/* 2 */ PRUint16 compression; /* SSLCompressionMethod */
-/* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
+/* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
/* 4 */ PRUint32 masterWrapMech;
/* 4 */ SSL3KEAType exchKeyType;
/* 4 */ PRInt32 certIndex;
/* 4 */ PRInt32 srvNameIndex;
/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
-/*104 */} ssl3;
+/*108 */} ssl3;
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
struct {
/*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
@@ -507,7 +507,6 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
to->sessionIDLength = from->u.ssl3.sessionIDLength;
to->u.ssl3.certIndex = -1;
to->u.ssl3.srvNameIndex = -1;
-
PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
to->sessionIDLength);
@@ -637,7 +636,7 @@ ConvertToSID(sidCacheEntry * from,
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
-
+
return to;
loser:
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index 2ab9d2d52..f73500925 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -85,6 +85,7 @@ static sslOptions ssl_defaults = {
PR_TRUE, /* reuseServerECDHEKey */
PR_FALSE, /* enableFallbackSCSV */
PR_TRUE, /* enableServerDhe */
+ PR_FALSE /* enableExtendedMS */
};
/*
@@ -825,6 +826,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
ss->opt.enableServerDhe = on;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ ss->opt.enableExtendedMS = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -901,6 +906,8 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
on = ss->opt.reuseServerECDHEKey; break;
case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break;
case SSL_ENABLE_SERVER_DHE: on = ss->opt.enableServerDhe; break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ on = ss->opt.enableExtendedMS; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -973,6 +980,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
case SSL_ENABLE_SERVER_DHE:
on = ssl_defaults.enableServerDhe;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ on = ssl_defaults.enableExtendedMS;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1160,6 +1170,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
ssl_defaults.enableServerDhe = on;
break;
+ case SSL_ENABLE_EXTENDED_MASTER_SECRET:
+ ssl_defaults.enableExtendedMS = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
index f9d83c851..cd742bbb2 100644
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -145,6 +145,12 @@ typedef struct SSLChannelInfoStr {
/* compression method info */
const char * compressionMethodName;
SSLCompressionMethod compressionMethod;
+
+ /* The following fields are added in NSS 3.21.
+ * This field only has meaning in TLS < 1.3 and will be set to
+ * PR_FALSE in TLS 1.3.
+ */
+ PRBool extendedMasterSecretUsed;
} SSLChannelInfo;
/* Preliminary channel info */
@@ -229,13 +235,14 @@ typedef enum {
ssl_use_srtp_xtn = 14,
ssl_app_layer_protocol_xtn = 16,
ssl_padding_xtn = 21,
+ ssl_extended_master_secret_xtn = 23,
ssl_session_ticket_xtn = 35,
ssl_next_proto_nego_xtn = 13172,
ssl_renegotiation_info_xtn = 0xff01,
ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */
} SSLExtensionType;
-#define SSL_MAX_EXTENSIONS 11 /* doesn't include ssl_padding_xtn. */
+#define SSL_MAX_EXTENSIONS 12 /* doesn't include ssl_padding_xtn. */
typedef enum {
ssl_dhe_group_none = 0,