Bug 1057463: TLS 1.3 draft-11 1-RTT mode. EXPERIMENTAL USE ONLY. r=mt,wtc,ttaubert
authorEKR <ekr@rtfm.com>
Mon, 24 Aug 2015 16:23:37 -0700
changeset 11831 2716b2d7fe80bfd91758e8ea54009896f0d73a1a
parent 11830 d6ecb8117a436848f339be85ca0f78e6fc02ebbf
child 11832 96787f9c7785f77e3f19155d3b3db5de32e30a7e
push id945
push userekr@mozilla.com
push dateTue, 02 Feb 2016 17:00:55 +0000
reviewersmt, wtc, ttaubert
bugs1057463
Bug 1057463: TLS 1.3 draft-11 1-RTT mode. EXPERIMENTAL USE ONLY. r=mt,wtc,ttaubert
coreconf/config.mk
external_tests/ssl_gtest/manifest.mn
external_tests/ssl_gtest/ssl_extension_unittest.cc
external_tests/ssl_gtest/ssl_loopback_unittest.cc
external_tests/ssl_gtest/test_io.cc
external_tests/ssl_gtest/tls_agent.cc
external_tests/ssl_gtest/tls_agent.h
external_tests/ssl_gtest/tls_connect.cc
external_tests/ssl_gtest/tls_connect.h
external_tests/ssl_gtest/tls_hkdf_unittest.cc
lib/ssl/SSLerrs.h
lib/ssl/config.mk
lib/ssl/dtlscon.c
lib/ssl/manifest.mn
lib/ssl/ssl3con.c
lib/ssl/ssl3ecc.c
lib/ssl/ssl3ext.c
lib/ssl/ssl3prot.h
lib/ssl/sslerr.h
lib/ssl/sslimpl.h
lib/ssl/sslinfo.c
lib/ssl/sslsock.c
lib/ssl/sslt.h
lib/ssl/tls13con.c
lib/ssl/tls13con.h
lib/ssl/tls13hkdf.c
lib/ssl/tls13hkdf.h
--- a/coreconf/config.mk
+++ b/coreconf/config.mk
@@ -188,8 +188,16 @@ DEFINES += -DNO_NSPR_10_SUPPORT
 
 # Hide old, deprecated, TLS cipher suite names when building NSS
 DEFINES += -DSSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES
 
 # Mozilla's mozilla/modules/zlib/src/zconf.h adds the MOZ_Z_ prefix to zlib
 # exported symbols, which causes problem when NSS is built as part of Mozilla.
 # So we add a NSS_ENABLE_SSL_ZLIB variable to allow Mozilla to turn this off.
 NSS_ENABLE_SSL_ZLIB = 1
+
+# Allow build-time configuration of TLS 1.3 (Experimental)
+ifdef NSS_ENABLE_TLS_1_3
+ifdef NSS_DISABLE_ECC
+$(error Setting NSS_ENABLE_TLS_1_3 and NSS_DISABLE_ECC isn't a good idea.)
+endif
+DEFINES += -DNSS_ENABLE_TLS_1_3
+endif
--- a/external_tests/ssl_gtest/manifest.mn
+++ b/external_tests/ssl_gtest/manifest.mn
@@ -15,20 +15,22 @@ CPPSRCS = \
       ssl_agent_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_extension_unittest.cc \
       ssl_skip_unittest.cc \
       ssl_gtest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
+      tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_parser.cc \
       $(NULL)
 
-INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include
+INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
+            -I$(CORE_DEPTH)/external_tests/common
 
 REQUIRES = nspr nss libdbm gtest
 
 PROGRAM = ssl_gtest
 EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX)
 
 USE_STATIC_LIBS = 1
--- a/external_tests/ssl_gtest/ssl_extension_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_extension_unittest.cc
@@ -326,16 +326,25 @@ class TlsExtensionTest12Plus
   : public TlsExtensionTestBase,
     public ::testing::WithParamInterface<std::string> {
  public:
   TlsExtensionTest12Plus()
     : TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
                            SSL_LIBRARY_VERSION_TLS_1_2) {}
 };
 
+class TlsExtensionTest13
+  : public TlsExtensionTestBase,
+    public ::testing::WithParamInterface<std::string> {
+ public:
+  TlsExtensionTest13()
+    : TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
+                           SSL_LIBRARY_VERSION_TLS_1_3) {}
+};
+
 class TlsExtensionTestGeneric
   : public TlsExtensionTestBase,
     public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
  public:
   TlsExtensionTestGeneric()
     : TlsExtensionTestBase(TlsConnectTestBase::ToMode((std::get<0>(GetParam()))),
                            std::get<1>(GetParam())) {}
 };
@@ -708,22 +717,33 @@ TEST_P(TlsExtensionTestGeneric, SignedCe
 
   SignedCertificateTimestampsExtractor timestamps_extractor(*client_);
   Handshake();
   CheckConnected();
   timestamps_extractor.assertTimestamps(DataBuffer());
 }
 
 
+// Temporary test to verify that we choke on an empty ClientKeyShare.
+// This test will fail when we implement HelloRetryRequest.
+TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
+  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_tls13_key_share_xtn, 2),
+                       kTlsAlertHandshakeFailure);
+}
+
 INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsV10));
 INSTANTIATE_TEST_CASE_P(ExtensionVariants, TlsExtensionTestGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV11V12));
 INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
                         TlsConnectTestBase::kTlsModesAll);
+#ifdef NSS_ENABLE_TLS_1_3
+INSTANTIATE_TEST_CASE_P(ExtensionTls13, TlsExtensionTest13,
+                        TlsConnectTestBase::kTlsModesStream);
+#endif
 INSTANTIATE_TEST_CASE_P(ExtensionDgram, TlsExtensionTestDtls,
                         TlsConnectTestBase::kTlsV11V12);
 
 }  // namespace nspr_test
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -86,24 +86,24 @@ class TlsServerKeyExchangeEcdhe {
   DataBuffer public_key_;
 };
 
 TEST_P(TlsConnectGeneric, SetupOnly) {}
 
 TEST_P(TlsConnectGeneric, Connect) {
   SetExpectedVersion(std::get<1>(GetParam()));
   Connect();
-  client_->CheckAuthType(ssl_auth_rsa);
+  CheckAuthType(ssl_auth_rsa);
 }
 
 TEST_P(TlsConnectGeneric, ConnectEcdsa) {
   SetExpectedVersion(std::get<1>(GetParam()));
   ResetEcdsa();
   Connect();
-  client_->CheckAuthType(ssl_auth_ecdsa);
+  CheckAuthType(ssl_auth_ecdsa);
 }
 
 TEST_P(TlsConnectGeneric, ConnectFalseStart) {
   client_->EnableFalseStart();
   Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumed) {
@@ -228,16 +228,41 @@ TEST_P(TlsConnectGeneric, ResumeWithHigh
 
 TEST_P(TlsConnectGeneric, ClientAuth) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   server_->CheckAuthType(ssl_auth_rsa);
 }
 
+// Temporary copy for TLS 1.3 because 1.3 is stream only.
+TEST_P(TlsConnectStream, ClientAuth) {
+  client_->SetupClientAuth();
+  server_->RequestClientAuth(true);
+  Connect();
+  server_->CheckAuthType(ssl_auth_rsa);
+}
+
+// In TLS 1.3, the client sends its cert rejection on the
+// second flight, and since it has already received the
+// server's Finished, it transitions to complete and
+// then gets an alert from the server. The test harness
+// doesn't handle this right yet.
+TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) {
+  server_->RequestClientAuth(true);
+  ConnectExpectFail();
+}
+
+TEST_P(TlsConnectStream, ClientAuthRequestedRejected) {
+  server_->RequestClientAuth(false);
+  Connect();
+  server_->CheckAuthType(ssl_auth_rsa);
+}
+
+
 TEST_P(TlsConnectGeneric, ClientAuthEcdsa) {
   ResetEcdsa();
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   server_->CheckAuthType(ssl_auth_ecdsa);
 }
 
@@ -294,17 +319,24 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
 TEST_P(TlsConnectGeneric, SignatureAlgorithmNoOverlapStaticRsa) {
   client_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->SetSignatureAlgorithms(SignatureRsaSha256,
                                   PR_ARRAY_SIZE(SignatureRsaSha256));
   DisableDheAndEcdheCiphers();
   Connect();
   client_->CheckKEAType(ssl_kea_rsa);
-  client_->CheckAuthType(ssl_auth_rsa);
+  CheckAuthType(ssl_auth_rsa);
+}
+
+TEST_P(TlsConnectStreamPre13, ConnectStaticRSA) {
+  DisableDheCiphers();
+  Connect();
+  client_->CheckKEAType(ssl_kea_rsa);
+  CheckAuthType(ssl_auth_rsa);
 }
 
 // Signature algorithms governs both verification and generation of signatures.
 // With ECDSA, we need to at least have a common signature algorithm configured.
 TEST_P(TlsConnectTls12, SignatureAlgorithmNoOverlapEcdsa) {
   ResetEcdsa();
   client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha384));
@@ -334,70 +366,74 @@ TEST_P(TlsConnectTls12, RequestClientAut
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
 }
 
+// Temporary copy to test Alpn with TLS 1.3.
+TEST_P(TlsConnectStream, ConnectAlpn) {
+  EnableAlpn();
+  Connect();
+  client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
+  server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
+}
+
 TEST_P(TlsConnectDatagram, ConnectSrtp) {
   EnableSrtp();
   Connect();
   CheckSrtp();
 }
 
-TEST_P(TlsConnectStream, ConnectAndClientRenegotiate) {
+// 1.3 is disabled in the next few tests because we don't
+// presently support resumption in 1.3.
+TEST_P(TlsConnectStreamPre13, ConnectAndClientRenegotiate) {
   Connect();
   server_->PrepareForRenegotiate();
   client_->StartRenegotiate();
   Handshake();
   CheckConnected();
 }
 
-TEST_P(TlsConnectStream, ConnectAndServerRenegotiate) {
+TEST_P(TlsConnectStreamPre13, ConnectAndServerRenegotiate) {
   Connect();
   client_->PrepareForRenegotiate();
   server_->StartRenegotiate();
   Handshake();
   CheckConnected();
 }
 
-TEST_P(TlsConnectStream, ConnectStaticRSA) {
-  DisableDheAndEcdheCiphers();
-  Connect();
-  client_->CheckKEAType(ssl_kea_rsa);
-}
-
-TEST_P(TlsConnectStream, ConnectDhe) {
+TEST_P(TlsConnectStreamPre13, ConnectDhe) {
   DisableEcdheCiphers();
   Connect();
   client_->CheckKEAType(ssl_kea_dh);
 }
 
 // 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) {
+TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
   DisableDheAndEcdheCiphers();
   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) {
+TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
   DisableDheAndEcdheCiphers();
   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());
@@ -411,70 +447,70 @@ TEST_P(TlsConnectGeneric, ConnectStaticR
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 TEST_P(TlsConnectStream, ConnectEcdhe) {
   Connect();
-  client_->CheckKEAType(ssl_kea_ecdh);
-}
+  CheckKEAType(ssl_kea_ecdh);
+  }
 
-TEST_P(TlsConnectStream, ConnectEcdheTwiceReuseKey) {
+TEST_P(TlsConnectStreamPre13, ConnectEcdheTwiceReuseKey) {
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
-  client_->CheckKEAType(ssl_kea_ecdh);
+  CheckKEAType(ssl_kea_ecdh);
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   ResetRsa();
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
-  client_->CheckKEAType(ssl_kea_ecdh);
+  CheckKEAType(ssl_kea_ecdh);
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are the same.
   EXPECT_EQ(dhe1.public_key_.len(), dhe2.public_key_.len());
   EXPECT_TRUE(!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                       dhe1.public_key_.len()));
 }
 
-TEST_P(TlsConnectStream, ConnectEcdheTwiceNewKey) {
+TEST_P(TlsConnectStreamPre13, ConnectEcdheTwiceNewKey) {
   server_->EnsureTlsSetup();
   SECStatus rv =
       SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
-  client_->CheckKEAType(ssl_kea_ecdh);
+  CheckKEAType(ssl_kea_ecdh);
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   ResetRsa();
   server_->EnsureTlsSetup();
   rv = SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
-  client_->CheckKEAType(ssl_kea_ecdh);
+  CheckKEAType(ssl_kea_ecdh);
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are different.
   EXPECT_FALSE((dhe1.public_key_.len() == dhe2.public_key_.len()) &&
                (!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                         dhe1.public_key_.len())));
@@ -535,46 +571,46 @@ TEST_P(TlsConnectGeneric, ConnectExtende
 
 TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretStaticRSA) {
   DisableDheAndEcdheCiphers();
   EnableExtendedMasterSecret();
   Connect();
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
-TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusCKE) {
+TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusCKE) {
   DisableDheAndEcdheCiphers();
   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) {
+TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
   DisableDheAndEcdheCiphers();
   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) {
+TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
   DisableDheAndEcdheCiphers();
   EnableExtendedMasterSecret();
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
@@ -583,69 +619,122 @@ TEST_P(TlsConnectGeneric, ConnectExtende
   Connect();
 
   ResetRsa();
   EnableExtendedMasterSecret();
   ExpectResumption(RESUME_SESSIONID);
   Connect();
 }
 
-TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretTicket) {
+TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretTicket) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   EnableExtendedMasterSecret();
   Connect();
 
   ResetRsa();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
 
   EnableExtendedMasterSecret();
   ExpectResumption(RESUME_TICKET);
   Connect();
 }
 
-TEST_P(TlsConnectGeneric,
+TEST_P(TlsConnectGenericPre13,
        ConnectExtendedMasterSecretClientOnly) {
   client_->EnableExtendedMasterSecret();
   ExpectExtendedMasterSecret(false);
   Connect();
 }
 
-TEST_P(TlsConnectGeneric,
+TEST_P(TlsConnectGenericPre13,
        ConnectExtendedMasterSecretServerOnly) {
   server_->EnableExtendedMasterSecret();
   ExpectExtendedMasterSecret(false);
   Connect();
 }
 
-TEST_P(TlsConnectGeneric,
+TEST_P(TlsConnectGenericPre13,
        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,
+TEST_P(TlsConnectGenericPre13,
        ConnectNormalResumeWithExtendedMasterSecret) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
   ExpectExtendedMasterSecret(false);
   Connect();
 
   ResetRsa();
   EnableExtendedMasterSecret();
   ExpectResumption(RESUME_NONE);
   Connect();
 }
 
+TEST_P(TlsConnectStream, ConnectWithCompressionMaybe)
+{
+  EnsureTlsSetup();
+  client_->EnableCompression();
+  server_->EnableCompression();
+  Connect();
+  EXPECT_EQ(client_->version() < SSL_LIBRARY_VERSION_TLS_1_3, client_->is_compressed());
+  SendReceive();
+}
+
+
+TEST_P(TlsConnectStream, ConnectSendReceive) {
+  Connect();
+  SendReceive();
+}
+
+TEST_P(TlsConnectStream, ServerNegotiateTls10) {
+  uint16_t minver, maxver;
+  client_->GetVersionRange(&minver, &maxver);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
+                           maxver);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
+                           SSL_LIBRARY_VERSION_TLS_1_0);
+  Connect();
+}
+
+TEST_P(TlsConnectStream, ServerNegotiateTls11) {
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_1)
+    return;
+
+  uint16_t minver, maxver;
+  client_->GetVersionRange(&minver, &maxver);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           maxver);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_1);
+  Connect();
+}
+
+TEST_P(TlsConnectStream, ServerNegotiateTls12) {
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_2)
+    return;
+
+  uint16_t minver, maxver;
+  client_->GetVersionRange(&minver, &maxver);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           maxver);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_2);
+  Connect();
+}
+
+
 INSTANTIATE_TEST_CASE_P(VariantsStream10, TlsConnectGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsV10));
 INSTANTIATE_TEST_CASE_P(VariantsAll, TlsConnectGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV11V12));
@@ -660,10 +749,13 @@ INSTANTIATE_TEST_CASE_P(Pre12Stream, Tls
 INSTANTIATE_TEST_CASE_P(Pre12All, TlsConnectPre12,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV11));
 INSTANTIATE_TEST_CASE_P(VersionsStream10, TlsConnectStream,
                         TlsConnectTestBase::kTlsV10);
 INSTANTIATE_TEST_CASE_P(VersionsStream, TlsConnectStream,
                         TlsConnectTestBase::kTlsV11V12);
-
+#ifdef NSS_ENABLE_TLS_1_3
+INSTANTIATE_TEST_CASE_P(VersionsStream13, TlsConnectStream,
+                        TlsConnectTestBase::kTlsV13);
+#endif
 }  // namespace nspr_test
--- a/external_tests/ssl_gtest/test_io.cc
+++ b/external_tests/ssl_gtest/test_io.cc
@@ -427,17 +427,17 @@ void Poller::Cancel(Event event, DummyPr
 void Poller::SetTimer(uint32_t timer_ms, PollTarget *target, PollCallback cb,
                       Timer **timer) {
   Timer *t = new Timer(PR_Now() + timer_ms * 1000, target, cb);
   timers_.push(t);
   if (timer) *timer = t;
 }
 
 bool Poller::Poll() {
-  std::cerr << "Poll()\n";
+  std::cerr << "Poll() waiters = " << waiters_.size() << std::endl;
   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
   PRTime now = PR_Now();
   bool fired = false;
 
   // Figure out the timer for the select.
   if (!timers_.empty()) {
     Timer *first_timer = timers_.top();
     if (now >= first_timer->deadline_) {
--- a/external_tests/ssl_gtest/tls_agent.cc
+++ b/external_tests/ssl_gtest/tls_agent.cc
@@ -19,16 +19,17 @@ namespace nss_test {
 
 
 const char* TlsAgent::states[] = {"INIT", "CONNECTING", "CONNECTED", "ERROR"};
 
 TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode, SSLKEAType kea)
   : name_(name),
     mode_(mode),
     kea_(kea),
+    server_key_bits_(0),
     pr_fd_(nullptr),
     adapter_(nullptr),
     ssl_fd_(nullptr),
     role_(role),
     state_(STATE_INIT),
     falsestart_enabled_(false),
     expected_version_(0),
     expected_cipher_suite_(0),
@@ -80,16 +81,22 @@ bool TlsAgent::EnsureTlsSetup() {
   if (!ssl_fd_) return false;
   pr_fd_ = nullptr;
 
   if (role_ == SERVER) {
     CERTCertificate* cert = PK11_FindCertFromNickname(name_.c_str(), nullptr);
     EXPECT_NE(nullptr, cert);
     if (!cert) return false;
 
+    SECKEYPublicKey* pub = CERT_ExtractPublicKey(cert);
+    EXPECT_NE(nullptr, pub);
+    if (!pub) return false;  // Leak cert.
+    server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub);
+    SECKEY_DestroyPublicKey(pub);
+
     SECKEYPrivateKey* priv = PK11_FindKeyByAnyCert(cert, nullptr);
     EXPECT_NE(nullptr, priv);
     if (!priv) return false;  // Leak cert.
 
     SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kea_);
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;  // Leak cert and key.
 
@@ -216,20 +223,29 @@ void TlsAgent::SetVersionRange(uint16_t 
    vrange_.max = maxver;
 
    if (ssl_fd_) {
      SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
      EXPECT_EQ(SECSuccess, rv);
    }
 }
 
+void TlsAgent::GetVersionRange(uint16_t* minver, uint16_t* maxver) {
+  *minver = vrange_.min;
+  *maxver = vrange_.max;
+}
+
 void TlsAgent::SetExpectedVersion(uint16_t version) {
   expected_version_ = version;
 }
 
+void TlsAgent::SetServerKeyBits(uint16_t bits) {
+  server_key_bits_ = bits;
+}
+
 void TlsAgent::SetExpectedReadError(bool err) {
   expected_read_error_ = err;
 }
 
 void TlsAgent::SetSignatureAlgorithms(const SSLSignatureAndHashAlg* algorithms,
                                       size_t count) {
   EXPECT_TRUE(EnsureTlsSetup());
   EXPECT_LE(count, SSL_SignatureMaxCount());
@@ -268,16 +284,30 @@ void TlsAgent::SetSignatureAlgorithms(co
     }
   }
   EXPECT_EQ(i, configuredCount) << "algorithms in use were all set";
 }
 
 void TlsAgent::CheckKEAType(SSLKEAType type) const {
   EXPECT_EQ(STATE_CONNECTED, state_);
   EXPECT_EQ(type, csinfo_.keaType);
+  /* Check the length */
+  switch (type) {
+      case ssl_kea_ecdh:
+          EXPECT_EQ(256, info_.keaKeyBits);
+          break;
+      case ssl_kea_dh:
+          EXPECT_EQ(2048, info_.keaKeyBits);
+          break;
+      case ssl_kea_rsa:
+          EXPECT_EQ(server_key_bits_, info_.keaKeyBits);
+          break;
+      default:
+          break;
+  }
 }
 
 void TlsAgent::CheckAuthType(SSLAuthType type) const {
   EXPECT_EQ(STATE_CONNECTED, state_);
   EXPECT_EQ(type, csinfo_.authAlgorithm);
 }
 
 void TlsAgent::EnableFalseStart() {
@@ -402,38 +432,47 @@ void TlsAgent::EnableExtendedMasterSecre
   SECStatus rv = SSL_OptionSet(ssl_fd_,
                                SSL_ENABLE_EXTENDED_MASTER_SECRET,
                                PR_TRUE);
 
   ASSERT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::CheckExtendedMasterSecret(bool expected) {
+  if (version() >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    expected = PR_TRUE;
+  }
   ASSERT_EQ(expected, info_.extendedMasterSecretUsed != PR_FALSE)
       << "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::EnableCompression() {
+  ASSERT_TRUE(EnsureTlsSetup());
+
+  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_DEFLATE, PR_TRUE);
+  ASSERT_EQ(SECSuccess, rv);
+}
+
 void TlsAgent::Handshake() {
   SECStatus rv = SSL_ForceHandshake(ssl_fd_);
   if (rv == SECSuccess) {
     Connected();
 
     Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
                              &TlsAgent::ReadableCallback);
-
     return;
   }
 
   int32_t err = PR_GetError();
   switch (err) {
     case PR_WOULD_BLOCK_ERROR:
       LOG("Would have blocked");
       // TODO(ekr@rtfm.com): set DTLS timeouts
--- a/external_tests/ssl_gtest/tls_agent.h
+++ b/external_tests/ssl_gtest/tls_agent.h
@@ -80,18 +80,20 @@ class TlsAgent : public PollTarget {
   void RequestClientAuth(bool requireAuth);
   bool GetClientAuthCredentials(CERTCertificate** cert,
                                 SECKEYPrivateKey** priv) const;
 
   void ConfigureSessionCache(SessionResumptionMode mode);
   void SetSessionTicketsEnabled(bool en);
   void SetSessionCacheEnabled(bool en);
   void SetVersionRange(uint16_t minver, uint16_t maxver);
+  void GetVersionRange(uint16_t* minver, uint16_t* maxver);
   void CheckPreliminaryInfo();
   void SetExpectedVersion(uint16_t version);
+  void SetServerKeyBits(uint16_t bits);
   void SetExpectedReadError(bool err);
   void EnableFalseStart();
   void ExpectResumption();
   void SetSignatureAlgorithms(const SSLSignatureAndHashAlg* algorithms,
                               size_t count);
   void EnableAlpn(const uint8_t* val, size_t len);
   void CheckAlpn(SSLNextProtoState expected_state,
                  const std::string& expected) const;
@@ -99,30 +101,35 @@ class TlsAgent : public PollTarget {
   void CheckSrtp() const;
   void CheckErrorCode(int32_t expected) const;
   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();
+  void EnableCompression();
 
   Role role() const { return role_; }
 
   State state() const { return state_; }
 
   SSLKEAType kea() const { return kea_; }
 
   const char* state_str() const { return state_str(state()); }
 
   const char* state_str(State state) const { return states[state]; }
 
   PRFileDesc* ssl_fd() { return ssl_fd_; }
   DummyPrSocket* adapter() { return adapter_; }
 
+  bool is_compressed() const {
+    return info_.compressionMethod != ssl_compression_null;
+  }
+  uint16_t server_key_bits() const { return server_key_bits_; }
   uint16_t min_version() const { return vrange_.min; }
   uint16_t max_version() const { return vrange_.max; }
   uint16_t version() const {
     EXPECT_EQ(STATE_CONNECTED, state_);
     return info_.protocolVersion;
   }
 
   bool cipher_suite(int16_t* cipher_suite) const {
@@ -244,16 +251,17 @@ class TlsAgent : public PollTarget {
   }
 
   void CheckCallbacks() const;
   void Connected();
 
   const std::string name_;
   Mode mode_;
   SSLKEAType kea_;
+  uint16_t server_key_bits_;
   PRFileDesc* pr_fd_;
   DummyPrSocket* adapter_;
   PRFileDesc* ssl_fd_;
   Role role_;
   State state_;
   bool falsestart_enabled_;
   uint16_t expected_version_;
   uint16_t expected_cipher_suite_;
--- a/external_tests/ssl_gtest/tls_connect.cc
+++ b/external_tests/ssl_gtest/tls_connect.cc
@@ -30,27 +30,32 @@ static const uint16_t kTlsV11Arr[] = {SS
 static const uint16_t kTlsV11V12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_1,
                                          SSL_LIBRARY_VERSION_TLS_1_2};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV11V12 = ::testing::ValuesIn(kTlsV11V12Arr);
 // TODO: add TLS 1.3
 static const uint16_t kTlsV12PlusArr[] = {SSL_LIBRARY_VERSION_TLS_1_2};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV12Plus = ::testing::ValuesIn(kTlsV12PlusArr);
+static const uint16_t kTlsV13Arr[] = {SSL_LIBRARY_VERSION_TLS_1_3};
+::testing::internal::ParamGenerator<uint16_t>
+  TlsConnectTestBase::kTlsV13 = ::testing::ValuesIn(kTlsV13Arr);
 
 static std::string VersionString(uint16_t version) {
   switch(version) {
   case 0:
     return "(no version)";
   case SSL_LIBRARY_VERSION_TLS_1_0:
     return "1.0";
   case SSL_LIBRARY_VERSION_TLS_1_1:
     return "1.1";
   case SSL_LIBRARY_VERSION_TLS_1_2:
     return "1.2";
+  case SSL_LIBRARY_VERSION_TLS_1_3:
+    return "1.3";
   default:
     std::cerr << "Invalid version: " << version << std::endl;
     EXPECT_TRUE(false);
     return "";
   }
 }
 
 TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
@@ -126,16 +131,18 @@ void TlsConnectTestBase::ExpectResumptio
 }
 
 void TlsConnectTestBase::EnsureTlsSetup() {
   EXPECT_TRUE(client_->EnsureTlsSetup());
   EXPECT_TRUE(server_->EnsureTlsSetup());
 }
 
 void TlsConnectTestBase::Handshake() {
+  EnsureTlsSetup();
+  client_->SetServerKeyBits(server_->server_key_bits());
   client_->Handshake();
   server_->Handshake();
 
   ASSERT_TRUE_WAIT((client_->state() != TlsAgent::STATE_CONNECTING) &&
                    (server_->state() != TlsAgent::STATE_CONNECTING),
                    5000);
 }
 
@@ -168,34 +175,45 @@ void TlsConnectTestBase::CheckConnected(
   ret = server_->cipher_suite(&cipher_suite2);
   EXPECT_TRUE(ret);
   EXPECT_EQ(cipher_suite1, cipher_suite2);
 
   std::cerr << "Connected with version " << client_->version()
             << " cipher suite " << client_->cipher_suite_name()
             << std::endl;
 
-  // Check and store session ids.
-  std::vector<uint8_t> sid_c1 = client_->session_id();
-  EXPECT_EQ(32U, sid_c1.size());
-  std::vector<uint8_t> sid_s1 = server_->session_id();
-  EXPECT_EQ(32U, sid_s1.size());
-  EXPECT_EQ(sid_c1, sid_s1);
-  session_ids_.push_back(sid_c1);
+  if (client_->version() < SSL_LIBRARY_VERSION_TLS_1_3) {
+    // Check and store session ids.
+    std::vector<uint8_t> sid_c1 = client_->session_id();
+    EXPECT_EQ(32U, sid_c1.size());
+    std::vector<uint8_t> sid_s1 = server_->session_id();
+    EXPECT_EQ(32U, sid_s1.size());
+    EXPECT_EQ(sid_c1, sid_s1);
+    session_ids_.push_back(sid_c1);
+  }
+
+  CheckExtendedMasterSecret();
 
   CheckResumption(expected_resumption_mode_);
-  // Check whether the extended master secret extension was negotiated.
-  CheckExtendedMasterSecret();
+}
+
+void TlsConnectTestBase::CheckKEAType(SSLKEAType type) const {
+  client_->CheckKEAType(type);
+  server_->CheckKEAType(type);
+}
+
+void TlsConnectTestBase::CheckAuthType(SSLAuthType type) const {
+  client_->CheckAuthType(type);
+  server_->CheckAuthType(type);
 }
 
 void TlsConnectTestBase::ConnectExpectFail() {
   server_->StartConnect();
   client_->StartConnect();
   Handshake();
-
   ASSERT_EQ(TlsAgent::STATE_ERROR, client_->state());
   ASSERT_EQ(TlsAgent::STATE_ERROR, server_->state());
 }
 
 void TlsConnectTestBase::SetExpectedVersion(uint16_t version) {
   client_->SetExpectedVersion(version);
   server_->SetExpectedVersion(version);
 }
@@ -231,17 +249,17 @@ void TlsConnectTestBase::CheckResumption
   EXPECT_EQ(resume_ct, stats->hch_sid_cache_hits);
   EXPECT_EQ(resume_ct, stats->hsh_sid_cache_hits);
 
   EXPECT_EQ(stateless_ct, stats->hch_sid_stateless_resumes);
   EXPECT_EQ(stateless_ct, stats->hsh_sid_stateless_resumes);
 
   if (resume_ct) {
     // Check that the last two session ids match.
-    EXPECT_GE(2U, session_ids_.size());
+    EXPECT_EQ(2U, session_ids_.size());
     EXPECT_EQ(session_ids_[session_ids_.size()-1],
               session_ids_[session_ids_.size()-2]);
   }
 }
 
 void TlsConnectTestBase::EnableAlpn() {
   // A simple value of "a", "b".  Note that the preferred value of "a" is placed
   // at the end, because the NSS API follows the now defunct NPN specification,
@@ -267,17 +285,17 @@ void TlsConnectTestBase::SendReceive() {
   server_->SendData(50);
   WAIT_(client_->received_bytes() == 50U &&
         server_->received_bytes() == 50U, 2000);
   ASSERT_EQ(50U, client_->received_bytes());
   ASSERT_EQ(50U, server_->received_bytes());
 }
 
 void TlsConnectTestBase::ExpectExtendedMasterSecret(bool expected) {
-    expect_extended_master_secret_ = expected;
+  expect_extended_master_secret_ = expected;
 }
 
 void TlsConnectTestBase::CheckExtendedMasterSecret() {
   client_->CheckExtendedMasterSecret(expect_extended_master_secret_);
   server_->CheckExtendedMasterSecret(expect_extended_master_secret_);
 }
 
 TlsConnectGeneric::TlsConnectGeneric()
--- a/external_tests/ssl_gtest/tls_connect.h
+++ b/external_tests/ssl_gtest/tls_connect.h
@@ -22,16 +22,17 @@ namespace nss_test {
 class TlsConnectTestBase : public ::testing::Test {
  public:
   static ::testing::internal::ParamGenerator<std::string> kTlsModesStream;
   static ::testing::internal::ParamGenerator<std::string> kTlsModesAll;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV10;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV11;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV11V12;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV12Plus;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV13;
 
   static inline Mode ToMode(const std::string& str) {
     return str == "TLS" ? STREAM : DGRAM;
   }
 
   TlsConnectTestBase(Mode mode, uint16_t version);
   virtual ~TlsConnectTestBase();
 
@@ -51,16 +52,18 @@ class TlsConnectTestBase : public ::test
   // Run the handshake.
   void Handshake();
   // Connect and check that it works.
   void Connect();
   // Check that the connection was successfully established.
   void CheckConnected();
   // Connect and expect it to fail.
   void ConnectExpectFail();
+  void CheckKEAType(SSLKEAType type) const;
+  void CheckAuthType(SSLAuthType type) const;
 
   void SetExpectedVersion(uint16_t version);
   // Expect resumption of a particular type.
   void ExpectResumption(SessionResumptionMode expected);
   void DisableDheAndEcdheCiphers();
   void DisableDheCiphers();
   void DisableEcdheCiphers();
   void EnableExtendedMasterSecret();
@@ -90,16 +93,20 @@ class TlsConnectTestBase : public ::test
 
 // A TLS-only test base.
 class TlsConnectStream : public TlsConnectTestBase,
                          public ::testing::WithParamInterface<uint16_t> {
  public:
   TlsConnectStream() : TlsConnectTestBase(STREAM, GetParam()) {}
 };
 
+// A TLS-only test base for tests before 1.3
+class TlsConnectStreamPre13 : public TlsConnectStream {
+};
+
 // A DTLS-only test base.
 class TlsConnectDatagram : public TlsConnectTestBase,
                            public ::testing::WithParamInterface<uint16_t> {
  public:
   TlsConnectDatagram() : TlsConnectTestBase(DGRAM, GetParam()) {}
 };
 
 // A generic test class that can be either STREAM or DGRAM and a single version
@@ -123,11 +130,15 @@ class TlsConnectPre12
 // A TLS 1.2 only generic test.
 class TlsConnectTls12
   : public TlsConnectTestBase,
     public ::testing::WithParamInterface<std::string> {
  public:
   TlsConnectTls12();
 };
 
+// A variant that is used only with Pre13.
+class TlsConnectGenericPre13 : public TlsConnectGeneric {
+};
+
 } // namespace nss_test
 
 #endif
new file mode 100644
--- /dev/null
+++ b/external_tests/ssl_gtest/tls_hkdf_unittest.cc
@@ -0,0 +1,185 @@
+/* -*- 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 "nss.h"
+#include "pk11pub.h"
+#include "tls13hkdf.h"
+#include <memory>
+
+#include "databuffer.h"
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+
+namespace nss_test {
+
+const uint8_t kKey1Data[] = {
+  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+  0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+  0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+  0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+  0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+  0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+};
+const DataBuffer kKey1(kKey1Data,
+                       sizeof(kKey1Data));
+
+// The same as key1 but with the first byte
+// 0x01.
+const uint8_t kKey2Data[] = {
+  0x01,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+  0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+  0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+  0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+  0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+  0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+};
+const DataBuffer kKey2(kKey2Data,
+                       sizeof(kKey2Data));
+
+const char kLabelMasterSecret[] = "master secret";
+
+const uint8_t kSessionHash[] = {
+  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
+  0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
+  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
+  0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+  0xd0,0xd1,0xd2,0xd3
+};
+
+static void ImportKey(ScopedPK11SymKey* to, const DataBuffer& key,
+                      PK11SlotInfo* slot) {
+  SECItem key_item = {
+    siBuffer,
+    const_cast<uint8_t*>(key.data()),
+    static_cast<unsigned int>(key.len())
+  };
+
+  PK11SymKey* inner =
+      PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, PK11_OriginUnwrap,
+                        CKA_DERIVE, &key_item, NULL);
+  ASSERT_NE(nullptr, inner);
+  to->reset(inner);
+}
+
+
+static void DumpData(const std::string& label, const uint8_t* buf, size_t len) {
+  DataBuffer d(buf, len);
+
+  std::cerr << label << ": " << d << std::endl;
+}
+
+void DumpKey(const std::string& label, ScopedPK11SymKey& key) {
+  SECStatus rv = PK11_ExtractKeyValue(key.get());
+  ASSERT_EQ(SECSuccess, rv);
+
+  SECItem *key_data = PK11_GetKeyData(key.get());
+  ASSERT_NE(nullptr, key_data);
+
+  DumpData(label, key_data->data, key_data->len);
+}
+
+class TlsHkdfTest : public ::testing::Test {
+ public:
+  TlsHkdfTest() : k1_(), k2_(), slot_(PK11_GetInternalSlot()) {
+    EXPECT_NE(nullptr, slot_);
+  }
+
+  void SetUp() {
+    ImportKey(&k1_, kKey1, slot_.get());
+    ImportKey(&k2_, kKey2, slot_.get());
+  }
+
+  void VerifyKey(const ScopedPK11SymKey& key, const DataBuffer& expected) {
+    SECStatus rv = PK11_ExtractKeyValue(key.get());
+    ASSERT_EQ(SECSuccess, rv);
+
+    SECItem *key_data = PK11_GetKeyData(key.get());
+    ASSERT_NE(nullptr, key_data);
+
+    EXPECT_EQ(expected.len(), key_data->len);
+    EXPECT_EQ(0, memcmp(expected.data(),
+                        key_data->data, expected.len()));
+  }
+
+  void HkdfExtract(const ScopedPK11SymKey& ikmk1, const ScopedPK11SymKey& ikmk2,
+                   SSLHashType base_hash,
+                   const DataBuffer& expected) {
+    PK11SymKey* prk = nullptr;
+    SECStatus rv = tls13_HkdfExtract(
+        ikmk1.get(), ikmk2.get(), base_hash, &prk);
+    ASSERT_EQ(SECSuccess, rv);
+    ScopedPK11SymKey prkk(prk);
+
+    DumpKey("Output", prkk);
+    VerifyKey(prkk, expected);
+  }
+
+  void HkdfExpandLabel(ScopedPK11SymKey* prk, SSLHashType base_hash,
+                       const uint8_t *session_hash, size_t session_hash_len,
+                       const char *label, size_t label_len,
+                       const DataBuffer& expected) {
+    uint8_t output[expected.len()];
+
+    SECStatus rv = tls13_HkdfExpandLabelRaw(prk->get(), base_hash,
+                                            session_hash, session_hash_len,
+                                            label, label_len,
+                                            output, sizeof(output));
+    ASSERT_EQ(SECSuccess, rv);
+    DumpData("Output", output, sizeof(output));
+    EXPECT_EQ(0, memcmp(expected.data(), output,
+                        expected.len()));
+  }
+
+ protected:
+  ScopedPK11SymKey k1_;
+  ScopedPK11SymKey k2_;
+
+ private:
+  ScopedPK11SlotInfo slot_;
+};
+
+TEST_F(TlsHkdfTest, HkdfSha256Key2Only) {
+  const uint8_t expected[] = {
+    0x2f, 0x5f, 0x78, 0xd0, 0xa4, 0xc4, 0x36, 0xee,
+    0x6c, 0x8a, 0x4e, 0xf9, 0xd0, 0x43, 0x81, 0x02,
+    0x13, 0xfd, 0x47, 0x83, 0x63, 0x3a, 0xd2, 0xe1,
+    0x40, 0x6d, 0x2d, 0x98, 0x00, 0xfd, 0xc1, 0x87
+  };
+  const DataBuffer expected_data(expected, sizeof(expected));
+
+  HkdfExtract(nullptr, k2_, ssl_hash_sha256,
+              expected_data);
+}
+
+TEST_F(TlsHkdfTest, HkdfSha256Key1Key2) {
+  const uint8_t expected[] = {
+    0x79, 0x53, 0xb8, 0xdd, 0x6b, 0x98, 0xce, 0x00,
+    0xb7, 0xdc, 0xe8, 0x03, 0x70, 0x8c, 0xe3, 0xac,
+    0x06, 0x8b, 0x22, 0xfd, 0x0e, 0x34, 0x48, 0xe6,
+    0xe5, 0xe0, 0x8a, 0xd6, 0x16, 0x18, 0xe5, 0x48
+  };
+  const DataBuffer expected_data(expected, sizeof(expected));
+
+  HkdfExtract(k1_, k2_, ssl_hash_sha256,
+              expected_data);
+}
+
+TEST_F(TlsHkdfTest, HkdfExpandLabelSha256) {
+  const uint8_t expected[] = {
+    0x34, 0x7c, 0x67, 0x80, 0xff, 0x0b, 0xba, 0xd7,
+    0x1c, 0x28, 0x3b, 0x16, 0xeb, 0x2f, 0x9c, 0xf6,
+    0x2d, 0x24, 0xe6, 0xcd, 0xb6, 0x13, 0xd5, 0x17,
+    0x76, 0x54, 0x8c, 0xb0, 0x7d, 0xcd, 0xe7, 0x4c
+  };
+  const DataBuffer expected_data(expected, sizeof(expected));
+
+  HkdfExpandLabel(&k1_, ssl_hash_sha256,
+                  kSessionHash, 32,
+                  kLabelMasterSecret, strlen(kLabelMasterSecret),
+                  expected_data);
+}
+
+} // namespace nss_test
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -435,8 +435,33 @@ ER3(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALG
 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")
+
+ER3(SSL_ERROR_RX_MALFORMED_KEY_SHARE, (SSL_ERROR_BASE + 138),
+"SSL received a malformed Key Share extension.")
+
+ER3(SSL_ERROR_MISSING_KEY_SHARE, (SSL_ERROR_BASE + 139),
+"SSL expected a Key Share extension.")
+
+ER3(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE, (SSL_ERROR_BASE + 140),
+"SSL received a malformed ECDHE key share handshake extension.")
+
+ER3(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE, (SSL_ERROR_BASE + 141),
+"SSL received a malformed DHE key share handshake extension.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS, (SSL_ERROR_BASE + 142),
+"SSL received a malformed Encrypted Extensions handshake message.")
+
+ER3(SSL_ERROR_MISSING_EXTENSION_ALERT, (SSL_ERROR_BASE + 143),
+"SSL received a missing_extenson alert.")
+
+ER3(SSL_ERROR_KEY_EXCHANGE_FAILURE, (SSL_ERROR_BASE + 144),
+"SSL had an error performing key exchange.")
+
+ER3(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 145),
+"SSL received an extension that is not permitted for this version.")
+
--- a/lib/ssl/config.mk
+++ b/lib/ssl/config.mk
@@ -2,21 +2,16 @@
 # 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/.
 
 ifdef NISCC_TEST
 DEFINES += -DNISCC_TEST
 endif
 
-# Allow build-time configuration of TLS 1.3 (Experimental)
-ifdef NSS_ENABLE_TLS_1_3
-DEFINES += -DNSS_ENABLE_TLS_1_3
-endif
-
 ifdef NSS_NO_PKCS11_BYPASS
 DEFINES += -DNO_PKCS11_BYPASS
 else
 CRYPTOLIB=$(SOFTOKEN_LIB_DIR)/$(LIB_PREFIX)freebl.$(LIB_SUFFIX)
 
 EXTRA_LIBS += \
 	$(CRYPTOLIB) \
 	$(NULL)
--- a/lib/ssl/dtlscon.c
+++ b/lib/ssl/dtlscon.c
@@ -809,19 +809,23 @@ dtls_CompressMACEncryptRecord(sslSocket 
             cwSpec = ss->ssl3.pwSpec;
         else
             cwSpec = NULL;
     } else {
         cwSpec = ss->ssl3.cwSpec;
     }
 
     if (cwSpec) {
-        rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
-                                           PR_FALSE, type, pIn, contentLen,
-                                           wrBuf);
+        if (ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+            rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
+                                               PR_FALSE, type, pIn, contentLen,
+                                               wrBuf);
+        } else {
+            rv = tls13_ProtectRecord(ss, type, pIn, contentLen, wrBuf);
+        }
     } else {
         PR_NOT_REACHED("Couldn't find a cipher spec matching epoch");
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     }
     ssl_ReleaseSpecReadLock(ss); /************************************/
 
     return rv;
 }
@@ -1042,20 +1046,20 @@ dtls_InitRecvdRecords(DTLSRecvdRecords *
 }
 
 /*
  * Has this DTLS record been received? Return values are:
  * -1 -- out of range to the left
  *  0 -- not received yet
  *  1 -- replay
  *
- *  Called from: dtls_HandleRecord()
+ *  Called from: ssl3_HandleRecord()
  */
 int
-dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
+dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq)
 {
     PRUint64 offset;
 
     /* Out of range to the left */
     if (seq < records->left) {
         return -1;
     }
 
@@ -1139,8 +1143,46 @@ DTLS_GetHandshakeTimeout(PRFileDesc *soc
         /* Timer expired */
         *timeout = PR_INTERVAL_NO_WAIT;
     } else {
         *timeout = desired - elapsed;
     }
 
     return SECSuccess;
 }
+
+/*
+ * DTLS relevance checks:
+ * Note that this code currently ignores all out-of-epoch packets,
+ * which means we lose some in the case of rehandshake +
+ * loss/reordering. Since DTLS is explicitly unreliable, this
+ * seems like a good tradeoff for implementation effort and is
+ * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1.
+ *
+ * If the packet is not relevant, this function returns PR_FALSE.
+ * If the packet is relevant, this function returns PR_TRUE
+ * and sets |*seqNum| to the packet sequence number.
+ */
+PRBool
+dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec,
+                const SSL3Ciphertext *cText, PRUint64 *seqNum)
+{
+    DTLSEpoch epoch = cText->seq_num.high >> 16;
+    PRUint64 dtls_seq_num;
+
+    if (crSpec->epoch != epoch) {
+        SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, received packet "
+                 "from irrelevant epoch %d", SSL_GETPID(), ss->fd, epoch));
+        return PR_FALSE;
+    }
+
+    dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) |
+                   ((PRUint64)cText->seq_num.low);
+
+    if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) {
+        SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, rejecting "
+                 "potentially replayed packet", SSL_GETPID(), ss->fd));
+        return PR_FALSE;
+    }
+
+    *seqNum = dtls_seq_num;
+    return PR_TRUE;
+}
--- a/lib/ssl/manifest.mn
+++ b/lib/ssl/manifest.mn
@@ -39,15 +39,17 @@ CSRCS = \
 	sslsnce.c \
 	sslsock.c \
 	ssltrace.c \
 	sslver.c \
 	authcert.c \
 	cmpcert.c \
 	sslinfo.c \
 	ssl3ecc.c \
+        tls13con.c \
+        tls13hkdf.c \
 	$(NULL)
 
 LIBRARY_NAME = ssl
 LIBRARY_VERSION = 3
 
 # This part of the code, including all sub-dirs, can be optimized for size
 export ALLOW_OPT_CODE_SIZE = 1
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -46,32 +46,29 @@
 static SECStatus ssl3_AuthCertificate(sslSocket *ss);
 static void      ssl3_CleanupPeerCerts(sslSocket *ss);
 static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
                                        PK11SlotInfo * serverKeySlot);
 static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
 static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss);
 static SECStatus ssl3_HandshakeFailure(      sslSocket *ss);
 static SECStatus ssl3_InitState(             sslSocket *ss);
-static SECStatus ssl3_SendCertificate(       sslSocket *ss);
-static SECStatus ssl3_SendCertificateStatus( sslSocket *ss);
-static SECStatus ssl3_SendEmptyCertificate(  sslSocket *ss);
+
 static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
 static SECStatus ssl3_SendNextProto(         sslSocket *ss);
 static SECStatus ssl3_SendFinished(          sslSocket *ss, PRInt32 flags);
-static SECStatus ssl3_SendServerHello(       sslSocket *ss);
 static SECStatus ssl3_SendServerHelloDone(   sslSocket *ss);
 static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
 static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
                                              const unsigned char *b,
                                              unsigned int l);
-static SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
-                                             ssl3CipherSpec *spec,
-                                             SSL3Hashes *hashes,
-                                             PRUint32 sender);
+static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss,
+                                                      SSL3Opaque *b,
+                                                      PRUint32 length,
+                                                      SSL3Hashes *hashesPtr);
 static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
 
 static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
 			     int maxOutputLen, const unsigned char *input,
 			     int inputLen);
 #ifndef NO_PKCS11_BYPASS
 static SECStatus ssl3_AESGCMBypass(ssl3KeyMaterial *keys, PRBool doDecrypt,
 				   unsigned char *out, int *outlen, int maxout,
@@ -549,29 +546,36 @@ typedef struct ECCWrappedKeyInfoStr {
     PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */
     PRUint16 pubValueLen;     /* length (in bytes) of EC public value */
     PRUint16 wrappedKeyLen;   /* length (in bytes) of the wrapped key */
     PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */
     /* EC public-key params, the EC public value and the wrapped key  */
 } ECCWrappedKeyInfo;
 #endif /* NSS_DISABLE_ECC */
 
+CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg)
+{
+    PORT_Assert(alg2Mech[calg].calg == calg);
+    return alg2Mech[calg].cmech;
+}
+
 #if defined(TRACE)
 
 static char *
 ssl3_DecodeHandshakeType(int msgType)
 {
     char * rv;
     static char line[40];
 
     switch(msgType) {
     case hello_request:	        rv = "hello_request (0)";               break;
     case client_hello:	        rv = "client_hello  (1)";               break;
     case server_hello:	        rv = "server_hello  (2)";               break;
     case hello_verify_request:  rv = "hello_verify_request (3)";        break;
+    case encrypted_extensions:  rv = "encrypted_extensions (8)";        break;
     case certificate:	        rv = "certificate  (11)";               break;
     case server_key_exchange:	rv = "server_key_exchange (12)";        break;
     case certificate_request:	rv = "certificate_request (13)";        break;
     case server_hello_done:	rv = "server_hello_done   (14)";        break;
     case certificate_verify:	rv = "certificate_verify  (15)";        break;
     case client_key_exchange:	rv = "client_key_exchange (16)";        break;
     case finished:	        rv = "finished     (20)";               break;
     default:
@@ -657,22 +661,22 @@ ssl3_CipherSuiteAllowedForVersionRange(
     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
     case TLS_RSA_WITH_AES_128_CBC_SHA256:
     case TLS_RSA_WITH_AES_128_GCM_SHA256:
     case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
     case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
     case TLS_RSA_WITH_NULL_SHA256:
+    case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
         return vrange->max == SSL_LIBRARY_VERSION_TLS_1_2;
 
     case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
     case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
     case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
-    case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
 	return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2;
 
     /* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and
      * point formats.*/
     case TLS_ECDH_ECDSA_WITH_NULL_SHA:
     case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
     case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
     case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
@@ -772,18 +776,17 @@ ssl3_config_match_init(sslSocket *ss)
 	     * this cipher.  It isn't part of the static definition.
 	     */
 	    cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
 	    if (!cipher_def) {
 	    	suite->isPresent = PR_FALSE;
 		continue;
 	    }
 	    cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg;
-	    PORT_Assert(  alg2Mech[cipher_alg].calg == cipher_alg);
-	    cipher_mech = alg2Mech[cipher_alg].cmech;
+	    cipher_mech = ssl3_Alg2Mech(cipher_alg);
 	    exchKeyType =
 	    	    kea_defs[cipher_def->key_exchange_alg].exchKeyType;
 #ifdef NSS_DISABLE_ECC
 	    svrAuth = ss->serverCerts + exchKeyType;
 #else
 	    /* XXX SSLKEAType isn't really a good choice for 
 	     * indexing certificates. It doesn't work for
 	     * (EC)DHE-* ciphers. Here we use a hack to ensure
@@ -1335,17 +1338,17 @@ ssl3_ComputeDHKeyHash(SSLHashType hashAl
 		  hashes->u.raw, hashes->len));
     }
 
     if (hashBuf != buf && hashBuf != NULL)
     	PORT_Free(hashBuf);
     return rv;
 }
 
-static void
+void
 ssl3_BumpSequenceNumber(SSL3SequenceNumber *num)
 {
     num->low++;
     if (num->low == 0)
 	num->high++;
 }
 
 /* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */
@@ -1408,17 +1411,17 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *s
 }
 
 /* Fill in the pending cipher spec with info from the selected ciphersuite.
 ** This is as much initialization as we can do without having key material.
 ** Called from ssl3_HandleServerHello(), ssl3_SendServerHello()
 ** Caller must hold the ssl3 handshake lock.
 ** Acquires & releases SpecWriteLock.
 */
-static SECStatus
+SECStatus
 ssl3_SetupPendingCipherSpec(sslSocket *ss)
 {
     ssl3CipherSpec *          pwSpec;
     ssl3CipherSpec *          cwSpec;
     ssl3CipherSuite           suite     = ss->ssl3.hs.cipher_suite;
     SSL3MACAlgorithm          mac;
     SSL3BulkCipher            cipher;
     SSL3KeyExchangeAlgorithm  kea;
@@ -1482,16 +1485,20 @@ ssl3_SetupPendingCipherSpec(sslSocket *s
     pwSpec->decodeContext = NULL;
 
     pwSpec->mac_size = pwSpec->mac_def->mac_size;
 
     pwSpec->compression_method = ss->ssl3.hs.compression;
     pwSpec->compressContext = NULL;
     pwSpec->decompressContext = NULL;
 
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        PORT_Assert(ss->ssl3.hs.kea_def->ephemeral);
+        PORT_Assert(pwSpec->cipher_def->type == type_aead);
+    }
     ssl_ReleaseSpecWriteLock(ss);  /*******************************/
     return SECSuccess;
 }
 
 #ifdef NSS_ENABLE_SSL_ZLIB
 #define SSL3_DEFLATE_CONTEXT_SIZE sizeof(z_stream)
 
 static SECStatus
@@ -2092,17 +2099,17 @@ ssl3_InitPendingContextsPKCS11(sslSocket
     */
 
     if (calg == calg_null) {
 	pwSpec->encode  = Null_Cipher;
 	pwSpec->decode  = Null_Cipher;
 	pwSpec->destroy = NULL;
 	return SECSuccess;
     }
-    mechanism = alg2Mech[calg].cmech;
+    mechanism = ssl3_Alg2Mech(calg);
     effKeyBits = cipher_def->key_size * BPB;
 
     /*
      * build the server context
      */
     iv.data = pwSpec->server.write_iv;
     iv.len  = cipher_def->iv_size;
     param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits);
@@ -2880,17 +2887,16 @@ 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 = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
 					       ss->sec.isServer, IS_DTLS(ss),
 					       capRecordVersion, type, pIn,
 					       1, wrBuf);
 	    if (rv != SECSuccess)
 	        goto spec_locked_loser;
 
 	    PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
@@ -2907,23 +2913,30 @@ ssl3_SendRecord(   sslSocket *        ss
 	                                       &secondRecord);
 	    if (rv == SECSuccess) {
 	        PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
 	                       secondRecord.buf, secondRecord.len));
 	        wrBuf->len += secondRecord.len;
 	    }
 	} else {
 	    if (!IS_DTLS(ss)) {
-		rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
-						   ss->sec.isServer,
-						   IS_DTLS(ss),
-						   capRecordVersion,
-						   type, pIn,
-						   contentLen, wrBuf);
-	    } else {
+                if (ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+                    rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+                                                       ss->sec.isServer,
+                                                       PR_FALSE,
+                                                       capRecordVersion,
+                                                       type, pIn,
+                                                       contentLen, wrBuf);
+                } else {
+                    rv = tls13_ProtectRecord(ss, type, pIn,
+                                             contentLen, wrBuf);
+                }
+            } else {
+                /* TLS <= 1.2 and TLS 1.3 cases are both handled in
+                 * dtls_CompressMACEncryptRecord. */
 		rv = dtls_CompressMACEncryptRecord(ss, epoch,
 						   !!(flags & ssl_SEND_FLAG_USE_EPOCH),
 						   type, pIn,
 						   contentLen, wrBuf);
 	    }
 
 	    if (rv == SECSuccess) {
 	        PRINT_BUF(50, (ss, "send (encrypted) record data:",
@@ -3103,17 +3116,17 @@ ssl3_SendApplicationData(sslSocket *ss, 
  * - ssl3_FlushHandshakeMessages if non-DTLS
  * - dtls_FlushHandshakeMessages if DTLS
  *
  * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(),
  *             ssl3_AppendHandshake(), ssl3_SendClientHello(),
  *             ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(),
  *             ssl3_SendFinished(),
  */
-static SECStatus
+SECStatus
 ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
 {
     if (IS_DTLS(ss)) {
         return dtls_FlushHandshakeMessages(ss, flags);
     } else {
         return ssl3_FlushHandshakeMessages(ss, flags);
     }
 }
@@ -3233,16 +3246,17 @@ ssl3_HandleNoCertificate(sslSocket *ss)
 **              ssl3_HandleServerHelloDone <-
 **              ssl3_HandleClientHello	<-
 **              ssl3_HandleV2ClientHello <-
 **              ssl3_HandleCertificateVerify <-
 **              ssl3_HandleClientKeyExchange <-
 **              ssl3_HandleCertificate	<-
 **              ssl3_HandleFinished	<-
 **              ssl3_HandleHandshakeMessage <-
+**              ssl3_HandlePostHelloHandshakeMessage <-
 **              ssl3_HandleRecord	<-
 **
 */
 SECStatus
 SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
 {
     PRUint8 	bytes[2];
     SECStatus	rv;
@@ -3410,16 +3424,18 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
     case protocol_version: 	error = SSL_ERROR_PROTOCOL_VERSION_ALERT; break;
     case insufficient_security: error = SSL_ERROR_INSUFFICIENT_SECURITY_ALERT; 
     									  break;
     case internal_error: 	error = SSL_ERROR_INTERNAL_ERROR_ALERT;   break;
     case user_canceled: 	error = SSL_ERROR_USER_CANCELED_ALERT;    break;
     case no_renegotiation: 	error = SSL_ERROR_NO_RENEGOTIATION_ALERT; break;
 
     /* Alerts for TLS client hello extensions */
+    case missing_extension:
+                        error = SSL_ERROR_MISSING_EXTENSION_ALERT;        break;
     case unsupported_extension: 
 			error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT;    break;
     case certificate_unobtainable: 
 			error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT; break;
     case unrecognized_name: 
 			error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;        break;
     case bad_certificate_status_response: 
 			error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; break;
@@ -3944,18 +3960,17 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
 	keySize                             = 0;
         key_material_params.ulKeySizeInBits = 0;
         key_material_params.ulIVSizeInBits  = 0;
     	returnedKeys.pIVClient              = NULL;
     	returnedKeys.pIVServer              = NULL;
     }
 
     calg = cipher_def->calg;
-    PORT_Assert(     alg2Mech[calg].calg == calg);
-    bulk_mechanism = alg2Mech[calg].cmech;
+    bulk_mechanism = ssl3_Alg2Mech(calg);
 
     if (isTLS12) {
 	key_derive    = CKM_TLS12_KEY_AND_MAC_DERIVE;
 	key_material_params.prfHashMechanism = CKM_SHA256;
 	key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS);
     } else if (isTLS) {
 	key_derive    = CKM_TLS_KEY_AND_MAC_DERIVE;
 	key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
@@ -4571,16 +4586,26 @@ SECStatus
 ssl3_CheckSignatureAndHashAlgorithmConsistency(
     sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash,
     CERTCertificate* cert)
 {
     SECStatus rv;
     SSLSignType sigAlg;
     unsigned int i;
 
+    /* If we're a client, check that the signature algorithm matches the signing
+     * key type of the cipher suite. */
+    if (!ss->sec.isServer &&
+        ss->ssl3.hs.kea_def->signKeyType != sigAndHash->sigAlg) {
+        PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+        return SECFailure;
+    }
+
+    /* Verify that the signature algorithm used for the
+     * signature matches the signing key. */
     rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg);
     if (rv != SECSuccess) {
         return rv;
     }
     if (sigAlg != sigAndHash->sigAlg) {
         PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
@@ -4671,17 +4696,17 @@ ssl3_ConsumeSignatureAndHashAlgorithm(ss
  * Called from ssl3_SendCertificateVerify
  *             ssl3_SendFinished
  *             ssl3_HandleHandshakeMessage
  *
  * Caller must hold the SSL3HandshakeLock.
  * Caller must hold a read or write lock on the Spec R/W lock.
  *	(There is presently no way to assert on a Read lock.)
  */
-static SECStatus
+SECStatus
 ssl3_ComputeHandshakeHashes(sslSocket *     ss,
                             ssl3CipherSpec *spec,   /* uses ->master_secret */
 			    SSL3Hashes *    hashes, /* output goes here. */
 			    PRUint32        sender)
 {
     SECStatus     rv        = SECSuccess;
     PRBool        isTLS     = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
     unsigned int  outLength;
@@ -5244,16 +5269,22 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
 	}
 
 	sid = ssl3_NewSessionID(ss, PR_FALSE);
 	if (!sid) {
 	    return SECFailure;	/* memory error is set */
         }
     }
 
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = tls13_SetupClientHello(ss);
+        if (rv != SECSuccess)
+            return rv;
+    }
+
     isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
     ssl_GetSpecWriteLock(ss);
     cwSpec = ss->ssl3.cwSpec;
     if (cwSpec->mac_def->mac == mac_null) {
 	/* SSL records are not being MACed. */
 	cwSpec->version = ss->version;
     }
     ssl_ReleaseSpecWriteLock(ss);
@@ -5548,31 +5579,32 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
 	return rv;	/* error code set by ssl3_FlushHandshake */
     }
 
     ss->ssl3.hs.ws = wait_server_hello;
     return rv;
 }
 
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Hello Request.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
+ * complete ssl3 Hello Request.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleHelloRequest(sslSocket *ss)
 {
     sslSessionID *sid = ss->sec.ci.sid;
     SECStatus     rv;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle hello_request handshake",
 		SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     if (ss->ssl3.hs.ws == wait_server_hello)
 	return SECSuccess;
     if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) {
 	(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
 	return SECFailure;
     }
@@ -6314,68 +6346,101 @@ ssl3_SendClientKeyExchange(sslSocket *ss
 
 loser:
     if (serverKey) 
     	SECKEY_DestroyPublicKey(serverKey);
     return rv;	/* err code already set. */
 }
 
 /* Called from ssl3_HandleServerHelloDone(). */
-static SECStatus
-ssl3_SendCertificateVerify(sslSocket *ss)
+SECStatus
+ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
 {
     SECStatus     rv		= SECFailure;
     PRBool        isTLS;
     PRBool        isTLS12;
+    PRBool        isTLS13;
     SECItem       buf           = {siBuffer, NULL, 0};
     SSL3Hashes    hashes;
     KeyType       keyType;
     unsigned int  len;
     SSLSignatureAndHashAlg sigAndHash;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
 		SSL_GETPID(), ss->fd));
 
+    isTLS13 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
     ssl_GetSpecReadLock(ss);
     if (ss->ssl3.hs.hashType == handshake_hash_single &&
 	ss->ssl3.hs.backupHash) {
-	rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
-	PORT_Assert(!ss->ssl3.hs.backupHash);
+        PORT_Assert(!ss->ssl3.hs.backupHash);
+        PORT_Assert(!isTLS13);
+        /* TODO(ekr@rtfm.com): The backup hash here contains a SHA-1 hash
+         * but in TLS 1.3, we always sign H(Context, Hash(handshake))
+         * where:
+         *
+         * H is the negotiated signature hash and
+         * Hash is the cipher-suite specific handshake hash
+         * Generally this means that Hash is SHA-256.
+         *
+         * We need code to negotiate H but the current code is a mess.
+         */
+        if (isTLS13) {
+            /* rv is already set to SECFailure */
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        } else {
+            rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
+        }
     } else {
-	rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
+        ssl3CipherSpec *spec;
+
+        if (isTLS13) {
+            /* In TLS 1.3, we are already encrypted. */
+            spec = ss->ssl3.cwSpec;
+        } else {
+            spec = ss->ssl3.pwSpec;
+        }
+
+        rv = ssl3_ComputeHandshakeHashes(ss, spec, &hashes, 0);
     }
     ssl_ReleaseSpecReadLock(ss);
     if (rv != SECSuccess) {
 	goto done;	/* err code was set by ssl3_ComputeHandshakeHashes */
     }
 
+    if (isTLS13) {
+        rv = tls13_AddContextToHashes(ss, &hashes, tls13_GetHash(ss), PR_TRUE);
+        if (rv != SECSuccess) {
+            goto done;	/* err code was set by tls13_AddContextToHashes */
+        }
+    }
+
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
-    keyType = ss->ssl3.clientPrivateKey->keyType;
-    rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
-    if (rv == SECSuccess) {
-	PK11SlotInfo * slot;
-	sslSessionID * sid   = ss->sec.ci.sid;
-
-    	/* Remember the info about the slot that did the signing.
+
+    keyType = privKey->keyType;
+    rv = ssl3_SignHashes(&hashes, privKey, &buf, isTLS);
+    if (rv == SECSuccess && !ss->sec.isServer) {
+        /* Remember the info about the slot that did the signing.
 	** Later, when doing an SSL restart handshake, verify this.
 	** These calls are mere accessors, and can't fail.
 	*/
-	slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey);
-	sid->u.ssl3.clAuthSeries     = PK11_GetSlotSeries(slot);
-	sid->u.ssl3.clAuthSlotID     = PK11_GetSlotID(slot);
-	sid->u.ssl3.clAuthModuleID   = PK11_GetModuleID(slot);
-	sid->u.ssl3.clAuthValid      = PR_TRUE;
-	PK11_FreeSlot(slot);
-    }
-    SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
-    ss->ssl3.clientPrivateKey = NULL;
+        PK11SlotInfo *slot;
+        sslSessionID *sid = ss->sec.ci.sid;
+
+        slot = PK11_GetSlotFromPrivateKey(privKey);
+        sid->u.ssl3.clAuthSeries     = PK11_GetSlotSeries(slot);
+        sid->u.ssl3.clAuthSlotID     = PK11_GetSlotID(slot);
+        sid->u.ssl3.clAuthModuleID   = PK11_GetModuleID(slot);
+        sid->u.ssl3.clAuthValid      = PR_TRUE;
+        PK11_FreeSlot(slot);
+    }
     if (rv != SECSuccess) {
 	goto done;	/* err code was set by ssl3_SignHashes */
     }
 
     len = buf.len + 2 + (isTLS12 ? 2 : 0);
 
     rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
     if (rv != SECSuccess) {
@@ -6488,27 +6553,29 @@ ssl3_HandleServerHello(sslSocket *ss, SS
 	desc = internal_error;
 	errCode = PORT_GetError();
 	goto alert_loser;
     }
 
     rv = ssl3_ConsumeHandshake(
 	ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
     if (rv != SECSuccess) {
-    	goto loser; 	/* alert has been sent */
-    }
-
-    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. */
+    	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 (isTLS)
+                desc = decode_error;
+            goto alert_loser;	/* malformed. */
+        }
     }
 
     /* find selected cipher suite in our list. */
     temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
     if (temp < 0) {
     	goto loser; 	/* alert has been sent */
     }
     ssl3_config_match_init(ss);
@@ -6542,39 +6609,44 @@ ssl3_HandleServerHello(sslSocket *ss, SS
     ss->ssl3.hs.suite_def    = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp);
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
     PORT_Assert(ss->ssl3.hs.suite_def);
     if (!ss->ssl3.hs.suite_def) {
 	errCode = SEC_ERROR_LIBRARY_FAILURE;
 	PORT_SetError(errCode);
 	goto loser;	/* we don't send alerts for our screw-ups. */
     }
+
     ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
-    
-    /* find selected compression method in our list. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
-    if (temp < 0) {
-    	goto loser; 	/* alert has been sent */
-    }
-    suite_found = PR_FALSE;
-    for (i = 0; i < compressionMethodsCount; i++) {
-	if (temp == compressions[i]) {
-	    if (!compressionEnabled(ss, compressions[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;
+
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        /* find selected compression method in our list. */
+        temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
+        if (temp < 0) {
+            goto loser; 	/* alert has been sent */
+        }
+        suite_found = PR_FALSE;
+        for (i = 0; i < compressionMethodsCount; i++) {
+            if (temp == compressions[i]) {
+                if (!compressionEnabled(ss, compressions[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
@@ -6583,17 +6655,17 @@ ssl3_HandleServerHello(sslSocket *ss, SS
     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_HandleHelloExtensions(ss, &extensions.data,
-					    &extensions.len);
+                                            &extensions.len, server_hello);
 	    if (rv != SECSuccess)
 		goto alert_loser;
 	}
     }
     if ((ss->opt.requireSafeNegotiation || 
          (ss->firstHsDone && (ss->peerRequestedProtection ||
 	 ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN))) &&
 	!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
@@ -6795,17 +6867,22 @@ ssl3_HandleServerHello(sslSocket *ss, SS
         if (rv != SECSuccess)
             goto loser;
         /* Clean up the temporary pointer to the handshake buffer. */
         ss->xtnData.signedCertTimestamps.data = NULL;
         ss->xtnData.signedCertTimestamps.len = 0;
     }
 
     ss->ssl3.hs.isResuming = PR_FALSE;
-    if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_null) {
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = tls13_HandleServerKeyShare(ss);
+        if (rv != SECSuccess)
+            goto alert_loser;
+        TLS13_SET_HS_STATE(ss, wait_encrypted_extensions);
+    } else if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_null) {
         /* All current cipher suites other than those with ssl_sign_null (i.e.,
          * (EC)DH_anon_* suites) require a certificate, so use that signal. */
         ss->ssl3.hs.ws = wait_server_cert;
     } else {
         /* All the remaining cipher suites must be (EC)DH_anon_* and so
          * must be ephemeral. Note, if we ever add PSK this might
          * change. */
         PORT_Assert(ss->ssl3.hs.kea_def->ephemeral);
@@ -6820,18 +6897,18 @@ loser:
     /* Clean up the temporary pointer to the handshake buffer. */
     ss->xtnData.signedCertTimestamps.data = NULL;
     ss->xtnData.signedCertTimestamps.len = 0;
     ssl_MapLowLevelError(errCode);
     return SECFailure;
 }
 
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 ServerKeyExchange message.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
+ * complete ssl3 ServerKeyExchange message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     PLArenaPool *    arena     = NULL;
     SECKEYPublicKey *peerKey   = NULL;
     PRBool           isTLS, isTLS12;
@@ -7197,31 +7274,107 @@ done:
     }
 }
 
 typedef struct dnameNode {
     struct dnameNode *next;
     SECItem           name;
 } dnameNode;
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Certificate Request message.
+/*
+ * Parse the ca_list structure in a CertificateRequest.
+ *
+ * Called from:
+ * ssl3_HandleCertificateRequest
+ * tls13_HandleCertificateRequest
+ */
+SECStatus
+ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length,
+                                PLArenaPool *arena, CERTDistNames *ca_list)
+{
+    PRInt32 remaining;
+    int nnames = 0;
+    dnameNode *node;
+    int i;
+
+    remaining = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
+    if (remaining < 0)
+        return SECFailure;      /* malformed, alert has been sent */
+
+    if ((PRUint32)remaining > *length)
+        goto alert_loser;
+
+    ca_list->head = node = PORT_ArenaZNew(arena, dnameNode);
+    if (node == NULL)
+        goto no_mem;
+
+    while (remaining > 0) {
+        PRInt32 len;
+
+        if (remaining < 2)
+            goto alert_loser; /* malformed */
+
+        node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
+        if (len <= 0)
+            return SECFailure;      /* malformed, alert has been sent */
+
+        remaining -= 2;
+        if (remaining < len)
+            goto alert_loser; /* malformed */
+
+        node->name.data = *b;
+        *b += len;
+        *length -= len;
+        remaining -= len;
+        nnames++;
+        if (remaining <= 0)
+            break;  /* success */
+
+        node->next = PORT_ArenaZNew(arena, dnameNode);
+        node = node->next;
+        if (node == NULL)
+            goto no_mem;
+    }
+
+    ca_list->nnames = nnames;
+    ca_list->names  = PORT_ArenaNewArray(arena, SECItem, nnames);
+    if (nnames > 0 && ca_list->names == NULL)
+        goto no_mem;
+
+    for(i = 0, node = (dnameNode*)ca_list->head;
+        i < nnames;
+        i++, node = node->next) {
+        ca_list->names[i] = node->name;
+    }
+
+    return SECSuccess;
+
+no_mem:
+    PORT_SetError(SEC_ERROR_NO_MEMORY);
+    return SECFailure;
+
+alert_loser:
+    (void)SSL3_SendAlert(ss, alert_fatal,
+                         ss->version < SSL_LIBRARY_VERSION_TLS_1_0 ?
+                         illegal_parameter : decode_error);
+    PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
+    return SECFailure;
+}
+
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 Certificate Request message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     PLArenaPool *        arena       = NULL;
-    dnameNode *          node;
-    PRInt32              remaining;
     PRBool               isTLS       = PR_FALSE;
     PRBool               isTLS12     = PR_FALSE;
-    int                  i;
     int                  errCode     = SSL_ERROR_RX_MALFORMED_CERT_REQUEST;
-    int                  nnames      = 0;
     SECStatus            rv;
     SSL3AlertDescription desc        = illegal_parameter;
     SECItem              cert_types  = {siBuffer, NULL, 0};
     SECItem              algorithms  = {siBuffer, NULL, 0};
     CERTDistNames        ca_list;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake",
 		SSL_GETPID(), ss->fd));
@@ -7255,78 +7408,66 @@ ssl3_HandleCertificateRequest(sslSocket 
 	if (algorithms.len == 0 || (algorithms.len & 1) != 0)
 	    goto alert_loser;
     }
 
     arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (arena == NULL)
     	goto no_mem;
 
-    remaining = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
-    if (remaining < 0)
-    	goto loser;	 	/* malformed, alert has been sent */
-
-    if ((PRUint32)remaining > length)
-	goto alert_loser;
-
-    ca_list.head = node = PORT_ArenaZNew(arena, dnameNode);
-    if (node == NULL)
-    	goto no_mem;
-
-    while (remaining > 0) {
-	PRInt32 len;
-
-	if (remaining < 2)
-	    goto alert_loser;	/* malformed */
-
-	node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
-	if (len <= 0)
-	    goto loser;		/* malformed, alert has been sent */
-
-	remaining -= 2;
-	if (remaining < len)
-	    goto alert_loser;	/* malformed */
-
-	node->name.data = b;
-	b         += len;
-	length    -= len;
-	remaining -= len;
-	nnames++;
-	if (remaining <= 0)
-	    break;		/* success */
-
-	node->next = PORT_ArenaZNew(arena, dnameNode);
-	node = node->next;
-	if (node == NULL)
-	    goto no_mem;
-    }
-
-    ca_list.nnames = nnames;
-    ca_list.names  = PORT_ArenaNewArray(arena, SECItem, nnames);
-    if (nnames > 0 && ca_list.names == NULL)
-        goto no_mem;
-
-    for(i = 0, node = (dnameNode*)ca_list.head;
-	i < nnames;
-	i++, node = node->next) {
-	ca_list.names[i] = node->name;
-    }
+    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list);
+    if (rv != SECSuccess)
+        goto done;  /* alert sent in ssl3_ParseCertificateRequestCAs */
 
     if (length != 0)
-        goto alert_loser;   	/* malformed */
+        goto alert_loser;  /* malformed */
 
     desc = no_certificate;
+
     ss->ssl3.hs.ws = wait_hello_done;
 
+    rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list);
+    if (rv == SECFailure) {
+        PORT_Assert(0);
+        errCode = SEC_ERROR_LIBRARY_FAILURE;
+        desc = internal_error;
+        goto alert_loser;
+    }
+    goto done;
+
+no_mem:
+    rv = SECFailure;
+    PORT_SetError(SEC_ERROR_NO_MEMORY);
+    goto done;
+
+alert_loser:
+    if (isTLS && desc == illegal_parameter)
+    	desc = decode_error;
+    (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+    PORT_SetError(errCode);
+    rv = SECFailure;
+done:
+    if (arena != NULL)
+    	PORT_FreeArena(arena, PR_FALSE);
+    return rv;
+}
+
+SECStatus
+ssl3_CompleteHandleCertificateRequest(sslSocket *ss, SECItem *algorithms,
+                                      CERTDistNames *ca_list)
+{
+    SECStatus rv;
+
     if (ss->getClientAuthData != NULL) {
         PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
                     ssl_preinfo_all);
 	/* XXX Should pass cert_types and algorithms in this call!! */
 	rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
-						 ss->fd, &ca_list,
+                                                 ss->fd, ca_list,
 						 &ss->ssl3.clientCertificate,
 						 &ss->ssl3.clientPrivateKey);
     } else {
 	rv = SECFailure; /* force it to send a no_certificate alert */
     }
     switch (rv) {
     case SECWouldBlock:	/* getClientAuthData has put up a dialog box. */
 	ssl3_SetAlwaysBlock(ss);
@@ -7357,48 +7498,32 @@ ssl3_HandleCertificateRequest(sslSocket 
 	if (ss->ssl3.clientCertChain == NULL) {
 	    CERT_DestroyCertificate(ss->ssl3.clientCertificate);
 	    ss->ssl3.clientCertificate = NULL;
 	    SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
 	    ss->ssl3.clientPrivateKey = NULL;
 	    goto send_no_certificate;
 	}
 	if (ss->ssl3.hs.hashType == handshake_hash_single) {
-	    ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms);
+	    ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, algorithms);
 	}
 	break;	/* not an error */
 
     case SECFailure:
     default:
 send_no_certificate:
-	if (isTLS) {
+	if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) {
 	    ss->ssl3.sendEmptyCert = PR_TRUE;
 	} else {
 	    (void)SSL3_SendAlert(ss, alert_warning, no_certificate);
 	}
 	rv = SECSuccess;
 	break;
     }
-    goto done;
-
-no_mem:
-    rv = SECFailure;
-    PORT_SetError(SEC_ERROR_NO_MEMORY);
-    goto done;
-
-alert_loser:
-    if (isTLS && desc == illegal_parameter)
-    	desc = decode_error;
-    (void)SSL3_SendAlert(ss, alert_fatal, desc);
-loser:
-    PORT_SetError(errCode);
-    rv = SECFailure;
-done:
-    if (arena != NULL)
-    	PORT_FreeArena(arena, PR_FALSE);
+
     return rv;
 }
 
 static SECStatus
 ssl3_CheckFalseStart(sslSocket *ss)
 {
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
     PORT_Assert( !ss->ssl3.hs.authCertificatePending );
@@ -7464,18 +7589,18 @@ ssl3_WaitingForStartOfServerSecondRound(
         break;
     }
 
     return result;
 }
 
 static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Server Hello Done message.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 Server Hello Done message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerHelloDone(sslSocket *ss)
 {
     SECStatus     rv;
     SSL3WaitState ws          = ss->ssl3.hs.ws;
 
@@ -7573,21 +7698,23 @@ ssl3_SendClientSecondRound(sslSocket *ss
 	rv = ssl3_SendCertificate(ss);
 	if (rv != SECSuccess) {
 	    goto loser;	/* error code is set. */
     	}
     }
 
     rv = ssl3_SendClientKeyExchange(ss);
     if (rv != SECSuccess) {
-    	goto loser;	/* err is set. */
+        goto loser;    /* err is set. */
     }
 
     if (sendClientCert) {
-	rv = ssl3_SendCertificateVerify(ss);
+	rv = ssl3_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
+        SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+        ss->ssl3.clientPrivateKey = NULL;
 	if (rv != SECSuccess) {
 	    goto loser;	/* err is set. */
         }
     }
 
     rv = ssl3_SendChangeCipherSpecs(ss);
     if (rv != SECSuccess) {
 	goto loser;	/* err code was set. */
@@ -7882,38 +8009,45 @@ ssl3_HandleClientHello(sslSocket *ss, SS
     SSL3ProtocolVersion version;
     SECItem             sidBytes = {siBuffer, NULL, 0};
     SECItem             cookieBytes = {siBuffer, NULL, 0};
     SECItem             suites   = {siBuffer, NULL, 0};
     SECItem             comps    = {siBuffer, NULL, 0};
     PRBool              haveSpecWriteLock = PR_FALSE;
     PRBool              haveXmitBufLock   = PR_FALSE;
     PRBool              canOfferSessionTicket = PR_FALSE;
+    PRBool              isTLS13 = PR_FALSE;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake",
     	SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert( ss->ssl3.initialized );
     ss->ssl3.hs.preliminaryInfo = 0;
 
     if (!ss->sec.isServer ||
         (ss->ssl3.hs.ws != wait_client_hello &&
          ss->ssl3.hs.ws != idle_handshake)) {
         desc = unexpected_message;
         errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
         goto alert_loser;
     }
-    if (ss->ssl3.hs.ws == idle_handshake &&
-        ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
-        desc = no_renegotiation;
-        level = alert_warning;
-        errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
-        goto alert_loser;
+    if (ss->ssl3.hs.ws == idle_handshake) {
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+            desc = unexpected_message;
+            errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+            goto alert_loser;
+        }
+        if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+            desc = no_renegotiation;
+            level = alert_warning;
+            errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+            goto alert_loser;
+        }
     }
 
     /* Get peer name of client */
     rv = ssl_GetPeerInfo(ss);
     if (rv != SECSuccess) {
 	return rv;		/* error code is set. */
     }
 
@@ -7955,25 +8089,34 @@ ssl3_HandleClientHello(sslSocket *ss, SS
 
     rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
     if (rv != SECSuccess) {
     	desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version 
 	                                           : handshake_failure;
 	errCode = SSL_ERROR_UNSUPPORTED_VERSION;
 	goto alert_loser;
     }
+    isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
 
     rv = ssl3_InitHandshakeHashes(ss);
     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);
+    if (rv != SECSuccess) {
+        errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
+        goto loser;
+    }
+
     /* grab the client random data. */
     rv = ssl3_ConsumeHandshake(
 	ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
     if (rv != SECSuccess) {
 	goto loser;		/* malformed */
     }
 
     /* grab the client's SID, if present. */
@@ -8011,17 +8154,17 @@ ssl3_HandleClientHello(sslSocket *ss, SS
 
     /* grab the list of compression methods. */
     rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length);
     if (rv != SECSuccess) {
 	goto loser;		/* malformed */
     }
 
     /* TLS 1.3 requires that compression be empty */
-    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    if (isTLS13) {
         if (comps.len != 1 || comps.data[0] != ssl_compression_null) {
             goto loser;
         }
     }
     desc = handshake_failure;
 
     /* Handle TLS hello extensions for SSL3 & TLS. We do not know if
      * we are restarting a previous session until extensions have been
@@ -8036,32 +8179,32 @@ ssl3_HandleClientHello(sslSocket *ss, SS
 	extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
 	if (extension_length < 0) {
 	    goto loser;				/* alert already sent */
 	}
 	if (extension_length != length) {
 	    ssl3_DecodeError(ss);		/* send alert */
 	    goto loser;
 	}
-	rv = ssl3_HandleHelloExtensions(ss, &b, &length);
+	rv = ssl3_HandleHelloExtensions(ss, &b, &length, client_hello);
 	if (rv != SECSuccess) {
 	    goto loser;		/* malformed */
 	}
     }
     if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
     	/* If we didn't receive an RI extension, look for the SCSV,
 	 * and if found, treat it just like an empty RI extension
 	 * by processing a local copy of an empty RI extension.
 	 */
 	for (i = 0; i + 1 < suites.len; i += 2) {
 	    PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
 	    if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
 		SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
 		PRUint32     L2 = sizeof emptyRIext;
-		(void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
+		(void)ssl3_HandleHelloExtensions(ss, &b2, &L2, client_hello);
 	    	break;
 	    }
 	}
     }
     if (ss->firstHsDone &&
         (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
         ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) && 
 	!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
@@ -8669,28 +8812,44 @@ compression_found:
         if (!passed) {
             errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
             desc = handshake_failure;
             goto alert_loser;
         }
     }
 #endif
 
+    /* If this is TLS 1.3 we are expecting a ClientKeyShare
+     * extension. Missing/absent extension cause failure
+     * below. */
+    if (isTLS13) {
+        rv = tls13_HandleClientKeyShare(ss);
+        if (rv != SECSuccess) {
+            errCode = PORT_GetError();
+            goto alert_loser;
+        }
+    }
+
     sid = ssl3_NewSessionID(ss, PR_TRUE);
     if (sid == NULL) {
 	errCode = PORT_GetError();
 	goto loser;	/* memory error is set. */
     }
     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);
+    if (isTLS13) {
+        rv = tls13_SendServerHelloSequence(ss);
+    } else {
+        rv = ssl3_SendServerHelloSequence(ss);
+    }
     ssl_ReleaseXmitBufLock(ss);
     if (rv != SECSuccess) {
         errCode = PORT_GetError();
         desc = handshake_failure;
         goto alert_loser;
     }
 
     if (haveXmitBufLock) {
@@ -8862,17 +9021,17 @@ suite_found:
     /* Look for the SCSV, and if found, treat it just like an empty RI 
      * extension by processing a local copy of an empty RI extension.
      */
     for (i = 0; i+2 < suite_length; i += 3) {
 	PRUint32 suite_i = (suites[i] << 16) | (suites[i+1] << 8) | suites[i+2];
 	if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
 	    SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
 	    PRUint32     L2 = sizeof emptyRIext;
-	    (void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
+	    (void)ssl3_HandleHelloExtensions(ss, &b2, &L2, client_hello);
 	    break;
 	}
     }
 
     if (ss->opt.requireSafeNegotiation &&
 	!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
 	desc = handshake_failure;
 	errCode = SSL_ERROR_UNSAFE_NEGOTIATION;
@@ -8926,17 +9085,17 @@ loser:
 }
 
 /* The negotiated version number has been already placed in ss->version.
 **
 ** Called from:  ssl3_HandleClientHello                     (resuming session),
 ** 	ssl3_SendServerHelloSequence <- ssl3_HandleClientHello   (new session),
 ** 	ssl3_SendServerHelloSequence <- ssl3_HandleV2ClientHello (new session)
 */
-static SECStatus
+SECStatus
 ssl3_SendServerHello(sslSocket *ss)
 {
     sslSessionID *sid;
     SECStatus     rv;
     PRUint32      maxBytes = 65535;
     PRUint32      length;
     PRInt32       extensions_len = 0;
     SSL3ProtocolVersion version;
@@ -8960,76 +9119,86 @@ ssl3_SendServerHello(sslSocket *ss)
 	if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_DTLS_1_0)) {
 	    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
 	    return SECFailure;
 	}
     }
 
     sid = ss->sec.ci.sid;
 
-    extensions_len = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes,
-					       &ss->xtnData.serverSenders[0]);
+    extensions_len = ssl3_CallHelloExtensionSenders(
+        ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]);
     if (extensions_len > 0)
     	extensions_len += 2; /* Add sizeof total extension length */
 
-    length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 +
-             ((sid == NULL) ? 0: sid->u.ssl3.sessionIDLength) +
-	     sizeof(ssl3CipherSuite) + 1 + extensions_len;
+    /* TLS 1.3 doesn't use the session_id or compression_method
+     * fields in the ServerHello. */
+    length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH;
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        length += 1 + ((sid == NULL) ? 0: sid->u.ssl3.sessionIDLength);
+    }
+    length += sizeof(ssl3CipherSuite);
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        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)) {
 	version = dtls_TLSVersionToDTLSVersion(ss->version);
     } else {
 	version = ss->version;
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, version, 2);
     if (rv != SECSuccess) {
 	return rv;	/* err set by AppendHandshake. */
     }
-    rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random);
-    if (rv != SECSuccess) {
-	ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
-	return rv;
-    }
+    /* Random already generated in ssl3_HandleClientHello */
     rv = ssl3_AppendHandshake(
 	ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
 	return rv;	/* err set by AppendHandshake. */
     }
 
-    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. */
+    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. */
+        }
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2);
     if (rv != SECSuccess) {
 	return rv;	/* err set by AppendHandshake. */
     }
-    rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1);
-    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 (rv != SECSuccess) {
+            return rv;	/* err set by AppendHandshake. */
+        }
     }
     if (extensions_len) {
 	PRInt32 sent_len;
 
     	extensions_len -= 2;
 	rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2);
 	if (rv != SECSuccess) 
 	    return rv;	/* err set by ssl3_AppendHandshakeNumber */
 	sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len,
-					   &ss->xtnData.serverSenders[0]);
+					   &ss->xtnData.serverHelloSenders[0]);
         PORT_Assert(sent_len == extensions_len);
 	if (sent_len != extensions_len) {
 	    if (sent_len >= 0)
 	    	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 	    return SECFailure;
 	}
     }
     rv = ssl3_SetupPendingCipherSpec(ss);
@@ -9360,17 +9529,17 @@ ssl3_SendServerKeyExchange(sslSocket *ss
 	break;
     }
 loser:
     if (signed_hash.data != NULL) 
     	PORT_Free(signed_hash.data);
     return SECFailure;
 }
 
-static SECStatus
+SECStatus
 ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
                                      unsigned maxLen, PRUint32 *len)
 {
     unsigned int i;
 
     PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
     if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -9391,56 +9560,69 @@ ssl3_EncodeCertificateRequestSigAlgs(ssl
 
     if (*len == 0) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
     return SECSuccess;
 }
 
+void
+ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calen, SECItem **names,
+                              int *nnames)
+{
+    SECItem *name;
+    CERTDistNames *ca_list;
+    int i;
+
+    *calen = 0;
+    *names = NULL;
+    *nnames = 0;
+
+    /* ssl3.ca_list is initialized to NULL, and never changed. */
+    ca_list = ss->ssl3.ca_list;
+    if (!ca_list) {
+	ca_list = ssl3_server_ca_list;
+    }
+
+    if (ca_list != NULL) {
+	*names = ca_list->names;
+	*nnames = ca_list->nnames;
+    }
+
+    for (i = 0, name = *names; i < *nnames; i++, name++) {
+	*calen += 2 + name->len;
+    }
+}
+
 static SECStatus
 ssl3_SendCertificateRequest(sslSocket *ss)
 {
     PRBool         isTLS12;
-    SECItem *      name;
-    CERTDistNames *ca_list;
     const PRUint8 *certTypes;
-    SECItem *      names	= NULL;
     SECStatus      rv;
     int            length;
+    SECItem *      names;
+    int            calen;
+    int            nnames;
+    SECItem *      name;
     int            i;
-    int            calen	= 0;
-    int            nnames	= 0;
     int            certTypesLength;
     PRUint8        sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
     unsigned int   sigAlgsLength = 0;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
 		SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    /* ssl3.ca_list is initialized to NULL, and never changed. */
-    ca_list = ss->ssl3.ca_list;
-    if (!ca_list) {
-	ca_list = ssl3_server_ca_list;
-    }
-
-    if (ca_list != NULL) {
-	names = ca_list->names;
-	nnames = ca_list->nnames;
-    }
-
-    for (i = 0, name = names; i < nnames; i++, name++) {
-	calen += 2 + name->len;
-    }
-
+    ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
     certTypes       = certificate_types;
     certTypesLength = sizeof certificate_types;
 
     length = 1 + certTypesLength + 2 + calen;
     if (isTLS12) {
         rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs),
                                                   &sigAlgsLength);
         if (rv != SECSuccess) {
@@ -9494,18 +9676,18 @@ ssl3_SendServerHelloDone(sslSocket *ss)
     }
     rv = ssl3_FlushHandshake(ss, 0);
     if (rv != SECSuccess) {
 	return rv;	/* error code set by ssl3_FlushHandshake */
     }
     return SECSuccess;
 }
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Certificate Verify message
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 Certificate Verify message
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 			     SSL3Hashes *hashes)
 {
     SECItem              signed_hash = {siBuffer, NULL, 0};
     SECStatus            rv;
@@ -9617,22 +9799,21 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3C
 	/* The specReadLock would suffice here, but we cannot assert on
 	** read locks.  Also, all the callers who call with a non-null
 	** slot already hold the SpecWriteLock.
 	*/
 	PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
 	PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
 
         calg = spec->cipher_def->calg;
-	PORT_Assert(alg2Mech[calg].calg == calg);
 
 	/* First get an appropriate slot.  */
 	mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
 	mechanism_array[1] = CKM_RSA_PKCS;
-	mechanism_array[2] = alg2Mech[calg].cmech;
+	mechanism_array[2] = ssl3_Alg2Mech(calg);
 
 	slot = PK11_GetBestSlotMultiple(mechanism_array, 3, pwArg);
 	if (slot == NULL) {
 	   /* can't find a slot with all three, find a slot with the minimum */
 	    slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
 	    if (slot == NULL) {
 		PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
 		return pms;	/* which is NULL */
@@ -9924,18 +10105,18 @@ loser:
     if (ss->dheKeyPair) {
         ssl3_FreeKeyPair(ss->dheKeyPair);
         ss->dheKeyPair = NULL;
     }
     return rv;
 }
 
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 ClientKeyExchange message from the remote client
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 ClientKeyExchange message from the remote client
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECKEYPrivateKey *serverKey         = NULL;
     SECStatus         rv;
     const ssl3KEADef *kea_def;
@@ -10075,26 +10256,42 @@ skip:
 	return SECFailure;
     }
     ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher;
     return SECSuccess;
 
 }
 
 /* This is TLS's equivalent of sending a no_certificate alert. */
-static SECStatus
+SECStatus
 ssl3_SendEmptyCertificate(sslSocket *ss)
 {
-    SECStatus            rv;
-
-    rv = ssl3_AppendHandshakeHeader(ss, certificate, 3);
-    if (rv == SECSuccess) {
-	rv = ssl3_AppendHandshakeNumber(ss, 0, 3);
-    }
-    return rv;	/* error, if any, set by functions called above. */
+    SECStatus rv;
+    unsigned int len = 0;
+    PRBool isTLS13 = PR_FALSE;
+
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        len = ss->ssl3.hs.certReqContextLen + 1;
+        isTLS13 = PR_TRUE;
+    }
+
+    rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+
+    if (isTLS13) {
+        rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.certReqContext,
+                                          ss->ssl3.hs.certReqContextLen, 1);
+        if (rv != SECSuccess) {
+            return rv;
+        }
+    }
+
+    return ssl3_AppendHandshakeNumber(ss, 0, 3);
 }
 
 SECStatus
 ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus rv;
     SECItem ticketData;
 
@@ -10208,28 +10405,30 @@ loser:
     return SECFailure;
 }
 #endif
 
 /*
  * Used by both client and server.
  * Called from HandleServerHelloDone and from SendServerHelloSequence.
  */
-static SECStatus
+SECStatus
 ssl3_SendCertificate(sslSocket *ss)
 {
     SECStatus            rv;
     CERTCertificateList *certChain;
-    int                  len 		= 0;
+    int                  certChainLen = 0;
     int                  i;
     SSL3KEAType          certIndex;
 #ifdef NISCC_TEST
     SECItem              fakeCert;
     int                  ndex           = -1;
 #endif
+    PRBool               isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
+    unsigned int         contextLen     = 0;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake",
 		SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->sec.localCert)
@@ -10260,35 +10459,56 @@ ssl3_SendCertificate(sslSocket *ss)
 	certChain          = ss->ssl3.clientCertChain;
 	ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
     }
 
 #ifdef NISCC_TEST
     rv = get_fake_cert(&fakeCert, &ndex);
 #endif
 
+    if (isTLS13) {
+        contextLen = 1;  /* Length of the context */
+        if (!ss->sec.isServer) {
+            contextLen += ss->ssl3.hs.certReqContextLen;
+        }
+    }
     if (certChain) {
 	for (i = 0; i < certChain->len; i++) {
 #ifdef NISCC_TEST
 	    if (fakeCert.len > 0 && i == ndex) {
-		len += fakeCert.len + 3;
+		certChainLen += fakeCert.len + 3;
 	    } else {
-		len += certChain->certs[i].len + 3;
+		certChainLen += certChain->certs[i].len + 3;
 	    }
 #else
-	    len += certChain->certs[i].len + 3;
+	    certChainLen += certChain->certs[i].len + 3;
 #endif
 	}
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
+    rv = ssl3_AppendHandshakeHeader(ss, certificate,
+                                    contextLen + certChainLen + 3);
     if (rv != SECSuccess) {
 	return rv; 		/* err set by AppendHandshake. */
     }
-    rv = ssl3_AppendHandshakeNumber(ss, len, 3);
+
+    if (isTLS13) {
+        if (ss->sec.isServer) {
+            rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+        } else {
+            rv = ssl3_AppendHandshakeVariable(ss,
+                                              ss->ssl3.hs.certReqContext,
+                                              ss->ssl3.hs.certReqContextLen, 1);
+        }
+        if (rv != SECSuccess) {
+            return rv;          /* err set by AppendHandshake. */
+        }
+    }
+
+    rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3);
     if (rv != SECSuccess) {
 	return rv; 		/* err set by AppendHandshake. */
     }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
 #ifdef NISCC_TEST
             if (fakeCert.len > 0 && i == ndex) {
                 rv = ssl3_AppendHandshakeVariable(ss, fakeCert.data,
@@ -10310,17 +10530,17 @@ ssl3_SendCertificate(sslSocket *ss)
 
     return SECSuccess;
 }
 
 /*
  * Used by server only.
  * single-stapling, send only a single cert status
  */
-static SECStatus
+SECStatus
 ssl3_SendCertificateStatus(sslSocket *ss)
 {
     SECStatus rv;
     int len = 0;
     SECItemArray *statusToSend = NULL;
     SSL3KEAType certIndex;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake",
@@ -10379,31 +10599,42 @@ ssl3_CleanupPeerCerts(sslSocket *ss)
     for (; certs; certs = certs->next) {
 	CERT_DestroyCertificate(certs->cert);
     }
     if (arena) PORT_FreeArena(arena, PR_FALSE);
     ss->ssl3.peerCertArena = NULL;
     ss->ssl3.peerCertChain = NULL;
 }
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 CertificateStatus message.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 CertificateStatus message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
-    PRInt32 status, len;
-
     if (ss->ssl3.hs.ws != wait_certificate_status) {
         (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS);
         return SECFailure;
     }
 
+    return ssl3_CompleteHandleCertificateStatus(ss, b, length);
+}
+
+/* Called from:
+ *      ssl3_HandleCertificateStatus
+ *      tls13_HandleCertificateStatus
+ */
+SECStatus
+ssl3_CompleteHandleCertificateStatus(sslSocket *ss, SSL3Opaque *b,
+                                     PRUint32 length)
+{
+    PRInt32 status, len;
+
     PORT_Assert(!ss->sec.isServer);
 
     /* Consume the CertificateStatusType enum */
     status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
     if (status != 1 /* ocsp */) {
        goto format_loser;
     }
 
@@ -10434,46 +10665,54 @@ ssl3_HandleCertificateStatus(sslSocket *
     ss->sec.ci.sid->peerCertStatus.items[0].type = siBuffer;
 
     return ssl3_AuthCertificate(ss);
 
 format_loser:
     return ssl3_DecodeError(ss);
 }
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Certificate message.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 Certificate message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
+    SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake",
+		SSL_GETPID(), ss->fd));
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    if ((ss->sec.isServer && ss->ssl3.hs.ws != wait_client_cert) ||
+        (!ss->sec.isServer && ss->ssl3.hs.ws != wait_server_cert)) {
+        (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+        PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE);
+        return SECFailure;
+    }
+
+    return ssl3_CompleteHandleCertificate(ss, b, length);
+}
+
+/* Called from ssl3_HandleCertificate
+ */
+SECStatus
+ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
     ssl3CertNode *   c;
     ssl3CertNode *   lastCert 	= NULL;
     PRInt32          remaining  = 0;
     PRInt32          size;
     SECStatus        rv;
     PRBool           isServer	= (PRBool)(!!ss->sec.isServer);
     PRBool           isTLS;
     SSL3AlertDescription desc;
     int              errCode    = SSL_ERROR_RX_MALFORMED_CERTIFICATE;
     SECItem          certItem;
 
-    SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake",
-		SSL_GETPID(), ss->fd));
-    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
-    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
-
-    if ((isServer && ss->ssl3.hs.ws != wait_client_cert) ||
-        (!isServer && ss->ssl3.hs.ws != wait_server_cert)) {
-        desc = unexpected_message;
-        errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
-        goto alert_loser;
-    }
-
     if (ss->sec.peerCert != NULL) {
 	if (ss->sec.peerKey) {
 	    SECKEY_DestroyPublicKey(ss->sec.peerKey);
 	    ss->sec.peerKey = NULL;
 	}
 	CERT_DestroyCertificate(ss->sec.peerCert);
 	ss->sec.peerCert = NULL;
     }
@@ -10500,18 +10739,23 @@ ssl3_HandleCertificate(sslSocket *ss, SS
 	}
     	/* This is TLS's version of a no_certificate alert. */
     	/* I'm a server. I've requested a client cert. He hasn't got one. */
 	rv = ssl3_HandleNoCertificate(ss);
 	if (rv != SECSuccess) {
 	    errCode = PORT_GetError();
 	    goto loser;
 	}
-       ss->ssl3.hs.ws = wait_client_key;
-       return SECSuccess;
+
+        if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+            ss->ssl3.hs.ws = wait_client_key;
+        } else {
+            TLS13_SET_HS_STATE(ss, wait_finished);
+        }
+        return SECSuccess;
     }
 
     ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (ss->ssl3.peerCertArena == NULL) {
 	goto loser;	/* don't send alerts on memory errors */
     }
 
     /* First get the peer cert. */
@@ -10631,58 +10875,63 @@ ssl3_AuthCertificate(sslSocket *ss)
 
     PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
                 ssl_preinfo_all);
     /*
      * Ask caller-supplied callback function to validate cert chain.
      */
     rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd,
 					   PR_TRUE, isServer);
-    if (rv) {
+    if (rv != SECSuccess) {
 	errCode = PORT_GetError();
 	if (rv != SECWouldBlock) {
 	    if (ss->handleBadCert) {
 		rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
 	    }
 	}
 
 	if (rv == SECWouldBlock) {
 	    if (ss->sec.isServer) {
 		errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
 		rv = SECFailure;
 		goto loser;
 	    }
+            /* TODO(ekr@rtfm.com): Reenable for TLS 1.3 */
+            if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+                errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION;
+                rv = SECFailure;
+		goto loser;
+            }
 
 	    ss->ssl3.hs.authCertificatePending = PR_TRUE;
 	    rv = SECSuccess;
 	}
 
 	if (rv != SECSuccess) {
 	    ssl3_SendAlertForCertError(ss, errCode);
 	    goto loser;
 	}
     }
 
     ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
 
     if (!ss->sec.isServer) {
         CERTCertificate *cert = ss->sec.peerCert;
 
-	/* set the server authentication and key exchange types and sizes
-	** from the value in the cert.  If the key exchange key is different,
-	** it will get fixed when we handle the server key exchange message.
-	*/
+	/* set the server authentication type and size from the value
+        ** in the cert. */
 	SECKEYPublicKey * pubKey  = CERT_ExtractPublicKey(cert);
 	ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
 	ss->sec.keaType       = ss->ssl3.hs.kea_def->exchKeyType;
 	if (pubKey) {
 	    KeyType pubKeyType;
 	    PRInt32  minKey;
-	    ss->sec.keaKeyBits = ss->sec.authKeyBits =
-		SECKEY_PublicKeyStrengthInBits(pubKey);
+            /* This partly fixes Bug 124230 and may cause problems for
+             * callers which depend on the old (wrong) behavior. */
+            ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
             pubKeyType = SECKEY_GetPublicKeyType(pubKey);
 	    minKey = ss->sec.authKeyBits;
 	    switch (pubKeyType) {
 	    case rsaKey:
 	    case rsaPssKey:
 	    case rsaOaepKey:
 		rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey);
 		if (rv != SECSuccess) {
@@ -10716,29 +10965,43 @@ ssl3_AuthCertificate(sslSocket *ss)
                                      : illegal_parameter);
                 SECKEY_DestroyPublicKey(pubKey);
                 return SECFailure;
             }
 	    SECKEY_DestroyPublicKey(pubKey); 
 	    pubKey = NULL;
     	}
 
-        /* Ephemeral suites require ServerKeyExchange. Export cipher suites
-         * with RSA key exchange also require ServerKeyExchange if the
-         * authentication key exceeds the key size limit. */
-        if (ss->ssl3.hs.kea_def->ephemeral ||
-            (ss->ssl3.hs.kea_def->is_limited &&
-             ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa &&
-             ss->sec.authKeyBits > ss->ssl3.hs.kea_def->key_size_limit)) {
-            ss->ssl3.hs.ws = wait_server_key; /* require server_key_exchange */
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+            TLS13_SET_HS_STATE(ss, wait_cert_verify);
         } else {
-            ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
+            /* Ephemeral suites require ServerKeyExchange. Export cipher suites
+             * with RSA key exchange also require ServerKeyExchange if the
+             * authentication key exceeds the key size limit. */
+            if (ss->ssl3.hs.kea_def->ephemeral ||
+                (ss->ssl3.hs.kea_def->is_limited &&
+                 ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa &&
+                 ss->sec.authKeyBits > ss->ssl3.hs.kea_def->key_size_limit)) {
+                /* require server_key_exchange */
+                ss->ssl3.hs.ws = wait_server_key;
+            } else  {
+                /* disallow server_key_exchange */
+                ss->ssl3.hs.ws = wait_cert_request;
+                /* This is static RSA key exchange so set the key bits to
+                 * auth bits. */
+                ss->sec.keaKeyBits = ss->sec.authKeyBits;
+            }
         }
     } else {
-	ss->ssl3.hs.ws = wait_client_key;
+        /* Server */
+        if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+            ss->ssl3.hs.ws = wait_client_key;
+        } else {
+            TLS13_SET_HS_STATE(ss, wait_cert_verify);
+        }
     }
 
     PORT_Assert(rv == SECSuccess);
     if (rv != SECSuccess) {
 	errCode = SEC_ERROR_LIBRARY_FAILURE;
 	rv = SECFailure;
 	goto loser;
     }
@@ -11183,18 +11446,18 @@ ssl3_CacheWrappedMasterSecret(sslSocket 
 			     spec->master_secret, &wmsItem);
 	/* rv is examined below. */
 	sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len;
 	PK11_FreeSymKey(wrappingKey);
     }
     return rv;
 }
 
-/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
- * ssl3 Finished message from the peer.
+/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
+ * a complete ssl3 Finished message from the peer.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 		    const SSL3Hashes *hashes)
 {
     sslSessionID *    sid	   = ss->sec.ci.sid;
     SECStatus         rv           = SECSuccess;
@@ -11444,28 +11707,45 @@ SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus         rv 	= SECSuccess;
     SSL3HandshakeType type 	= ss->ssl3.hs.msg_type;
     SSL3Hashes        hashes;	/* computed hashes are put here. */
     SSL3Hashes       *hashesPtr = NULL;  /* Set when hashes are computed */
     PRUint8           hdr[4];
     PRUint8           dtlsData[8];
+    PRBool            computeHashes = PR_FALSE;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
     /*
      * We have to compute the hashes before we update them with the
      * current message.
      */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        if(((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
+           ((type == certificate_verify) &&
+            (ss->ssl3.hs.ws == wait_cert_verify))) {
+            computeHashes = PR_TRUE;
+        }
+    } else {
+        if (type == certificate_verify) {
+            computeHashes =
+                    TLS13_IN_HS_STATE(ss, wait_cert_verify);
+        } else if (type == finished) {
+            computeHashes =
+                    TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished);
+        }
+    }
+
     ssl_GetSpecReadLock(ss);	/************************************/
-    if(((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
-       ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify))) {
+    if (computeHashes) {
 	SSL3Sender      sender = (SSL3Sender)0;
-	ssl3CipherSpec *rSpec  = ss->ssl3.prSpec;
+	ssl3CipherSpec *rSpec  = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ?
+                ss->ssl3.crSpec : ss->ssl3.prSpec;
 
 	if (type == finished) {
 	    sender = ss->sec.isServer ? sender_client : sender_server;
 	    rSpec  = ss->ssl3.crSpec;
 	}
 	rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
         if (rv == SECSuccess) {
             hashesPtr = &hashes;
@@ -11537,45 +11817,70 @@ ssl3_HandleHandshakeMessage(sslSocket *s
         rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
         PORT_Assert(rv != SECWouldBlock);
         if (rv != SECSuccess) {
             return rv;
         }
     }
 
     switch (ss->ssl3.hs.msg_type) {
-    case hello_request:
-	if (length != 0) {
-	    (void)ssl3_DecodeError(ss);
-	    PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST);
-	    return SECFailure;
-	}
-	if (ss->sec.isServer) {
-	    (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
-	    PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
-	    return SECFailure;
-	}
-	rv = ssl3_HandleHelloRequest(ss);
-	break;
     case client_hello:
 	if (!ss->sec.isServer) {
 	    (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	    PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO);
 	    return SECFailure;
 	}
 	rv = ssl3_HandleClientHello(ss, b, length);
 	break;
     case server_hello:
 	if (ss->sec.isServer) {
 	    (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	    PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO);
 	    return SECFailure;
 	}
 	rv = ssl3_HandleServerHello(ss, b, length);
 	break;
+    default:
+        if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+            rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr);
+        } else {
+            rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length,
+                                                       hashesPtr);
+        }
+        break;
+    }
+
+    if (IS_DTLS(ss) && (rv != SECFailure)) {
+	/* Increment the expected sequence number */
+	ss->ssl3.hs.recvMessageSeq++;
+    }
+    return rv;
+}
+
+static SECStatus
+ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
+                                     PRUint32 length, SSL3Hashes *hashesPtr)
+{
+    SECStatus rv;
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
+    switch (ss->ssl3.hs.msg_type) {
+    case hello_request:
+	if (length != 0) {
+	    (void)ssl3_DecodeError(ss);
+	    PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST);
+	    return SECFailure;
+	}
+        if (ss->sec.isServer) {
+            (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+            PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
+            return SECFailure;
+        }
+	rv = ssl3_HandleHelloRequest(ss);
+	break;
     case hello_verify_request:
 	if (!IS_DTLS(ss) || ss->sec.isServer) {
 	    (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	    PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST);
 	    return SECFailure;
 	}
 	rv = dtls_HandleHelloVerifyRequest(ss, b, length);
 	break;
@@ -11642,21 +11947,16 @@ ssl3_HandleHandshakeMessage(sslSocket *s
         rv = ssl3_HandleFinished(ss, b, length, hashesPtr);
 	break;
     default:
 	(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE);
 	rv = SECFailure;
     }
 
-    if (IS_DTLS(ss) && (rv != SECFailure)) {
-	/* Increment the expected sequence number */
-	ss->ssl3.hs.recvMessageSeq++;
-    }
-
     return rv;
 }
 
 /* Called only from ssl3_HandleRecord, for each (deciphered) ssl3 record.
  * origBuf is the decrypted ssl record content.
  * Caller must hold the handshake and RecvBuf locks.
  */
 static SECStatus
@@ -11954,125 +12254,45 @@ ssl_CBCExtractMAC(sslBuffer *plaintext,
 	unsigned char offset =
 	    (divSpoiler + macSize - rotateOffset + i) % macSize;
 	for (j = 0; j < macSize; j++) {
 	    out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, offset);
 	}
     }
 }
 
-/* if cText is non-null, then decipher, check MAC, and decompress the
- * SSL record from cText->buf (typically gs->inbuf)
- * into databuf (typically gs->buf), and any previous contents of databuf
- * is lost.  Then handle databuf according to its SSL record type,
- * unless it's an application record.
- *
- * If cText is NULL, then the ciphertext has previously been deciphered and
- * checked, and is already sitting in databuf.  It is processed as an SSL
- * Handshake message.
+/* Unprotect an SSL3 record and leave the result in plaintext.
  *
- * DOES NOT process the decrypted/decompressed application data.
- * On return, databuf contains the decrypted/decompressed record.
- *
- * Called from ssl3_GatherCompleteHandshake
- *             ssl3_RestartHandshakeAfterCertReq
+ * If SECFailure is returned, we:
+ * 1. Set |*alert| to the alert to be sent.
+ * 2. Call PORT_SetError() with an appropriate code.
  *
- * Caller must hold the RecvBufLock.
+ * Called by ssl3_HandleRecord. Caller must hold the spec read lock.
+ * Therefore, we MUST not call SSL3_SendAlert().
  *
- * This function aquires and releases the SSL3Handshake Lock, holding the
- * lock around any calls to functions that handle records other than
- * Application Data records.
  */
-SECStatus
-ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
-{
-    const ssl3BulkCipherDef *cipher_def;
-    ssl3CipherSpec *     crSpec;
-    SECStatus            rv;
-    unsigned int         hashBytes = MAX_MAC_LENGTH + 1;
-    PRBool               isTLS;
-    SSL3ContentType      rType;
-    SSL3Opaque           hash[MAX_MAC_LENGTH];
-    SSL3Opaque           givenHashBuf[MAX_MAC_LENGTH];
-    SSL3Opaque          *givenHash;
-    sslBuffer           *plaintext;
-    sslBuffer            temp_buf;
-    PRUint64             dtls_seq_num = 0;
-    unsigned int         ivLen = 0;
-    unsigned int         originalLen = 0;
-    unsigned int         good;
-    unsigned int         minLength;
-    unsigned char        header[13];
-    unsigned int         headerLen;
-
-    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
-
-    if (!ss->ssl3.initialized) {
-	ssl_GetSSL3HandshakeLock(ss);
-	rv = ssl3_InitState(ss);
-	ssl_ReleaseSSL3HandshakeLock(ss);
-	if (rv != SECSuccess) {
-	    return rv;		/* ssl3_InitState has set the error code. */
-    	}
-    }
-
-    /* check for Token Presence */
-    if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
-	PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
-	return SECFailure;
-    }
-
-    /* cText is NULL when we're called from ssl3_RestartHandshakeAfterXXX().
-     * This implies that databuf holds a previously deciphered SSL Handshake
-     * message.
-     */
-    if (cText == NULL) {
-	SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake",
-		 SSL_GETPID(), ss->fd));
-	rType = content_handshake;
-	goto process_it;
-    }
-
-    ssl_GetSpecReadLock(ss); /******************************************/
-
-    crSpec = ss->ssl3.crSpec;
-    cipher_def = crSpec->cipher_def;
-
-    /* 
-     * DTLS relevance checks:
-     * Note that this code currently ignores all out-of-epoch packets,
-     * which means we lose some in the case of rehandshake +
-     * loss/reordering. Since DTLS is explicitly unreliable, this
-     * seems like a good tradeoff for implementation effort and is
-     * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1
-     */
-    if (IS_DTLS(ss)) {
-	DTLSEpoch epoch = (cText->seq_num.high >> 16) & 0xffff;
-	
-	if (crSpec->epoch != epoch) {
-	    ssl_ReleaseSpecReadLock(ss);
-	    SSL_DBG(("%d: SSL3[%d]: HandleRecord, received packet "
-		     "from irrelevant epoch %d", SSL_GETPID(), ss->fd, epoch));
-	    /* Silently drop the packet */
-            databuf->len = 0; /* Needed to ensure data not left around */
-	    return SECSuccess;
-	}
-
-	dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) |
-			((PRUint64)cText->seq_num.low);
-
-	if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) {
-	    ssl_ReleaseSpecReadLock(ss);
-	    SSL_DBG(("%d: SSL3[%d]: HandleRecord, rejecting "
-		     "potentially replayed packet", SSL_GETPID(), ss->fd));
-	    /* Silently drop the packet */
-            databuf->len = 0; /* Needed to ensure data not left around */
-	    return SECSuccess;
-	}
-    }
+static SECStatus
+ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
+                     SSL3AlertDescription *alert)
+{
+    ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
+    const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def;
+    PRBool isTLS;
+    unsigned int good;
+    unsigned int ivLen = 0;
+    SSL3ContentType rType;
+    unsigned int minLength;
+    unsigned int originalLen = 0;
+    unsigned char header[13];
+    unsigned int headerLen;
+    SSL3Opaque hash[MAX_MAC_LENGTH];
+    SSL3Opaque givenHashBuf[MAX_MAC_LENGTH];
+    SSL3Opaque *givenHash;
+    unsigned int hashBytes = MAX_MAC_LENGTH + 1;
+    SECStatus rv;
 
     good = ~0U;
     minLength = crSpec->mac_size;
     if (cipher_def->type == type_block) {
 	/* CBC records have a padding length byte at the end. */
 	minLength++;
 	if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
 	    /* With >= TLS 1.1, CBC records have an explicit IV. */
@@ -12096,64 +12316,40 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
 	 * component." Instead, we decrypt the first cipher block and then
 	 * discard it before decrypting the rest.
 	 */
 	SSL3Opaque iv[MAX_IV_LENGTH];
 	int decoded;
 
 	ivLen = cipher_def->iv_size;
 	if (ivLen < 8 || ivLen > sizeof(iv)) {
-	    ssl_ReleaseSpecReadLock(ss);
+            *alert = internal_error;
 	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 	    return SECFailure;
 	}
 
 	PRINT_BUF(80, (ss, "IV (ciphertext):", cText->buf->buf, ivLen));
 
 	/* The decryption result is garbage, but since we just throw away
 	 * the block it doesn't matter.  The decryption of the next block
 	 * depends only on the ciphertext of the IV block.
 	 */
 	rv = crSpec->decode(crSpec->decodeContext, iv, &decoded,
 			    sizeof(iv), cText->buf->buf, ivLen);
 
 	good &= SECStatusToMask(rv);
     }
 
-    /* If we will be decompressing the buffer we need to decrypt somewhere
-     * other than into databuf */
-    if (crSpec->decompressor) {
-	temp_buf.buf = NULL;
-	temp_buf.space = 0;
-	plaintext = &temp_buf;
-    } else {
-	plaintext = databuf;
-    }
-
-    plaintext->len = 0; /* filled in by decode call below. */
-    if (plaintext->space < MAX_FRAGMENT_LENGTH) {
-	rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
-	if (rv != SECSuccess) {
-	    ssl_ReleaseSpecReadLock(ss);
-	    SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
-		     SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
-	    /* sslBuffer_Grow has set a memory error code. */
-	    /* Perhaps we should send an alert. (but we have no memory!) */
-	    return SECFailure;
-	}
-    }
-
     PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen,
 				      cText->buf->len - ivLen));
 
     isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) {
-	ssl_ReleaseSpecReadLock(ss);
-	SSL3_SendAlert(ss, alert_fatal, record_overflow);
+        *alert = record_overflow;
 	PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
 	return SECFailure;
     }
 
     rType = cText->type;
     if (cipher_def->type == type_aead) {
 	/* XXX For many AEAD ciphers, the plaintext is shorter than the
 	 * ciphertext by a fixed byte count, but it is not true in general.
@@ -12250,44 +12446,165 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
 	    NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
 	    /* We're allowed to leak whether or not the MAC check was correct */
 	    good = 0;
 	}
     }
 
     if (good == 0) {
 decrypt_loser:
-	/* must not hold spec lock when calling SSL3_SendAlert. */
+        /* always log mac error, in case attacker can read server logs. */
+        PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+        *alert = bad_record_mac;
+        return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* if cText is non-null, then decipher, check MAC, and decompress the
+ * SSL record from cText->buf (typically gs->inbuf)
+ * into databuf (typically gs->buf), and any previous contents of databuf
+ * is lost.  Then handle databuf according to its SSL record type,
+ * unless it's an application record.
+ *
+ * If cText is NULL, then the ciphertext has previously been deciphered and
+ * checked, and is already sitting in databuf.  It is processed as an SSL
+ * Handshake message.
+ *
+ * DOES NOT process the decrypted/decompressed application data.
+ * On return, databuf contains the decrypted/decompressed record.
+ *
+ * Called from ssl3_GatherCompleteHandshake
+ *             ssl3_RestartHandshakeAfterCertReq
+ *
+ * Caller must hold the RecvBufLock.
+ *
+ * This function aquires and releases the SSL3Handshake Lock, holding the
+ * lock around any calls to functions that handle records other than
+ * Application Data records.
+ */
+SECStatus
+ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
+{
+    SECStatus            rv;
+    PRBool               isTLS;
+    PRUint64             dtls_seq_num = 0;
+    ssl3CipherSpec      *crSpec;
+    SSL3ContentType      rType;
+    sslBuffer           *plaintext;
+    sslBuffer            temp_buf;
+    SSL3AlertDescription alert;
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+    if (!ss->ssl3.initialized) {
+	ssl_GetSSL3HandshakeLock(ss);
+	rv = ssl3_InitState(ss);
+	ssl_ReleaseSSL3HandshakeLock(ss);
+	if (rv != SECSuccess) {
+	    return rv;		/* ssl3_InitState has set the error code. */
+    	}
+    }
+
+    /* check for Token Presence */
+    if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
+	PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+	return SECFailure;
+    }
+
+    /* cText is NULL when we're called from ssl3_RestartHandshakeAfterXXX().
+     * This implies that databuf holds a previously deciphered SSL Handshake
+     * message.
+     */
+    if (cText == NULL) {
+	SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake",
+		 SSL_GETPID(), ss->fd));
+	rType = content_handshake;
+	goto process_it;
+    }
+
+    ssl_GetSpecReadLock(ss); /******************************************/
+    crSpec = ss->ssl3.crSpec;
+    isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+    if (IS_DTLS(ss)) {
+        if (!dtls_IsRelevant(ss, crSpec, cText, &dtls_seq_num)) {
+	    ssl_ReleaseSpecReadLock(ss);
+	    /* Silently drop the packet */
+            databuf->len = 0; /* Needed to ensure data not left around */
+	    return SECSuccess;
+        }
+    }
+
+    /* If we will be decompressing the buffer we need to decrypt somewhere
+     * other than into databuf */
+    if (crSpec->decompressor) {
+	temp_buf.buf = NULL;
+	temp_buf.space = 0;
+	plaintext = &temp_buf;
+    } else {
+	plaintext = databuf;
+    }
+
+    plaintext->len = 0; /* filled in by Unprotect call below. */
+    if (plaintext->space < MAX_FRAGMENT_LENGTH) {
+	rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
+	if (rv != SECSuccess) {
+	    ssl_ReleaseSpecReadLock(ss);
+	    SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
+		     SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
+	    /* sslBuffer_Grow has set a memory error code. */
+	    /* Perhaps we should send an alert. (but we have no memory!) */
+	    return SECFailure;
+	}
+    }
+
+    /* IMPORTANT: Unprotect functions MUST NOT send alerts
+     * because we still hold the spec read lock. Instead, if they
+     * return SECFailure, they set *alert to the alert to be sent. */
+    if (crSpec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+        crSpec->cipher_def->calg == ssl_calg_null) {
+        /* Unencrypted TLS 1.3 records use the pre-TLS 1.3 format. */
+        rv = ssl3_UnprotectRecord(ss, cText, plaintext, &alert);
+    } else {
+        rv = tls13_UnprotectRecord(ss, cText, plaintext, &alert);
+    }
+
+    if (rv != SECSuccess) {
 	ssl_ReleaseSpecReadLock(ss);
 
 	SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
 
 	if (!IS_DTLS(ss)) {
-	    SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
-	    /* always log mac error, in case attacker can read server logs. */
-	    PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+            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;
 	} else {
 	    /* Silently drop the packet */
             databuf->len = 0; /* Needed to ensure data not left around */
 	    return SECSuccess;
 	}
     }
 
+    /* SECSuccess */
     if (!IS_DTLS(ss)) {
 	ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
     } else {
 	dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num);
     }
 
     ssl_ReleaseSpecReadLock(ss); /*****************************************/
 
     /*
      * The decrypted data is now in plaintext.
      */
+    rType = cText->type;  /* This must go after decryption because TLS 1.3
+                           * has encrypted content types. */
 
     /* possibly decompress the record. If we aren't using compression then
      * plaintext == databuf and so the uncompressed data is already in
      * databuf. */
     if (crSpec->decompressor) {
 	if (databuf->space < plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION) {
 	    rv = sslBuffer_Grow(
 	        databuf, plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION);
@@ -12491,16 +12808,24 @@ ssl3_InitState(sslSocket *ss)
 	ss->ssl3.hs.recvMessageSeq = 0;
 	ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
 	ss->ssl3.hs.rtRetries = 0;
 	ss->ssl3.hs.recvdHighWater = -1;
 	PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
 	dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */
     }
 
+    PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
+    ss->ssl3.hs.xSS = NULL;
+    ss->ssl3.hs.xES = NULL;
+    ss->ssl3.hs.trafficSecret = NULL;
+    ss->ssl3.hs.clientFinishedSecret = NULL;
+    ss->ssl3.hs.serverFinishedSecret = NULL;
+    ss->ssl3.hs.certReqContextLen = 0;
+
     PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space);
     ss->ssl3.hs.messages.buf = NULL;
     ss->ssl3.hs.messages.space = 0;
 
     ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
     PORT_Memset(&ss->ssl3.hs.newSessionTicket, 0,
 		sizeof(ss->ssl3.hs.newSessionTicket));
 
@@ -12874,17 +13199,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
 	if (ss->ssl3.hs.hashType == handshake_hash_combo) {
 	    SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE);
 	    MD5_DestroyContext((MD5Context *)ss->ssl3.hs.md5_cx, PR_FALSE);
 	} else if (ss->ssl3.hs.hashType == handshake_hash_single) {
 	    ss->ssl3.hs.sha_obj->destroy(ss->ssl3.hs.sha_cx, PR_FALSE);
 	}
-    } 
+    }
 #endif
     if (ss->ssl3.hs.md5) {
 	PK11_DestroyContext(ss->ssl3.hs.md5,PR_TRUE);
     }
     if (ss->ssl3.hs.sha) {
 	PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
     }
     if (ss->ssl3.hs.clientSigAndHash) {
@@ -12909,16 +13234,31 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     /* Destroy the DTLS data */
     if (IS_DTLS(ss)) {
 	dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
 	if (ss->ssl3.hs.recvdFragments.buf) {
 	    PORT_Free(ss->ssl3.hs.recvdFragments.buf);
 	}
     }
 
+    /* Destroy TLS 1.3 handshake shares */
+    tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares);
+
+    /* Destroy TLS 1.3 keys */
+    if (ss->ssl3.hs.xSS)
+        PK11_FreeSymKey(ss->ssl3.hs.xSS);
+    if (ss->ssl3.hs.xES)
+        PK11_FreeSymKey(ss->ssl3.hs.xES);
+    if (ss->ssl3.hs.trafficSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.trafficSecret);
+    if (ss->ssl3.hs.clientFinishedSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.clientFinishedSecret);
+    if (ss->ssl3.hs.serverFinishedSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.serverFinishedSecret);
+
     if (ss->ssl3.dheGroups) {
 	PORT_Free(ss->ssl3.dheGroups);
     }
 
     ss->ssl3.initialized = PR_FALSE;
 
     SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
 }
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -184,23 +184,31 @@ ssl3_ECName2Params(PLArenaPool * arena, 
      */
     params->data[0] = SEC_ASN1_OBJECT_ID;
     params->data[1] = oidData->oid.len;
     memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
 
     return SECSuccess;
 }
 
-static ECName
-params2ecName(SECKEYECParams * params)
+ECName
+ssl3_PubKey2ECName(SECKEYPublicKey *pubKey)
 {
     SECItem oid = { siBuffer, NULL, 0};
     SECOidData *oidData = NULL;
     PRUint32 policyFlags = 0;
     ECName i;
+    SECKEYECParams *params;
+
+    if (pubKey->keyType != ecKey) {
+        PORT_Assert(0);
+        return ec_noName;
+    }
+
+    params = &pubKey->u.ec.DEREncodedParams;
 
     /*
      * params->data needs to contain the ASN encoding of an object ID (OID)
      * representing a named curve. Here, we strip away everything
      * before the actual OID and use the OID to look up a named curve.
      */
     if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName;
     oid.len = params->len - 2;
@@ -360,24 +368,55 @@ ssl3_SendECDHClientKeyExchange(sslSocket
 loser:
     if(pms) PK11_FreeSymKey(pms);
     if(privKey) SECKEY_DestroyPrivateKey(privKey);
     if(pubKey) SECKEY_DestroyPublicKey(pubKey);
     return rv;
 }
 
 
+ECName
+tls13_GroupForECDHEKeyShare(ssl3KeyPair *pair)
+{
+    return ssl3_PubKey2ECName(pair->pubKey);
+}
+
+/* This function returns the size of the key_exchange field in
+ * the KeyShareEntry structure. */
+unsigned int
+tls13_SizeOfECDHEKeyShareKEX(ssl3KeyPair *pair)
+{
+    return 1 + /* Length */
+           pair->pubKey->u.ec.publicValue.len;
+}
+
+/* This function encodes the key_exchange field in
+ * the KeyShareEntry structure. */
+SECStatus
+tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, ssl3KeyPair *pair)
+{
+    const SECItem *publicValue;
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+    publicValue = &pair->pubKey->u.ec.publicValue;
+
+    return ssl3_AppendHandshakeVariable(ss, publicValue->data,
+                                        publicValue->len, 1);
+}
+
 /*
 ** Called from ssl3_HandleClientKeyExchange()
 */
 SECStatus
 ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
-                                     PRUint32 length,
-                                     SECKEYPublicKey *srvrPubKey,
-                                     SECKEYPrivateKey *srvrPrivKey)
+                                 PRUint32 length,
+                                 SECKEYPublicKey *srvrPubKey,
+                                 SECKEYPrivateKey *srvrPrivKey)
 {
     PK11SymKey *      pms;
     SECStatus         rv;
     SECKEYPublicKey   clntPubKey;
     CK_MECHANISM_TYPE   target;
     PRBool isTLS, isTLS12;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
@@ -422,16 +461,106 @@ ssl3_HandleECDHClientKeyExchange(sslSock
     PK11_FreeSymKey(pms);
     if (rv != SECSuccess) {
         SEND_ALERT
         return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
     }
     return SECSuccess;
 }
 
+/*
+** Take an encoded key share and make a public key out of it.
+** returns NULL on error.
+*/
+SECKEYPublicKey *
+tls13_ImportECDHKeyShare(sslSocket *ss, SSL3Opaque *b,
+                         PRUint32 length, ECName curve)
+{
+    PLArenaPool *    arena = NULL;
+    SECKEYPublicKey *peerKey = NULL;
+    SECStatus rv;
+    SECItem ecPoint  = {siBuffer, NULL, 0};
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &ecPoint, 1, &b, &length);
+    if (rv != SECSuccess) {
+        tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE,
+                         illegal_parameter);
+        return NULL;
+    }
+    if (length || !ecPoint.len) {
+        tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE,
+                         illegal_parameter);
+        return NULL;
+    }
+
+    /* Fail if the ec point uses compressed representation */
+    if (ecPoint.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+        tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_EC_POINT_FORM,
+                         illegal_parameter);
+        return NULL;
+    }
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        goto no_memory;
+    }
+
+    peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+    if (peerKey == NULL) {
+        goto no_memory;
+    }
+
+    peerKey->arena = arena;
+    peerKey->keyType = ecKey;
+    /* Set up the encoded params */
+    rv = ssl3_ECName2Params(arena, curve, &peerKey->u.ec.DEREncodedParams);
+    if (rv != SECSuccess) {
+        goto no_memory;
+    }
+
+    /* copy publicValue in peerKey */
+    if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ecPoint) !=
+        SECSuccess) {
+        goto no_memory;
+    }
+    peerKey->pkcs11Slot = NULL;
+    peerKey->pkcs11ID = CK_INVALID_HANDLE;
+
+    return peerKey;
+
+no_memory:      /* no-memory error has already been set. */
+    PORT_FreeArena(arena, PR_FALSE);
+    ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
+    return NULL;
+}
+
+PK11SymKey *
+tls13_ComputeECDHSharedKey(sslSocket* ss,
+                           SECKEYPrivateKey *myPrivKey,
+                           SECKEYPublicKey *peerKey)
+{
+    PK11SymKey* shared;
+
+    /* Determine the PMS */
+    shared = PK11_PubDeriveWithKDF(myPrivKey, peerKey, PR_FALSE, NULL, NULL,
+                                   CKM_ECDH1_DERIVE,
+                                   tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0,
+                                   CKD_NULL, NULL, NULL);
+
+    if (!shared) {
+        ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
+        return NULL;
+    }
+
+    return shared;
+}
+
 ECName
 ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits)
 {
     int    i;
 
     for ( i = 0; bits2curve[i].curve != ec_noName; i++) {
         if (bits2curve[i].bits < requiredECCbits)
             continue;
@@ -452,17 +581,17 @@ ssl3_GetCurveNameForServerSocket(sslSock
     SECKEYPublicKey * svrPublicKey = NULL;
     ECName ec_curve = ec_noName;
     int    signatureKeyStrength = 521;
     int    requiredECCbits = ss->sec.secretKeyBits * 2;
 
     if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
         svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh);
         if (svrPublicKey)
-            ec_curve = params2ecName(&svrPublicKey->u.ec.DEREncodedParams);
+            ec_curve = ssl3_PubKey2ECName(svrPublicKey);
         if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) {
             PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
             return ec_noName;
         }
         signatureKeyStrength = curve2bits[ ec_curve ];
     } else {
         /* RSA is our signing cert */
         int serverKeyStrengthInBits;
@@ -514,17 +643,17 @@ ssl3_ECRegister(void)
     rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs);
     if (rv != SECSuccess) {
         gECDHEKeyPairs[ec_noName].error = PORT_GetError();
     }
     return (PRStatus)rv;
 }
 
 /* Create an ECDHE key pair for a given curve */
-static SECStatus
+SECStatus
 ssl3_CreateECDHEphemeralKeyPair(ECName ec_curve, ssl3KeyPair** keyPair)
 {
     SECKEYPrivateKey *    privKey  = NULL;
     SECKEYPublicKey *     pubKey   = NULL;
     SECKEYECParams        ecParams = { siBuffer, NULL, 0 };
 
     if (ssl3_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) {
         return SECFailure;
@@ -801,17 +930,17 @@ ssl3_SendECDHServerKeyExchange(
     PORT_Assert(ecdhePub != NULL);
     if (!ecdhePub) {
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
     ec_params.len  = sizeof paramBuf;
     ec_params.data = paramBuf;
-    curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams);
+    curve = ssl3_PubKey2ECName(ecdhePub);
     if (curve != ec_noName) {
         ec_params.data[0] = ec_type_named;
         ec_params.data[1] = 0x00;
         ec_params.data[2] = curve;
     } else {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
         goto loser;
     }
@@ -1271,17 +1400,17 @@ ssl3_HandleSupportedPointFormatsXtn(sslS
 /* Extract the TLS curve name for the public key in our EC server cert. */
 ECName ssl3_GetSvrCertCurveName(sslSocket *ss)
 {
     SECKEYPublicKey       *srvPublicKey;
     ECName                ec_curve       = ec_noName;
 
     srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
     if (srvPublicKey) {
-        ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams);
+        ec_curve = ssl3_PubKey2ECName(srvPublicKey);
     }
     return ec_curve;
 }
 
 /* Ensure that the curve in our server cert is one of the ones supported
  * by the remote client, and disable all ECC cipher suites if not.
  */
 SECStatus
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -94,27 +94,33 @@ static SECStatus ssl3_ClientHandleSigned
                                                          PRUint16 ex_type,
                                                          SECItem *data);
 static PRInt32 ssl3_ServerSendSignedCertTimestampXtn(sslSocket * ss,
                                                      PRBool append,
                                                      PRUint32 maxBytes);
 static SECStatus ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss,
                                                          PRUint16 ex_type,
                                                          SECItem *data);
-
 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);
-
+static SECStatus tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append,
+                                             PRUint32 maxBytes);
+static SECStatus tls13_ClientHandleKeyShareXtn(sslSocket *ss,
+                                               PRUint16 ex_type,
+                                               SECItem *data);
+static SECStatus tls13_ServerHandleKeyShareXtn(sslSocket *ss,
+                                               PRUint16 ex_type,
+                                               SECItem *data);
 
 /*
  * Write bytes.  Using this function means the SECItem structure
  * cannot be freed.  The caller is expected to call this function
  * on a shallow copy of the structure.
  */
 static SECStatus
 ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
@@ -272,32 +278,34 @@ static const ssl3HelloExtensionHandler c
     { ssl_next_proto_nego_xtn,    &ssl3_ServerHandleNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
     { ssl_use_srtp_xtn,           &ssl3_ServerHandleUseSRTPXtn },
     { 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 },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
+    { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { -1, NULL }
 };
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_server_name_xtn,        &ssl3_HandleServerNameXtn },
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
     { ssl_session_ticket_xtn,     &ssl3_ClientHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { ssl_next_proto_nego_xtn,    &ssl3_ClientHandleNextProtoNegoXtn },
     { 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 },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
+    { ssl_tls13_key_share_xtn,    &tls13_ClientHandleKeyShareXtn },
     { -1, NULL }
 };
 
 static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { -1, NULL }
 };
 
@@ -319,16 +327,17 @@ ssl3HelloExtensionSender clientHelloSend
     { ssl_next_proto_nego_xtn,    &ssl3_ClientSendNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
     { ssl_use_srtp_xtn,           &ssl3_ClientSendUseSRTPXtn },
     { 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},
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
+    { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
     /* any extra entries will appear as { 0, NULL }    */
 };
 
 static const
 ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = {
     { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }
     /* any extra entries will appear as { 0, NULL }    */
 };
@@ -1924,28 +1933,44 @@ ssl3_ParseEncryptedSessionTicket(sslSock
     return SECSuccess;
 }
 
 /* go through hello extensions in buffer "b".
  * For each one, find the extension handler in the table, and
  * if present, invoke that handler.
  * Servers ignore any extensions with unknown extension types.
  * Clients reject any extensions with unadvertised extension types.
+ * In TLS >= 1.3, the client checks that extensions appear in the
+ * right phase.
  */
 SECStatus
-ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length)
+ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length,
+                           SSL3HandshakeType handshakeMessage)
 {
     const ssl3HelloExtensionHandler * handlers;
-
-    if (ss->sec.isServer) {
-        handlers = clientHelloHandlers;
-    } else if (ss->version > SSL_LIBRARY_VERSION_3_0) {
-        handlers = serverHelloHandlersTLS;
-    } else {
-        handlers = serverHelloHandlersSSL3;
+    PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
+
+    switch (handshakeMessage) {
+        case client_hello:
+            handlers = clientHelloHandlers;
+            break;
+        case encrypted_extensions:
+            PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+            /* fall through */
+        case server_hello:
+            if (ss->version > SSL_LIBRARY_VERSION_3_0) {
+                handlers = serverHelloHandlersTLS;
+            } else {
+                handlers = serverHelloHandlersSSL3;
+            }
+            break;
+        default:
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            PORT_Assert(0);
+            return SECFailure;
     }
 
     while (*length) {
         const ssl3HelloExtensionHandler * handler;
         SECStatus rv;
         PRInt32   extension_type;
         SECItem   extension_data;
 
@@ -1955,30 +1980,41 @@ ssl3_HandleHelloExtensions(sslSocket *ss
             return SECFailure;   /* alert already sent */
 
         /* get the data for this extension, so we can pass it or skip it. */
         rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length);
         if (rv != SECSuccess)
             return rv; /* alert already sent */
 
         /* Check whether the server sent an extension which was not advertised
-         * in the ClientHello.
-         */
+         * in the ClientHello */
         if (!ss->sec.isServer &&
-            !ssl3_ClientExtensionAdvertised(ss, extension_type)) {
+            !ssl3_ClientExtensionAdvertised(ss,extension_type)) {
             (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
             return SECFailure;
         }
 
         /* Check whether an extension has been sent multiple times. */
         if (ssl3_ExtensionNegotiated(ss, extension_type)) {
             (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
             return SECFailure;
         }
 
+        /* Check that this is a legal extension in TLS 1.3 */
+        if (isTLS13 && !tls13_ExtensionAllowed(extension_type,
+                                               handshakeMessage)) {
+            if (handshakeMessage == client_hello) {
+                /* Skip extensions not used in TLS 1.3 */
+                continue;
+            }
+            tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
+                             unsupported_extension);
+            return SECFailure;
+        }
+
         /* find extension_type in table of Hello Extension Handlers */
         for (handler = handlers; handler->ex_type >= 0; handler++) {
             /* if found, call this handler */
             if (handler->ex_type == extension_type) {
                 rv = (*handler->ex_handler)(ss, (PRUint16)extension_type,
                                                         &extension_data);
                 if (rv != SECSuccess) {
                     if (!ss->ssl3.fatalAlertSent) {
@@ -1995,17 +2031,28 @@ ssl3_HandleHelloExtensions(sslSocket *ss
 
 /* Add a callback function to the table of senders of server hello extensions.
  */
 SECStatus
 ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
                                         ssl3HelloExtensionSenderFunc cb)
 {
     int i;
-    ssl3HelloExtensionSender *sender = &ss->xtnData.serverSenders[0];
+    ssl3HelloExtensionSender *sender;
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        sender = &ss->xtnData.serverHelloSenders[0];
+    } else {
+        if (tls13_ExtensionAllowed(ex_type, server_hello)) {
+            PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions));
+            sender = &ss->xtnData.serverHelloSenders[0];
+        } else {
+            PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions));
+            sender = &ss->xtnData.encryptedExtensionsSenders[0];
+        }
+    }
 
     for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
         if (!sender->ex_sender) {
             sender->ex_type   = ex_type;
             sender->ex_sender = cb;
             return SECSuccess;
         }
         /* detect duplicate senders */
@@ -2702,17 +2749,16 @@ ssl3_HandleExtendedMasterSecretXtn(sslSo
 
     if (ss->sec.isServer) {
         return ssl3_RegisterServerHelloExtensionSender(
             ss, ex_type, ssl3_SendExtendedMasterSecretXtn);
     }
     return SECSuccess;
 }
 
-
 /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp
  * extension for TLS ClientHellos. */
 static PRInt32
 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append,
                                       PRUint32 maxBytes)
 {
     PRInt32 extension_length = 2 /* extension_type */ +
                                2 /* length(extension_data) */;
@@ -2823,8 +2869,272 @@ static SECStatus
 ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type,
                                         SECItem *data)
 {
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
     PORT_Assert(ss->sec.isServer);
     return ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
         ssl3_ServerSendSignedCertTimestampXtn);
 }
+
+/*
+ *     [draft-ietf-tls-tls13-11] Section 6.3.2.3.
+ *
+ *     struct {
+ *         NamedGroup group;
+ *         opaque key_exchange<1..2^16-1>;
+ *     } KeyShareEntry;
+ *
+ *     struct {
+ *         select (role) {
+ *             case client:
+ *                 KeyShareEntry client_shares<4..2^16-1>;
+ *
+ *             case server:
+ *                 KeyShareEntry server_share;
+ *         }
+ *     } KeyShare;
+ */
+static SECStatus
+tls13_SizeOfKeyShareEntry(ssl3KeyPair *pair)
+{
+    return 2 + 2 + tls13_SizeOfECDHEKeyShareKEX(pair);
+}
+
+static SECStatus
+tls13_EncodeKeyShareEntry(sslSocket *ss, ssl3KeyPair *pair)
+{
+    SECStatus rv;
+
+    /* This currently only works for ECC keys */
+    PORT_Assert(pair->pubKey->keyType == ecKey);
+    if (pair->pubKey->keyType != ecKey) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    rv = ssl3_AppendHandshakeNumber(ss, tls13_GroupForECDHEKeyShare(pair), 2);
+    if (rv != SECSuccess)
+        return rv;
+
+    rv = ssl3_AppendHandshakeNumber(ss, tls13_SizeOfECDHEKeyShareKEX(pair), 2);
+    if (rv != SECSuccess)
+        return rv;
+
+    rv = tls13_EncodeECDHEKeyShareKEX(ss, pair);
+    if (rv != SECSuccess)
+        return rv;
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_ClientSendKeyShareXtn(sslSocket * ss, PRBool append,
+                            PRUint32 maxBytes)
+{
+    SECStatus rv;
+    PRUint32 entry_length;
+    PRUint32 extension_length;
+
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        return 0;
+    }
+
+    /* Optimistically try to send an ECDHE key using the
+     * preexisting key (in future will be keys) */
+    SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn",
+                SSL_GETPID(), ss->fd));
+
+    entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair);
+    /* Type + length + vector_length + entry */
+    extension_length = 2 + 2 + 2 + entry_length;
+
+    if (maxBytes < extension_length) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
+        if (rv != SECSuccess)
+            goto loser;
+        rv = ssl3_AppendHandshakeNumber(ss, entry_length + 2, 2); /* Extension length */
+        if (rv != SECSuccess)
+            goto loser;
+        rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2);  /* Vector length */
+        if (rv != SECSuccess)
+            goto loser;
+        rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair);
+        if (rv != SECSuccess)
+            goto loser;
+
+        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+                ssl_tls13_key_share_xtn;
+    }
+
+    return extension_length;
+
+loser:
+    return -1;
+}
+
+static SECStatus
+tls13_HandleKeyShareEntry(sslSocket *ss, SECItem *data)
+{
+    SECStatus rv;
+    PRInt32 group;
+    TLS13KeyShareEntry* ks = NULL;
+    SECItem share = { siBuffer, NULL, 0 };
+
+    group = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    if (group < 0) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
+        goto loser;
+    }
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &share, 2, &data->data,
+                                       &data->len);
+    if (rv != SECSuccess)
+        goto loser;
+
+    ks = PORT_ZNew(TLS13KeyShareEntry);
+    if (!ks)
+        goto loser;
+    ks->group = group;
+
+    rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share);
+    if (rv != SECSuccess)
+        goto loser;
+
+    PR_APPEND_LINK(&ks->link, &ss->ssl3.hs.remoteKeyShares);
+    return SECSuccess;
+
+loser:
+    if (ks)
+        tls13_DestroyKeyShareEntry(ks);
+    return SECFailure;
+}
+
+/* Handle an incoming KeyShare extension at the client and copy to
+ * |ss->ssl3.hs.remoteKeyShares| for future use. The key
+ * share is processed in tls13_HandleServerKeyShare(). */
+static SECStatus
+tls13_ClientHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+
+    PORT_Assert(!ss->sec.isServer);
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        /* This can't happen because the extension processing
+         * code filters out TLS 1.3 extensions when not in
+         * TLS 1.3 mode. */
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
+		SSL_GETPID(), ss->fd));
+
+    rv = tls13_HandleKeyShareEntry(ss, data);
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
+        return SECFailure;
+    }
+
+    if (data->len) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* Handle an incoming KeyShare extension at the server and copy to
+ * |ss->ssl3.hs.remoteKeyShares| for future use. The key
+ * share is processed in tls13_HandleClientKeyShare(). */
+static SECStatus
+tls13_ServerHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+    PRInt32 length;
+
+    PORT_Assert(ss->sec.isServer);
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        return SECSuccess;
+    }
+
+    SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
+		SSL_GETPID(), ss->fd));
+
+    /* Redundant length because of TLS encoding (this vector consumes
+     * the entire extension.) */
+    length = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data,
+                                         &data->len);
+    if (length < 0)
+        goto loser;
+    if (length != data->len) {
+        /* Check for consistency */
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
+        goto loser;
+    }
+
+    while (data->len) {
+        rv = tls13_HandleKeyShareEntry(ss, data);
+        if (rv != SECSuccess)
+            goto loser;
+    }
+    return SECSuccess;
+
+loser:
+    tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares);
+    return SECFailure;
+}
+
+SECStatus
+tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append,
+                            PRUint32 maxBytes)
+{
+    PRUint32 extension_length;
+    PRUint32 entry_length;
+    SECStatus rv;
+
+    switch (ss->ssl3.hs.kea_def->exchKeyType) {
+#ifndef NSS_DISABLE_ECC
+    case ssl_kea_ecdh:
+        PORT_Assert(ss->ephemeralECDHKeyPair);
+        break;
+#endif
+    default:
+        /* got an unknown or unsupported Key Exchange Algorithm.
+         * Can't happen because tls13_HandleClientKeyShare
+         * enforces that we are ssl_kea_ecdh. */
+        PORT_Assert(0);
+        tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_KEYALG, internal_error);
+        return SECFailure;
+    }
+
+    entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair);
+    extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */
+    if (maxBytes < extension_length) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
+        if (rv != SECSuccess)
+            goto loser;
+
+        rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2);
+        if (rv != SECSuccess)
+            goto loser;
+
+        rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair);
+        if (rv != SECSuccess)
+            goto loser;
+    }
+
+    return extension_length;
+
+loser:
+    return -1;
+}
+
--- a/lib/ssl/ssl3prot.h
+++ b/lib/ssl/ssl3prot.h
@@ -12,17 +12,17 @@
 typedef PRUint8 SSL3Opaque;
 
 typedef PRUint16 SSL3ProtocolVersion;
 /* version numbers are defined in sslproto.h */
 
 /* The TLS 1.3 draft version. Used to avoid negotiating
  * between incompatible pre-standard TLS 1.3 drafts.
  * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
-#define TLS_1_3_DRAFT_VERSION  3
+#define TLS_1_3_DRAFT_VERSION  11
 
 typedef PRUint16 ssl3CipherSuite;
 /* The cipher suites are defined in sslproto.h */
 
 #define MAX_CERT_TYPES                  10
 #define MAX_COMPRESSION_METHODS         10
 #define MAX_MAC_LENGTH                  64
 #define MAX_PADDING_LENGTH              64
@@ -103,16 +103,17 @@ typedef enum {
     protocol_version        = 70,
     insufficient_security   = 71,
     internal_error          = 80,
     inappropriate_fallback  = 86,	/* could also be sent for SSLv3 */
     user_canceled           = 90,
     no_renegotiation        = 100,
 
 /* Alerts for client hello extensions */
+    missing_extension               = 109,
     unsupported_extension           = 110,
     certificate_unobtainable        = 111,
     unrecognized_name               = 112,
     bad_certificate_status_response = 113,
     bad_certificate_hash_value      = 114,
     no_application_protocol         = 120
 
 } SSL3AlertDescription;
@@ -123,16 +124,18 @@ typedef struct {
 } SSL3Alert;
 
 typedef enum {
     hello_request       = 0,
     client_hello        = 1,
     server_hello        = 2,
     hello_verify_request = 3,
     new_session_ticket  = 4,
+    hello_retry_request = 6,
+    encrypted_extensions = 8,
     certificate         = 11,
     server_key_exchange = 12,
     certificate_request = 13,
     server_hello_done   = 14,
     certificate_verify  = 15,
     client_key_exchange = 16,
     finished            = 20,
     certificate_status  = 22,
--- a/lib/ssl/sslerr.h
+++ b/lib/ssl/sslerr.h
@@ -203,13 +203,24 @@ SSL_ERROR_WEAK_SERVER_CERT_KEY          
 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_RX_MALFORMED_KEY_SHARE = (SSL_ERROR_BASE + 138),
+SSL_ERROR_MISSING_KEY_SHARE = (SSL_ERROR_BASE + 139),
+SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE = (SSL_ERROR_BASE + 140),
+SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE = (SSL_ERROR_BASE + 141),
+
+SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 142),
+SSL_ERROR_MISSING_EXTENSION_ALERT = (SSL_ERROR_BASE + 143),
+
+SSL_ERROR_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 144),
+SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 145),
+
 SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 #endif /* __SSL_ERR_H_ */
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -785,28 +785,32 @@ typedef enum {
     wait_finished,
     wait_server_hello, 
     wait_certificate_status,
     wait_server_cert, 
     wait_server_key,
     wait_cert_request, 
     wait_hello_done,
     wait_new_session_ticket,
-    idle_handshake
+    wait_encrypted_extensions,
+    idle_handshake,
+    wait_invalid /* Invalid value. There is no handshake message "invalid". */
 } SSL3WaitState;
 
 /*
  * TLS extension related constants and data structures.
  */
 typedef struct TLSExtensionDataStr       TLSExtensionData;
 typedef struct SessionTicketDataStr      SessionTicketData;
 
 struct TLSExtensionDataStr {
     /* registered callbacks that send server hello extensions */
-    ssl3HelloExtensionSender serverSenders[SSL_MAX_EXTENSIONS];
+    ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS];
+    ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
+
     /* Keep track of the extensions that are negotiated. */
     PRUint16 numAdvertised;
     PRUint16 numNegotiated;
     PRUint16 advertised[SSL_MAX_EXTENSIONS];
     PRUint16 negotiated[SSL_MAX_EXTENSIONS];
 
     /* SessionTicket Extension related data. */
     PRBool ticketTimestampVerified;
@@ -841,30 +845,36 @@ typedef SECStatus (*sslRestartTarget)(ss
 typedef struct DTLSQueuedMessageStr {
     PRCList link;         /* The linked list link */
     DTLSEpoch epoch;      /* The epoch to use */
     SSL3ContentType type; /* The message type */
     unsigned char *data;  /* The data */
     PRUint16 len;         /* The data length */
 } DTLSQueuedMessage;
 
+typedef struct TLS13KeyShareEntryStr {
+    PRCList link;      /* The linked list link */
+    PRUint16 group;    /* The group for the entry */
+    SECItem key_exchange;     /* The share itself */
+} TLS13KeyShareEntry;
+
 typedef enum {
     handshake_hash_unknown = 0,
     handshake_hash_combo = 1,  /* The MD5/SHA-1 combination */
     handshake_hash_single = 2  /* A single hash */
 } SSL3HandshakeHashType;
 
 /*
 ** This is the "hs" member of the "ssl3" struct.
 ** This entire struct is protected by ssl3HandshakeLock
 */
 typedef struct SSL3HandshakeStateStr {
     SSL3Random            server_random;
     SSL3Random            client_random;
-    SSL3WaitState         ws;
+    SSL3WaitState         ws;  /* May also contain SSL3WaitState | 0x80 for TLS 1.3 */
 
     /* This group of members is used for handshake running hashes. */
     SSL3HandshakeHashType hashType;
     sslBuffer             messages;    /* Accumulated handshake messages */
 #ifndef NO_PKCS11_BYPASS
     /* Bypass mode:
      * SSL 3.0 - TLS 1.1 use both |md5_cx| and |sha_cx|. |md5_cx| is used for
      * MD5 and |sha_cx| for SHA-1.
@@ -957,16 +967,29 @@ const ssl3CipherSuiteDef *suite_def;
 					    * in progress. */
     unsigned char         cookie[32];      /* The cookie */
     unsigned char         cookieLen;       /* The length of the cookie */
     PRIntervalTime        rtTimerStarted;  /* When the timer was started */
     DTLSTimerCb           rtTimerCb;       /* The function to call on expiry */
     PRUint32              rtTimeoutMs;     /* The length of the current timeout
 					    * used for backoff (in ms) */
     PRUint32              rtRetries;       /* The retry counter */
+
+    /* This group of values is used for TLS 1.3 and above */
+    PRCList               remoteKeyShares; /* The other side's public keys */
+    PK11SymKey            *xSS;            /* Extracted static secret */
+    PK11SymKey            *xES;            /* Extracted ephemeral secret */
+    PK11SymKey            *trafficSecret;  /* The source key to use to generate
+                                            * traffic keys */
+    PK11SymKey            *clientFinishedSecret; /* Used for client Finished */
+    PK11SymKey            *serverFinishedSecret; /* Used for server Finished */
+    unsigned char         certReqContext[255]; /* Ties CertificateRequest
+                                                * to Certificate */
+    PRUint8               certReqContextLen;   /* Length of the context
+                                                * cannot be greater than 255. */
 } SSL3HandshakeState;
 
 
 
 /*
 ** This is the "ssl3" struct, as in "ss->ssl3".
 ** note:
 ** usually,   crSpec == cwSpec and prSpec == pwSpec.  
@@ -1504,16 +1527,17 @@ extern SECStatus
 ssl3_CompressMACEncryptRecord(ssl3CipherSpec *   cwSpec,
 		              PRBool             isServer,
 			      PRBool             isDTLS,
 			      PRBool             capRecordVersion,
                               SSL3ContentType    type,
 		              const SSL3Opaque * pIn,
 		              PRUint32           contentLen,
 		              sslBuffer *        wrBuf);
+
 extern PRInt32   ssl3_SendRecord(sslSocket *ss, DTLSEpoch epoch,
 				 SSL3ContentType type,
                                  const SSL3Opaque* pIn, PRInt32 nIn,
                                  PRInt32 flags);
 
 #ifdef NSS_ENABLE_SSL_ZLIB
 /*
  * The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a
@@ -1717,17 +1741,20 @@ typedef enum { ec_noName     = 0,
 	       ec_secp256r1  = 23, 
 	       ec_secp384r1  = 24,
 	       ec_secp521r1  = 25,
 	       ec_pastLastName
 } ECName;
 
 extern SECStatus ssl3_ECName2Params(PLArenaPool *arena, ECName curve,
 				   SECKEYECParams *params);
+ECName ssl3_PubKey2ECName(SECKEYPublicKey *pubKey);
+
 ECName	ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
+ECName  ssl3_GetCurveNameForServerSocket(sslSocket *ss);
 
 
 #endif /* NSS_DISABLE_ECC */
 
 extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
 extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
 extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
 extern SECStatus ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled);
@@ -1767,16 +1794,21 @@ extern SECStatus ssl3_SendECDHClientKeyE
 extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, 
 					SSL3Opaque *b, PRUint32 length);
 extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, 
 				     SSL3Opaque *b, PRUint32 length,
                                      SECKEYPublicKey *srvrPubKey,
                                      SECKEYPrivateKey *srvrPrivKey);
 extern SECStatus ssl3_SendECDHServerKeyExchange(
     sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash);
+SECKEYPublicKey *tls13_ImportECDHKeyShare(
+    sslSocket *ss, SSL3Opaque *b, PRUint32 length, ECName curve);
+ECName tls13_GroupForECDHEKeyShare(ssl3KeyPair *pair);
+unsigned int tls13_SizeOfECDHEKeyShareKEX(ssl3KeyPair *pair);
+SECStatus tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, ssl3KeyPair *pair);
 #endif
 
 extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
 				PRUint8 * hashBuf,
 				unsigned int bufLen, SSL3Hashes *hashes, 
 				PRBool bypassPKCS11);
 extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName);
 extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms);
@@ -1850,17 +1882,18 @@ extern SECStatus ssl_ConfigSecureServer(
 extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss,
 			PRBool append, PRUint32 maxBytes);
 extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss,
 			PRBool append, PRUint32 maxBytes);
 #endif
 
 /* call the registered extension handlers. */
 extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, 
-			SSL3Opaque **b, PRUint32 *length);
+                                            SSL3Opaque **b, PRUint32 *length,
+                                            SSL3HandshakeType handshakeMessage);
 
 /* Hello Extension related routines. */
 extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type);
 extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
 			/*in/out*/ NewSessionTicket *session_ticket);
 extern SECStatus ssl3_SendNewSessionTicket(sslSocket *ss);
 extern PRBool ssl_GetSessionTicketKeys(unsigned char *keyName,
 			unsigned char *encKey, unsigned char *macKey);
@@ -1948,23 +1981,68 @@ SECStatus ssl3_DisableNonDTLSSuites(sslS
 extern SECStatus dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb);
 extern SECStatus dtls_RestartTimer(sslSocket *ss, PRBool backoff,
 				   DTLSTimerCb cb);
 extern void dtls_CheckTimer(sslSocket *ss);
 extern void dtls_CancelTimer(sslSocket *ss);
 extern void dtls_FinishedTimerCb(sslSocket *ss);
 extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
 extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
-extern int dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
+extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq);
 extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
 extern void dtls_RehandshakeCleanup(sslSocket *ss);
 extern SSL3ProtocolVersion
 dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
 extern SSL3ProtocolVersion
 dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
+extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec,
+                              const SSL3Ciphertext *cText, PRUint64 *seqNum);
+
+
+CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg);
+SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss);
+SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
+SECStatus ssl3_SendCertificate(sslSocket *ss);
+SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss,
+                                         SSL3Opaque *b, PRUint32 length);
+SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
+SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
+SECStatus ssl3_CompleteHandleCertificateStatus(sslSocket *ss, SSL3Opaque *b,
+                                                PRUint32 length);
+SECStatus ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
+                                               unsigned maxLen, PRUint32 *len);
+void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp,
+                                   int *nnamesp);
+SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss,SSL3Opaque **b,
+                                          PRUint32 *length, PLArenaPool *arena,
+                                          CERTDistNames *ca_list);
+SECStatus ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
+                                                SECItem *algorithms,
+                                                CERTDistNames *ca_list);
+SECStatus ssl3_SendCertificateVerify(sslSocket *ss,
+                                     SECKEYPrivateKey *privKey);
+SECStatus ssl3_SendServerHello(sslSocket *ss);
+SECOidTag ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc);
+SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
+                                      ssl3CipherSpec *spec,
+                                      SSL3Hashes *hashes,
+                                      PRUint32 sender);
+void ssl3_BumpSequenceNumber(SSL3SequenceNumber *num);
+SECStatus tls13_ServerSendKeyShareXtn(sslSocket * ss, PRBool append,
+                                      PRUint32 maxBytes);
+#ifndef NSS_DISABLE_ECC
+SECStatus ssl3_CreateECDHEphemeralKeyPair(ECName ec_curve,
+                                          ssl3KeyPair** keyPair);
+PK11SymKey *tls13_ComputeECDHSharedKey(sslSocket* ss,
+                                       SECKEYPrivateKey *myPrivKey,
+                                       SECKEYPublicKey *peerKey);
+#endif
+
+/* Pull in TLS 1.3 functions */
+#include "tls13con.h"
 
 /********************** misc calls *********************/
 
 #ifdef DEBUG
 extern void ssl3_CheckCipherSuiteOrderConsistency();
 #endif
 
 extern int ssl_MapLowLevelError(int hiLevelError);
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -62,17 +62,20 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLCh
 	    ssl_ReleaseSpecReadLock(ss);
 	    inf.compressionMethodName =
 		ssl_GetCompressionMethodName(inf.compressionMethod);
 	}
 	if (sid) {
 	    inf.creationTime   = sid->creationTime;
 	    inf.lastAccessTime = sid->lastAccessTime;
 	    inf.expirationTime = sid->expirationTime;
-            inf.extendedMasterSecretUsed = sid->u.ssl3.keys.extendedMasterSecretUsed;
+            inf.extendedMasterSecretUsed =
+                    (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ||
+                     sid->u.ssl3.keys.extendedMasterSecretUsed) ?
+                    PR_TRUE: PR_FALSE;
 
 	    if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
 	        inf.sessionIDLength = SSL2_SESSIONID_BYTES;
 		memcpy(inf.sessionID, sid->u.ssl2.sessionID, 
 		       SSL2_SESSIONID_BYTES);
 	    } else {
 		unsigned int sidLen = sid->u.ssl3.sessionIDLength;
 	        sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -3470,16 +3470,17 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
         ss->badCertArg         = NULL;
         ss->pkcs11PinArg       = NULL;
         ss->ephemeralECDHKeyPair = NULL;
 
         ssl_ChooseOps(ss);
         ssl2_InitSocketPolicy(ss);
         ssl3_InitSocketPolicy(ss);
         PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
+        PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
 
         if (makeLocks) {
             status = ssl_MakeLocks(ss);
             if (status != SECSuccess)
                 goto loser;
         }
         status = ssl_CreateSecurityInfo(ss);
         if (status != SECSuccess)
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -234,22 +234,23 @@ typedef enum {
     ssl_signature_algorithms_xtn     = 13,
     ssl_use_srtp_xtn                 = 14,
     ssl_app_layer_protocol_xtn       = 16,
     /* signed_certificate_timestamp extension, RFC 6962 */
     ssl_signed_cert_timestamp_xtn    = 18,
     ssl_padding_xtn                  = 21,
     ssl_extended_master_secret_xtn   = 23,
     ssl_session_ticket_xtn           = 35,
+    ssl_tls13_key_share_xtn          = 40,      /* unofficial TODO(ekr) */
     ssl_next_proto_nego_xtn          = 13172,
     ssl_renegotiation_info_xtn       = 0xff01,
     ssl_tls13_draft_version_xtn      = 0xff02   /* experimental number */
 } SSLExtensionType;
 
-#define SSL_MAX_EXTENSIONS             13 /* doesn't include ssl_padding_xtn. */
+#define SSL_MAX_EXTENSIONS             14 /* doesn't include ssl_padding_xtn. */
 
 typedef enum {
     ssl_dhe_group_none = 0,
     ssl_ff_dhe_2048_group = 1,
     ssl_ff_dhe_3072_group = 2,
     ssl_ff_dhe_4096_group = 3,
     ssl_ff_dhe_6144_group = 4,
     ssl_ff_dhe_8192_group = 5,
new file mode 100644
--- /dev/null
+++ b/lib/ssl/tls13con.c
@@ -0,0 +1,2046 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * TLS 1.3 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/. */
+
+#include "stdarg.h"
+#include "cert.h"
+#include "ssl.h"
+#include "keyhi.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "sslerr.h"
+#include "tls13hkdf.h"
+#include "tls13con.h"
+
+typedef enum {
+    TrafficKeyEarlyData,
+    TrafficKeyHandshake,
+    TrafficKeyApplicationData
+} TrafficKeyType;
+
+typedef enum {
+    InstallCipherSpecRead,
+    InstallCipherSpecWrite,
+    InstallCipherSpecBoth
+} InstallCipherSpecDirection;
+
+#define MAX_FINISHED_SIZE 64
+
+static SECStatus tls13_InstallCipherSpec(
+    sslSocket *ss, InstallCipherSpecDirection direction);
+static SECStatus tls13_InitCipherSpec(
+    sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install);
+static SECStatus tls13_AESGCM(
+    ssl3KeyMaterial *keys,
+    PRBool doDecrypt,
+    unsigned char *out, int *outlen, int maxout,
+    const unsigned char *in, int inlen,
+    const unsigned char *additionalData, int additionalDataLen);
+static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
+static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b,
+                                                 PRUint32 length);
+static SECStatus tls13_HandleCertificate(
+    sslSocket *ss, SSL3Opaque *b, PRUint32 length);
+static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b,
+                                                PRUint32 length);
+static SECStatus tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b,
+                                               PRUint32 length);
+static SECStatus tls13_HandleCertificateVerify(
+    sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+    SSL3Hashes *hashes);
+static SECStatus tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey* key,
+                                            SharedSecretType keyType);
+static SECStatus tls13_SendFinished(sslSocket *ss);
+static SECStatus tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+                                      const SSL3Hashes *hashes);
+static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b,
+                                              PRUint32 length);
+static SECStatus tls13_ComputeSecrets1(sslSocket *ss);
+static SECStatus tls13_ComputeFinished(
+    sslSocket *ss, const SSL3Hashes *hashes,
+    PRBool sending,
+    PRUint8 *output, unsigned int *outputLen,
+    unsigned int maxOutputLen);
+static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
+static SECStatus tls13_FinishHandshake(sslSocket *ss);
+
+const char kHkdfLabelExpandedSs[] = "expanded static secret";
+const char kHkdfLabelExpandedEs[] = "expanded ephemeral secret";
+const char kHkdfLabelMasterSecret[] = "master secret";
+const char kHkdfLabelTrafficSecret[] = "traffic secret";
+const char kHkdfLabelClientFinishedSecret[] = "client finished";
+const char kHkdfLabelServerFinishedSecret[] = "server finished";
+const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret";
+const char kHkdfLabelExporterMasterSecret[] = "exporter master secret";
+const char kHkdfPhaseEarlyHandshakeDataKeys[] = "early handshake key expansion";
+const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data key expansion";
+const char kHkdfPhaseHandshakeKeys[] = "handshake key expansion";
+const char kHkdfPhaseApplicationDataKeys[] = "application data key expansion";
+const char kHkdfPurposeClientWriteKey[] = "client write key";
+const char kHkdfPurposeServerWriteKey[] = "server write key";
+const char kHkdfPurposeClientWriteIv[] = "client write iv";
+const char kHkdfPurposeServerWriteIv[] = "server write iv";
+const char kClientFinishedLabel[] = "client finished";
+const char kServerFinishedLabel[] = "server finished";
+
+const SSL3ProtocolVersion kRecordVersion = 0x0301U;
+
+#define FATAL_ERROR(ss, prError, desc) do { \
+    SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
+                SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
+    tls13_FatalError(ss, prError, desc); \
+} while(0)
+
+#define UNIMPLEMENTED() do { \
+    SSL_TRC(3, ("%d: TLS13[%d]: unimplemented feature in %s (%s:%d)", \
+                SSL_GETPID(), ss->fd, __func__, __FILE__, __LINE__)); \
+    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \
+    PORT_Assert(0); \
+} while(0)
+
+void
+tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc)
+{
+    PORT_Assert(desc != internal_error);  /* These should never happen */
+    (void)SSL3_SendAlert(ss, alert_fatal, desc);
+    PORT_SetError(prError);
+}
+
+#define STATE_CASE(a) case a: return #a
+static char *
+tls13_HandshakeState(SSL3WaitState st)
+{
+    switch(st) {
+        STATE_CASE(wait_client_hello);
+        STATE_CASE(wait_client_cert);
+        STATE_CASE(wait_cert_verify);
+        STATE_CASE(wait_finished);
+        STATE_CASE(wait_server_hello);
+        STATE_CASE(wait_certificate_status);
+        STATE_CASE(wait_server_cert);
+        STATE_CASE(wait_cert_request);
+        STATE_CASE(wait_encrypted_extensions);
+        STATE_CASE(idle_handshake);
+        default:
+            break;
+    }
+    PORT_Assert(0);
+    return "unknown";
+}
+
+#define TLS13_WAIT_STATE_MASK 0x80
+
+#define TLS13_BASE_WAIT_STATE(ws) (ws & ~TLS13_WAIT_STATE_MASK)
+/* We don't mask idle_handshake because other parts of the code use it*/
+#define TLS13_WAIT_STATE(ws) (ws == idle_handshake ? ws :\
+                              ws | TLS13_WAIT_STATE_MASK)
+#define TLS13_CHECK_HS_STATE(ss, err, ...) \
+    tls13_CheckHsState(ss, err, #err, __func__, __FILE__, __LINE__, \
+                       __VA_ARGS__,                                 \
+                       wait_invalid)
+void
+tls13_SetHsState(sslSocket *ss, SSL3WaitState ws,
+                 const char *func, const char *file, int line)
+{
+    /* Compute the new state name here because this asserts
+     * validity as a side effect, whether we are logging or not. */
+    const char *new_state_name = tls13_HandshakeState(ws);
+
+    SSL_TRC(3, ("%d: TLS13[%d]: state change from %s->%s in %s (%s:%d)",
+                SSL_GETPID(), ss->fd,
+                tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
+                new_state_name,
+                func, file, line));
+
+    ss->ssl3.hs.ws = TLS13_WAIT_STATE(ws);
+}
+
+static PRBool
+tls13_InHsStateV(sslSocket *ss, va_list ap)
+{
+    SSL3WaitState ws;
+
+    while ((ws = va_arg(ap, SSL3WaitState)) != wait_invalid ) {
+        if (ws == TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)) {
+            return PR_TRUE;
+        }
+    }
+    return PR_FALSE;
+}
+
+PRBool
+tls13_InHsState(sslSocket *ss, ...)
+{
+    PRBool found;
+    va_list ap;
+
+    va_start(ap, ss);
+    found = tls13_InHsStateV(ss, ap);
+    va_end(ap);
+
+    return found;
+}
+
+static SECStatus
+tls13_CheckHsState(sslSocket *ss, int err, const char *error_name,
+                   const char *func, const char *file, int line,
+                   ...)
+{
+    va_list ap;
+    va_start(ap, line);
+    if (tls13_InHsStateV(ss, ap)) {
+        va_end(ap);
+        return SECSuccess;
+    }
+    va_end(ap);
+
+    SSL_TRC(3, ("%d: TLS13[%d]: error %s state is (%s) at %s (%s:%d)",
+                SSL_GETPID(), ss->fd,
+                error_name,
+                tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
+                func, file, line));
+    tls13_FatalError(ss, err, unexpected_message);
+    return SECFailure;
+}
+
+SSLHashType
+tls13_GetHash(sslSocket *ss)
+{
+    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
+    return ssl_hash_sha256;
+}
+
+CK_MECHANISM_TYPE
+tls13_GetHkdfMechanism(sslSocket *ss)
+{
+    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
+    return CKM_NSS_HKDF_SHA256;
+}
+
+static CK_MECHANISM_TYPE
+tls13_GetHmacMechanism(sslSocket *ss)
+{
+    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
+    return CKM_SHA256_HMAC;
+}
+
+/*
+ * Called from ssl3_SendClientHello
+ */
+SECStatus
+tls13_SetupClientHello(sslSocket *ss)
+{
+    SECStatus rv;
+    /* TODO(ekr@rtfm.com): Handle multiple curves here. */
+    ECName curves_to_try[] = { ec_secp256r1 };
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+    PORT_Assert(!ss->ephemeralECDHKeyPair);
+
+    rv = ssl3_CreateECDHEphemeralKeyPair(curves_to_try[0],
+                                         &ss->ephemeralECDHKeyPair);
+    if (rv != SECSuccess)
+        return rv;
+
+    return SECSuccess;
+}
+
+static SECStatus tls13_HandleECDHEKeyShare(sslSocket *ss,
+                                           TLS13KeyShareEntry *entry,
+                                           SECKEYPrivateKey *privKey,
+                                           SharedSecretType type)
+{
+    SECStatus rv;
+    SECKEYPublicKey *peerKey;
+    PK11SymKey *shared;
+
+    peerKey = tls13_ImportECDHKeyShare(ss, entry->key_exchange.data,
+                                       entry->key_exchange.len,
+                                       entry->group);
+    if (!peerKey)
+        return SECFailure;  /* Error code set already. */
+
+    /* Compute shared key. */
+    shared = tls13_ComputeECDHSharedKey(ss, privKey, peerKey);
+    SECKEY_DestroyPublicKey(peerKey);
+    if (!shared) {
+        return SECFailure;  /* Error code set already. */
+    }
+
+    /* Extract key. */
+    rv = tls13_HkdfExtractSharedKey(ss, shared, type);
+    PK11_FreeSymKey(shared);
+
+    return rv;
+}
+
+SECStatus
+tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
+                                     PRUint32 length, SSL3Hashes *hashesPtr)
+{
+    /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
+    switch (ss->ssl3.hs.msg_type) {
+    case certificate:
+	return tls13_HandleCertificate(ss, b, length);
+
+    case certificate_status:
+	return tls13_HandleCertificateStatus(ss, b, length);
+
+    case certificate_request:
+        return tls13_HandleCertificateRequest(ss, b, length);
+
+    case certificate_verify:
+	return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);
+
+    case encrypted_extensions:
+	return tls13_HandleEncryptedExtensions(ss, b, length);
+
+    case new_session_ticket:
+        return tls13_HandleNewSessionTicket(ss, b, length);
+
+    case finished:
+        return tls13_HandleFinished(ss, b, length, hashesPtr);
+
+    default:
+        FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
+        return SECFailure;
+    }
+
+    PORT_Assert(0); /* Unreached */
+    return SECFailure;
+}
+
+/* Called from ssl3_HandleClientHello.
+ *
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+SECStatus
+tls13_HandleClientKeyShare(sslSocket *ss)
+{
+    ECName expectedGroup;
+    SECStatus rv;
+    TLS13KeyShareEntry* found = NULL;
+    PRCList *cur_p;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle client_key_share handshake",
+		SSL_GETPID(), ss->fd));
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    rv = ssl3_SetupPendingCipherSpec(ss);
+    if (rv != SECSuccess)
+        return SECFailure; /* Error code set below */
+
+    /* Figure out what group we expect */
+    switch (ss->ssl3.hs.kea_def->exchKeyType) {
+#ifndef NSS_DISABLE_ECC
+    case ssl_kea_ecdh:
+        expectedGroup = ssl3_GetCurveNameForServerSocket(ss);
+        if (!expectedGroup) {
+            FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP,
+                        handshake_failure);
+            return SECFailure;
+        }
+        break;
+#endif
+    default:
+        /* Got an unknown or unsupported Key Exchange Algorithm.
+         * Can't happen. */
+        FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG,
+                    internal_error);
+        return SECFailure;
+    }
+
+    /* Now walk through the keys until we find one for our group */
+    cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
+    while (cur_p != &ss->ssl3.hs.remoteKeyShares) {
+        TLS13KeyShareEntry *offer = (TLS13KeyShareEntry*)cur_p;
+
+        if (offer->group == expectedGroup) {
+            found = offer;
+            break;
+        }
+        cur_p = PR_NEXT_LINK(cur_p);
+    }
+
+    if (!found) {
+        /* No acceptable group. In future, we will need to correct the client.
+         * Currently just generate an error.
+         * TODO(ekr@rtfm.com): Write code to correct client.
+         */
+        FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
+        return SECFailure;
+    }
+
+    /* Generate our key */
+    rv = ssl3_CreateECDHEphemeralKeyPair(expectedGroup, &ss->ephemeralECDHKeyPair);
+    if (rv != SECSuccess)
+        return rv;
+
+    ss->sec.keaType  = ss->ssl3.hs.kea_def->exchKeyType;
+    ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(
+        ss->ephemeralECDHKeyPair->pubKey);
+
+    /* Register the sender */
+    rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_key_share_xtn,
+                                                 tls13_ServerSendKeyShareXtn);
+    if (rv != SECSuccess)
+        return SECFailure;  /* Error code set below */
+
+    rv = tls13_HandleECDHEKeyShare(ss, found,
+                                   ss->ephemeralECDHKeyPair->privKey,
+                                   EphemeralSharedSecret);
+    if (rv != SECSuccess)
+        return SECFailure;  /* Error code set below */
+
+    return SECSuccess;
+}
+
+
+/*
+ *     [draft-ietf-tls-tls13-11] Section 6.3.3.2
+ *
+ *     opaque DistinguishedName<1..2^16-1>;
+ *
+ *     struct {
+ *         opaque certificate_extension_oid<1..2^8-1>;
+ *         opaque certificate_extension_values<0..2^16-1>;
+ *     } CertificateExtension;
+ *
+ *     struct {
+ *         opaque certificate_request_context<0..2^8-1>;
+ *         SignatureAndHashAlgorithm
+ *           supported_signature_algorithms<2..2^16-2>;
+ *         DistinguishedName certificate_authorities<0..2^16-1>;
+ *         CertificateExtension certificate_extensions<0..2^16-1>;
+ *     } CertificateRequest;
+ */
+static SECStatus
+tls13_SendCertificateRequest(sslSocket *ss)
+{
+    SECStatus rv;
+    int calen;
+    SECItem *names;
+    int nnames;
+    SECItem *name;
+    int i;
+    PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
+    unsigned int sigAlgsLength = 0;
+    int length;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
+		SSL_GETPID(), ss->fd));
+
+
+    /* Fixed context value. */
+    ss->ssl3.hs.certReqContext[0] = 0;
+    ss->ssl3.hs.certReqContextLen = 1;
+
+    rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs),
+                                              &sigAlgsLength);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+
+    ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+    length = 1 + ss->ssl3.hs.certReqContextLen
+             + 2 + sigAlgsLength + 2 + calen + 2;
+
+    rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
+    if (rv != SECSuccess) {
+	return rv; 		/* err set by AppendHandshake. */
+    }
+    rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.certReqContext,
+                                      ss->ssl3.hs.certReqContextLen, 1);
+    if (rv != SECSuccess) {
+        return rv; 		/* err set by AppendHandshake. */
+    }
+    rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2);
+    if (rv != SECSuccess) {
+        return rv; 		/* err set by AppendHandshake. */
+    }
+    rv = ssl3_AppendHandshakeNumber(ss, calen, 2);
+    if (rv != SECSuccess) {
+	return rv; 		/* err set by AppendHandshake. */
+    }
+    for (i = 0, name = names; i < nnames; i++, name++) {
+	rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2);
+	if (rv != SECSuccess) {
+	    return rv; 		/* err set by AppendHandshake. */
+	}
+    }
+    rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+    if (rv != SECSuccess) {
+	return rv; 		/* err set by AppendHandshake. */
+    }
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+    SECItem context = {siBuffer, NULL, 0};
+    SECItem algorithms  = {siBuffer, NULL, 0};
+    PLArenaPool *arena;
+    CERTDistNames ca_list;
+    PRInt32 extensionsLength;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence",
+		SSL_GETPID(), ss->fd));
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    /* Client */
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, wait_cert_request);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
+
+    PORT_Assert(ss->ssl3.clientCertChain == NULL);
+    PORT_Assert(ss->ssl3.clientCertificate == NULL);
+    PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
+    if (rv != SECSuccess)
+        return SECFailure;
+    PR_STATIC_ASSERT(sizeof(ss->ssl3.hs.certReqContext) == 255);
+    PORT_Memcpy(ss->ssl3.hs.certReqContext, context.data, context.len);
+    ss->ssl3.hs.certReqContextLen = context.len;
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length);
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    if (algorithms.len == 0 || (algorithms.len & 1) != 0) {
+	FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
+                    illegal_parameter);
+	return SECFailure;
+    }
+
+    arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list);
+    if (rv != SECSuccess)
+        goto loser; /* alert sent below */
+
+    /* Verify that the extensions length is correct. */
+    extensionsLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+    if (extensionsLength < 0) {
+        goto loser; /* alert sent below */
+    }
+    if (extensionsLength != length) {
+	FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
+                    illegal_parameter);
+        goto loser;
+    }
+
+    TLS13_SET_HS_STATE(ss, wait_server_cert);
+
+    rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        goto loser;
+    }
+
+    return SECSuccess;
+
+loser:
+    PORT_FreeArena(arena, PR_FALSE);
+    return SECFailure;
+}
+
+static SECStatus
+tls13_InitializeHandshakeEncryption(sslSocket *ss)
+{
+    SECStatus rv;
+
+    /* For all present cipher suites, SS = ES.
+     * TODO(ekr@rtfm.com): Revisit for 0-RTT. */
+    ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES);
+    if (!ss->ssl3.hs.xSS) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = tls13_InitCipherSpec(ss, TrafficKeyHandshake,
+                              InstallCipherSpecBoth);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    return rv;
+}
+
+/* Called from:  ssl3_HandleClientHello */
+SECStatus
+tls13_SendServerHelloSequence(sslSocket *ss)
+{
+    SECStatus rv;
+    SSL3KEAType certIndex;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence",
+		SSL_GETPID(), ss->fd));
+
+    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. */
+    }
+
+    rv = tls13_InitializeHandshakeEncryption(ss);
+    if (rv != SECSuccess) {
+        return SECFailure;      /* error code is set. */
+    }
+
+    rv = tls13_SendEncryptedExtensions(ss);
+    if (rv != SECSuccess) {
+	return SECFailure;	/* error code is set. */
+    }
+
+    if (ss->opt.requestCertificate) {
+	rv = tls13_SendCertificateRequest(ss);
+	if (rv != SECSuccess) {
+	    return SECFailure;		/* error code is set. */
+	}
+    }
+    rv = ssl3_SendCertificate(ss);
+    if (rv != SECSuccess) {
+	return SECFailure;	/* error code is set. */
+    }
+    rv = ssl3_SendCertificateStatus(ss);
+    if (rv != SECSuccess) {
+	return SECFailure;	/* error code is set. */
+    }
+
+    /* This was copied from: ssl3_SendCertificate.
+     * TODO(ekr@rtfm.com): Verify that this selection logic is correct.
+     * Bug 1237514.
+    */
+    if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+        (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+        certIndex = kt_rsa;
+    } else {
+        certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+    rv = ssl3_SendCertificateVerify(ss, ss->serverCerts[certIndex].SERVERKEY);
+    if (rv != SECSuccess) {
+        return rv;		/* err code is set. */
+    }
+
+    /* Compute the rest of the secrets except for the resumption
+     * and exporter secret. */
+    rv = tls13_ComputeSecrets1(ss);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = tls13_SendFinished(ss);
+    if (rv != SECSuccess) {
+	return rv;	/* error code is set. */
+    }
+
+    TLS13_SET_HS_STATE(ss, ss->opt.requestCertificate ?
+                       wait_client_cert : wait_finished);
+
+    return SECSuccess;
+}
+
+/*
+ * Called from ssl3_HandleServerHello.
+ *
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+SECStatus
+tls13_HandleServerKeyShare(sslSocket *ss)
+{
+    SECStatus rv;
+    ECName expectedGroup;
+    PRCList *cur_p;
+    TLS13KeyShareEntry *entry;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
+		SSL_GETPID(), ss->fd));
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    switch (ss->ssl3.hs.kea_def->exchKeyType) {
+#ifndef NSS_DISABLE_ECC
+    case ssl_kea_ecdh:
+        expectedGroup = ssl3_PubKey2ECName(ss->ephemeralECDHKeyPair->pubKey);
+        break;
+#endif /* NSS_DISABLE_ECC */
+    default:
+        FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG, handshake_failure);
+        return SECFailure;
+    }
+
+    /* This list should have one entry. */
+    cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
+    if (!cur_p) {
+        FATAL_ERROR(ss, SSL_ERROR_MISSING_KEY_SHARE, missing_extension);
+        return SECFailure;
+    }
+    PORT_Assert(PR_NEXT_LINK(cur_p) == &ss->ssl3.hs.remoteKeyShares);
+
+    entry = (TLS13KeyShareEntry*)cur_p;
+    if (entry->group != expectedGroup) {
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_SHARE, illegal_parameter);
+        return SECFailure;
+    }
+
+    rv = tls13_HandleECDHEKeyShare(ss, entry,
+                                   ss->ephemeralECDHKeyPair->privKey,
+                                   EphemeralSharedSecret);
+
+    ss->sec.keaType  = ss->ssl3.hs.kea_def->exchKeyType;
+    ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(
+        ss->ephemeralECDHKeyPair->pubKey);
+
+    if (rv != SECSuccess)
+        return SECFailure;  /* Error code set below */
+
+    return tls13_InitializeHandshakeEncryption(ss);
+}
+
+/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
+ * tls13 Certificate message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+tls13_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+    SECItem context = {siBuffer, NULL, 0};
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate handshake",
+		SSL_GETPID(), ss->fd));
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    if (ss->sec.isServer) {
+        rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+                                  wait_client_cert);
+    } else {
+        rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+                                  wait_cert_request, wait_server_cert);
+    }
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    /* Process the context string */
+    rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
+    if (rv != SECSuccess)
+        return SECFailure;
+    if (!ss->sec.isServer) {
+        if (context.len) {
+            /* The server's context string MUST be empty */
+            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE,
+                        illegal_parameter);
+            return SECFailure;
+        }
+    } else {
+        if (!context.len || context.len != ss->ssl3.hs.certReqContextLen ||
+            (NSS_SecureMemcmp(ss->ssl3.hs.certReqContext,
+                              context.data, context.len) != 0)) {
+            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE,
+                        illegal_parameter);
+            return SECFailure;
+        }
+        context.len = 0; /* Belt and suspenders. Zero out the context. */
+    }
+
+
+    return ssl3_CompleteHandleCertificate(ss, b, length);
+}
+
+/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 CertificateStatus message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_STATUS,
+                              wait_certificate_status);
+    if (rv != SECSuccess)
+        return rv;
+
+    return ssl3_CompleteHandleCertificateStatus(ss, b, length);
+}
+
+/*
+ * TODO(ekr@rtfm.com): This install logic needs renaming since it's
+ * what happens at various stages of cipher spec setup. Legacy from ssl3con.c.
+ */
+int
+tls13_InstallCipherSpec(sslSocket *ss, InstallCipherSpecDirection direction)
+{
+    SSL_TRC(3, ("%d: TLS13[%d]: Installing new cipher specs direction = %s",
+		SSL_GETPID(), ss->fd,
+                direction == InstallCipherSpecRead ? "read" : "write"));
+
+    PORT_Assert(!IS_DTLS(ss));  /* TODO(ekr@rtfm.com): Update for DTLS */
+    /* TODO(ekr@rtfm.com): Holddown timer for DTLS. */
+    ssl_GetSpecWriteLock(ss);	/**************************************/
+
+    /* Flush out any old stuff in the handshake buffers */
+    switch (direction) {
+        case InstallCipherSpecWrite:
+            {
+                ssl3CipherSpec *pwSpec;
+                pwSpec = ss->ssl3.pwSpec;
+
+                ss->ssl3.pwSpec = ss->ssl3.cwSpec;
+                ss->ssl3.cwSpec = pwSpec;
+                break;
+            }
+            break;
+        case InstallCipherSpecRead:
+            {
+                ssl3CipherSpec *prSpec;
+
+                prSpec = ss->ssl3.prSpec;
+                ss->ssl3.prSpec  = ss->ssl3.crSpec;
+                ss->ssl3.crSpec  = prSpec;
+            }
+            break;
+        default:
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            ssl_ReleaseSpecWriteLock(ss); /**************************************/
+            return SECFailure;
+    }
+
+    /* If we are really through with the old cipher prSpec
+     * (Both the read and write sides have changed) destroy it.
+     */
+    if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
+    	ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/);
+    }
+    ssl_ReleaseSpecWriteLock(ss); /**************************************/
+
+    return SECSuccess;
+}
+
+/* Add context to the hash functions as described in 
+   [draft-ietf-tls-tls13; Section 4.9.1] */
+SECStatus
+tls13_AddContextToHashes(sslSocket *ss, SSL3Hashes *hashes /* IN/OUT */,
+                         SSLHashType algorithm, PRBool sending)
+{
+    SECStatus rv = SECSuccess;
+    PK11Context* ctx;
+    const unsigned char context_padding[] = {
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    };
+    const char *client_cert_verify_string = "TLS 1.3, client CertificateVerify";
+    const char *server_cert_verify_string = "TLS 1.3, server CertificateVerify";
+    const char *context_string = (sending ^ ss->sec.isServer) ?
+            client_cert_verify_string : server_cert_verify_string;
+    unsigned int hashlength;
+
+    /* Double check that we are doing SHA-256 for the handshake hash.*/
+    PORT_Assert(hashes->hashAlg == ssl_hash_sha256);
+    if (hashes->hashAlg != ssl_hash_sha256) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        goto loser;
+    }
+    PORT_Assert(hashes->len == 32);
+
+    ctx = PK11_CreateDigestContext(ssl3_TLSHashAlgorithmToOID(algorithm));
+    if (!ctx) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    PR_STATIC_ASSERT(SECFailure);
+    PR_STATIC_ASSERT(!SECSuccess);
+
+    rv |= PK11_DigestBegin(ctx);
+    rv |= PK11_DigestOp(ctx, context_padding, sizeof(context_padding));
+    rv |= PK11_DigestOp(ctx, (unsigned char *)context_string,
+                        strlen(context_string) + 1); /* +1 includes the terminating 0 */
+    rv |= PK11_DigestOp(ctx, hashes->u.raw, hashes->len);
+    /* Update the hash in-place */
+    rv |= PK11_DigestFinal(ctx, hashes->u.raw, &hashlength, sizeof(hashes->u.raw));
+    PK11_DestroyContext(ctx, PR_TRUE);
+    PRINT_BUF(90, (NULL, "TLS 1.3 hash with context", hashes->u.raw, hashlength));
+
+    hashes->len = hashlength;
+    hashes->hashAlg = algorithm;
+
+    if (rv) {
+        ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+        goto loser;
+    }
+    return SECSuccess;
+
+loser:
+    return SECFailure;
+}
+
+static SECStatus
+tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey* key,
+                           SharedSecretType keyType)
+{
+    PK11SymKey** destp;
+
+    switch(keyType) {
+        case EphemeralSharedSecret:
+            destp = &ss->ssl3.hs.xES;
+            break;
+        case StaticSharedSecret:
+            destp = &ss->ssl3.hs.xSS;
+            break;
+        default:
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+    }
+
+    PORT_Assert(!*destp);
+    return tls13_HkdfExtract(NULL, key, tls13_GetHash(ss), destp);
+}
+
+static SECStatus
+tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *pwSpec,
+                        TrafficKeyType type)
+{
+    size_t keySize = pwSpec->cipher_def->key_size;
+    size_t ivSize = pwSpec->cipher_def->iv_size +
+            pwSpec->cipher_def->explicit_nonce_size; /* This isn't always going to
+                                                      * work, but it does for
+                                                      * AES-GCM */
+    CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(pwSpec->cipher_def->calg);
+    SSL3Hashes hashes;
+    PK11SymKey *prk = NULL;
+    const char *phase;
+    char label[256]; /* Arbitrary buffer large enough to hold the label */
+    SECStatus rv;
+
+#define FORMAT_LABEL(phase_, purpose_) do { \
+        PRUint32 n = PR_snprintf(label, sizeof(label), "%s, %s", phase_, purpose_); \
+        PORT_Assert((n+1) < sizeof(label)); /* Check for getting close */ \
+    } while(0)
+#define EXPAND_TRAFFIC_KEY(purpose_, target_)                           \
+    do {                                                                \
+        FORMAT_LABEL(phase, purpose_);                                  \
+        rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss),              \
+                                   hashes.u.raw, hashes.len,            \
+                                   label, strlen(label),                \
+                                   bulkAlgorithm, keySize, &pwSpec->target_); \
+        if (rv != SECSuccess) {                                         \
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);                   \
+            PORT_Assert(0);                                             \
+            goto loser;                                                 \
+        }                                                               \
+    } while (0)
+
+#define EXPAND_TRAFFIC_IV(purpose_, target_)                    \
+    do {                                                        \
+        FORMAT_LABEL(phase, purpose_);                          \
+        rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss),   \
+                                      hashes.u.raw, hashes.len, \
+                                      label, strlen(label),     \
+                                      pwSpec->target_, ivSize); \
+        if (rv != SECSuccess) {                                 \
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);           \
+            PORT_Assert(0);                                     \
+            goto loser;                                         \
+        }                                                       \
+    } while (0)
+
+
+    PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+    PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+    PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+    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;
+    }
+    PRINT_BUF(60, (ss, "Deriving traffic keys. Session hash=", hashes.u.raw,
+                   hashes.len));
+
+    switch (type) {
+        case TrafficKeyHandshake:
+            phase = kHkdfPhaseHandshakeKeys;
+            prk = ss->ssl3.hs.xES;
+            break;
+        case TrafficKeyApplicationData:
+            phase = kHkdfPhaseApplicationDataKeys;
+            prk = ss->ssl3.hs.trafficSecret;
+            break;
+        default:
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+    }
+    PORT_Assert(prk != NULL);
+
+    SSL_TRC(3, ("%d: TLS13[%d]: deriving traffic keys phase='%s'",
+                SSL_GETPID(), ss->fd, phase));
+
+    EXPAND_TRAFFIC_KEY(kHkdfPurposeClientWriteKey, client.write_key);
+    EXPAND_TRAFFIC_KEY(kHkdfPurposeServerWriteKey, server.write_key);
+    EXPAND_TRAFFIC_IV(kHkdfPurposeClientWriteIv, client.write_iv);
+    EXPAND_TRAFFIC_IV(kHkdfPurposeServerWriteIv, server.write_iv);
+
+    return SECSuccess;
+
+loser:
+    return SECFailure;
+}
+
+/* Set up a cipher spec with keys. If install is nonzero, then also install
+ * it as the current cipher spec for each value in the mask. */
+SECStatus
+tls13_InitCipherSpec(sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install)
+{
+    ssl3CipherSpec *pwSpec;
+    ssl3CipherSpec *cwSpec;
+    SECStatus rv;
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+    if (install == InstallCipherSpecWrite ||
+        install == InstallCipherSpecBoth) {
+        ssl_GetXmitBufLock(ss);
+
+        rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+        ssl_ReleaseXmitBufLock(ss);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+
+    ssl_GetSpecWriteLock(ss);	/**************************************/
+
+    PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+    pwSpec = ss->ssl3.pwSpec;
+    cwSpec = ss->ssl3.cwSpec;
+
+    switch(pwSpec->cipher_def->calg) {
+        case calg_aes_gcm:
+            pwSpec->aead = tls13_AESGCM;
+            break;
+        default:
+            PORT_Assert(0);
+            goto loser;
+            break;
+    }
+
+    /* Generic behaviors -- common to all crypto methods */
+    if (!IS_DTLS(ss)) {
+	pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0;
+    } else {
+	if (cwSpec->epoch == PR_UINT16_MAX) {
+	    /* The problem here is that we have rehandshaked too many
+	     * times (you are not allowed to wrap the epoch). The
+	     * spec says you should be discarding the connection
+	     * and start over, so not much we can do here. */
+	    rv = SECFailure;
+            goto loser;
+	}
+	/* The sequence number has the high 16 bits as the epoch. */
+	pwSpec->epoch = cwSpec->epoch + 1;
+	pwSpec->read_seq_num.high = pwSpec->write_seq_num.high =
+	    pwSpec->epoch << 16;
+
+	dtls_InitRecvdRecords(&pwSpec->recvdRecords);
+    }
+    pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0;
+
+    rv = tls13_DeriveTrafficKeys(ss, pwSpec, type);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    if (install == InstallCipherSpecWrite ||
+        install == InstallCipherSpecBoth) {
+        rv = tls13_InstallCipherSpec(ss, InstallCipherSpecWrite);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+    if (install == InstallCipherSpecRead ||
+        install == InstallCipherSpecBoth) {
+        rv = tls13_InstallCipherSpec(ss, InstallCipherSpecRead);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+    ssl_ReleaseSpecWriteLock(ss);	/**************************************/
+
+    return SECSuccess;
+
+loser:
+    ssl_ReleaseSpecWriteLock(ss);	/**************************************/
+    PORT_SetError(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE);
+    return SECFailure;
+}
+
+static SECStatus
+tls13_ComputeSecrets1(sslSocket *ss)
+{
+    SECStatus rv;
+    PK11SymKey *mSS = NULL;
+    PK11SymKey *mES = NULL;
+    PK11SymKey *masterSecret = NULL;
+    SSL3Hashes hashes;
+
+    rv = ssl3_SetupPendingCipherSpec(ss);
+    if (rv != SECSuccess) {
+        return rv;  /* error code set below. */
+    }
+
+    rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
+    if (rv != SECSuccess) {
+        PORT_Assert(0);  /* Should never fail */
+        ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+        return SECFailure;
+    }
+
+    PORT_Assert(ss->ssl3.hs.xSS);
+    PORT_Assert(ss->ssl3.hs.xES);
+
+    rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xSS,
+                               tls13_GetHash(ss),
+                               hashes.u.raw, hashes.len,
+                               kHkdfLabelExpandedSs,
+                               strlen(kHkdfLabelExpandedSs),
+                               tls13_GetHkdfMechanism(ss),
+                               hashes.len, &mSS);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xES,
+                               tls13_GetHash(ss),
+                               hashes.u.raw, hashes.len,
+                               kHkdfLabelExpandedEs,
+                               strlen(kHkdfLabelExpandedEs),
+                               tls13_GetHkdfMechanism(ss),
+                               hashes.len, &mES);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExtract(mSS, mES,
+                           tls13_GetHash(ss),
+                           &masterSecret);
+
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExpandLabel(masterSecret,
+                               tls13_GetHash(ss),
+                               hashes.u.raw, hashes.len,
+                               kHkdfLabelTrafficSecret,
+                               strlen(kHkdfLabelTrafficSecret),
+                               tls13_GetHkdfMechanism(ss),
+                               hashes.len, &ss->ssl3.hs.trafficSecret);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExpandLabel(masterSecret,
+                               tls13_GetHash(ss),
+                               NULL, 0,
+                               kHkdfLabelClientFinishedSecret,
+                               strlen(kHkdfLabelClientFinishedSecret),
+                               tls13_GetHmacMechanism(ss),
+                               hashes.len, &ss->ssl3.hs.clientFinishedSecret);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExpandLabel(masterSecret,
+                               tls13_GetHash(ss),
+                               NULL, 0,
+                               kHkdfLabelServerFinishedSecret,
+                               strlen(kHkdfLabelServerFinishedSecret),
+                               tls13_GetHmacMechanism(ss),
+                               hashes.len, &ss->ssl3.hs.serverFinishedSecret);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+loser:
+    PK11_FreeSymKey(ss->ssl3.hs.xSS);
+    PK11_FreeSymKey(ss->ssl3.hs.xES);
+
+    if (mSS) {
+        PK11_FreeSymKey(mSS);
+    }
+    if (mES) {
+        PK11_FreeSymKey(mES);
+    }
+    if (masterSecret) {
+        PK11_FreeSymKey(masterSecret);
+    }
+
+    return rv;
+}
+
+void
+tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer)
+{
+    SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE);
+    PORT_ZFree(offer, sizeof(offer));
+}
+
+void
+tls13_DestroyKeyShares(PRCList *list)
+{
+    PRCList *cur_p;
+
+    while (!PR_CLIST_IS_EMPTY(list)) {
+        cur_p = PR_LIST_TAIL(list);
+        PR_REMOVE_LINK(cur_p);
+        tls13_DestroyKeyShareEntry((TLS13KeyShareEntry *)cur_p);
+    }
+}
+
+/* Implement the SSLAEADCipher interface defined in sslimpl.h.
+ *
+ * That interface mixes the AD and the sequence number, but in
+ * TLS 1.3 there is no additional data so this value is just the
+ * encoded sequence number and we call it |seqNumBuf|.
+ */
+static SECStatus
+tls13_AESGCM(ssl3KeyMaterial *keys,
+             PRBool doDecrypt,
+             unsigned char *out,
+             int *outlen,
+             int maxout,
+             const unsigned char *in,
+             int inlen,
+             const unsigned char *seqNumBuf,
+             int seqNumLen)
+{
+    SECItem param;
+    SECStatus rv = SECFailure;
+    unsigned char nonce[12];
+    size_t i;
+    unsigned int uOutLen;
+    CK_GCM_PARAMS gcmParams;
+    static const int tagSize = 16;
+
+    PORT_Assert(seqNumLen == 8);
+
+    /* draft-ietf-tls-tls13 Section 5.2.2 specifies the following
+     * nonce algorithm:
+     *
+     * The length of the per-record nonce (iv_length) is set to max(8 bytes,
+     * N_MIN) for the AEAD algorithm (see [RFC5116] Section 4).  An AEAD
+     * algorithm where N_MAX is less than 8 bytes MUST NOT be used with TLS.
+     * The per-record nonce for the AEAD construction is formed as follows:
+     *
+     * 1.  The 64-bit record sequence number is padded to the left with
+     *     zeroes to iv_length.
+     *
+     * 2.  The padded sequence number is XORed with the static
+     *     client_write_iv or server_write_iv, depending on the role.
+     *
+     * The resulting quantity (of length iv_length) is used as the per-
+     * record nonce.
+     *
+     * Per RFC 5288: N_MIN = N_MAX = 12 bytes.
+     *
+     */
+    memcpy(nonce, keys->write_iv, sizeof(nonce));
+    for (i=0; i < 8; ++i) {
+        nonce[4 + i] ^= seqNumBuf[i];
+    }
+
+    param.type = siBuffer;
+    param.data = (unsigned char *) &gcmParams;
+    param.len = sizeof(gcmParams);
+    gcmParams.pIv = nonce;
+    gcmParams.ulIvLen = sizeof(nonce);
+    gcmParams.pAAD = NULL;
+    gcmParams.ulAADLen = 0;
+    gcmParams.ulTagBits = tagSize * 8;
+
+    if (doDecrypt) {
+	rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+			  maxout, in, inlen);
+    } else {
+	rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+			  maxout, in, inlen);
+    }
+    *outlen = (int)uOutLen;
+
+    return rv;
+}
+
+static SECStatus
+tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle encrypted extensions",
+    	SSL_GETPID(), ss->fd));
+
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS,
+                              wait_encrypted_extensions);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    rv = ssl3_HandleHelloExtensions(ss, &b, &length, encrypted_extensions);
+    if (rv != SECSuccess) {
+        return SECFailure;  /* Error code set below */
+    }
+
+    TLS13_SET_HS_STATE(ss, wait_cert_request);
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_SendEncryptedExtensions(sslSocket *ss)
+{
+    SECStatus rv;
+    PRInt32 extensions_len = 0;
+    PRInt32 sent_len = 0;
+    PRUint32 maxBytes = 65535;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake",
+                SSL_GETPID(), ss->fd));
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+    extensions_len = ssl3_CallHelloExtensionSenders(
+        ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]);
+
+    rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, extensions_len);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    sent_len = ssl3_CallHelloExtensionSenders(
+        ss, PR_TRUE, extensions_len, &ss->xtnData.encryptedExtensionsSenders[0]);
+    PORT_Assert(sent_len == extensions_len);
+    if (sent_len != extensions_len) {
+        PORT_Assert(sent_len == 0);
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
+ * tls13 CertificateVerify message
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+SECStatus
+tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+                              SSL3Hashes *hashes)
+{
+    SECItem              signed_hash = {siBuffer, NULL, 0};
+    SECStatus            rv;
+    SSLSignatureAndHashAlg sigAndHash;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
+		SSL_GETPID(), ss->fd));
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY,
+                              wait_cert_verify);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    if (!hashes) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    /* We only support CertificateVerify messages that use the handshake
+     * hash.
+     * TODO(ekr@rtfm.com): This should be easy to relax in TLS 1.3 by
+     * reading the client's hash algorithm first, but there may
+     * be subtleties so retain the restriction for now.
+     */
+    rv = tls13_AddContextToHashes(ss, hashes, hashes->hashAlg, PR_FALSE);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+                                               &sigAndHash);
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
+	return SECFailure;
+    }
+
+    rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+        ss, &sigAndHash, ss->sec.peerCert);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decrypt_error);
+        return SECFailure;
+    }
+
+    /* We only support CertificateVerify messages that use the handshake
+     * hash. */
+    if (sigAndHash.hashAlg != hashes->hashAlg) {
+        FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, decrypt_error);
+        return SECFailure;
+    }
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
+	return SECFailure;
+    }
+
+    if (length != 0) {
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decode_error);
+        return SECFailure;
+    }
+
+    rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
+				 PR_TRUE, ss->pkcs11PinArg);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
+        return SECFailure;
+    }
+
+    if (!ss->sec.isServer) {
+        /* Compute the rest of the secrets except for the resumption
+         * and exporter secret. */
+        rv = tls13_ComputeSecrets1(ss);
+        if (rv != SECSuccess) {
+            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+            return SECFailure;
+        }
+    }
+    TLS13_SET_HS_STATE(ss, wait_finished);
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_ComputeFinished(sslSocket *ss, const SSL3Hashes *hashes, PRBool sending,
+                      PRUint8 *output, unsigned int *outputLen, unsigned int maxOutputLen)
+{
+    SECStatus rv;
+    PK11Context *hmacCtx = NULL;
+    CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanism(ss);
+    SECItem param = { siBuffer, NULL, 0 };
+    unsigned int outputLenUint;
+    PK11SymKey *secret = (ss->sec.isServer ^ sending) ?
+            ss->ssl3.hs.clientFinishedSecret : ss->ssl3.hs.serverFinishedSecret;
+
+    PORT_Assert(secret);
+    PRINT_BUF(90, (NULL, "Handshake hash", hashes->u.raw, hashes->len));
+
+    hmacCtx = PK11_CreateContextBySymKey(macAlg, CKA_SIGN,
+                                         secret, &param);
+    if (!hmacCtx) {
+        goto abort;
+    }
+
+    rv = PK11_DigestBegin(hmacCtx);
+    if (rv != SECSuccess)
+        goto abort;
+
+    rv = PK11_DigestOp(hmacCtx, hashes->u.raw, hashes->len);
+    if (rv != SECSuccess)
+        goto abort;
+
+    PORT_Assert(maxOutputLen >= hashes->len);
+    rv = PK11_DigestFinal(hmacCtx, output, &outputLenUint, maxOutputLen);
+    if (rv != SECSuccess)
+        goto abort;
+    *outputLen = outputLenUint;
+
+    PK11_DestroyContext(hmacCtx, PR_TRUE);
+    return SECSuccess;
+
+abort:
+    if (hmacCtx) {
+        PK11_DestroyContext(hmacCtx, PR_TRUE);
+    }
+
+    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    return SECFailure;
+}
+
+static SECStatus
+tls13_SendFinished(sslSocket *ss)
+{
+    SECStatus rv;
+    PRUint8 finishedBuf[MAX_FINISHED_SIZE];
+    unsigned int finishedLen;
+    SSL3Hashes hashes;
+    int errCode;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: send finished handshake", SSL_GETPID(), ss->fd));
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+    rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    ssl_GetSpecReadLock(ss);
+    rv = tls13_ComputeFinished(ss, &hashes, PR_TRUE,
+                               finishedBuf, &finishedLen, sizeof(finishedBuf));
+    ssl_ReleaseSpecReadLock(ss);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen);
+    if (rv != SECSuccess) {
+        errCode = PR_GetError();
+        goto alert_loser;
+    }
+
+    rv = ssl3_AppendHandshake(ss, finishedBuf, finishedLen);
+    if (rv != SECSuccess) {
+        errCode = PR_GetError();
+        goto alert_loser;
+    }
+
+    rv = ssl3_FlushHandshake(ss, 0);
+    if (rv != SECSuccess) {
+        errCode = PR_GetError();
+        goto alert_loser;
+    }
+
+    if (!ss->sec.isServer) {
+        rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData,
+                                  InstallCipherSpecBoth);
+        if (rv != SECSuccess) {
+            errCode = PR_GetError();
+            goto alert_loser;
+        }
+    }
+
+    /* TODO(ekr@rtfm.com): Record key log */
+    return SECSuccess;
+
+  alert_loser:
+    (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+    PORT_SetError(errCode);  /* Restore error code */
+    return rv;
+}
+
+static SECStatus
+tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+                     const SSL3Hashes *hashes)
+{
+    SECStatus rv;
+    PRUint8 finishedBuf[MAX_FINISHED_SIZE];
+    unsigned int finishedLen;
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle finished handshake",
+    	SSL_GETPID(), ss->fd));
+
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
+    if (!hashes) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    ssl_GetSpecReadLock(ss);
+    rv = tls13_ComputeFinished(ss, hashes, PR_FALSE,
+                               finishedBuf, &finishedLen, sizeof(finishedBuf));
+    ssl_ReleaseSpecReadLock(ss);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+	return SECFailure;
+    }
+
+    if (length != finishedLen) {
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_FINISHED, decode_error);
+        return SECFailure;
+    }
+
+    if (NSS_SecureMemcmp(b, finishedBuf, finishedLen) != 0) {
+        FATAL_ERROR(ss, SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE,
+                    decrypt_error);
+        return SECFailure;
+    }
+
+    /* Server is now finished.
+     * Client sends second flight
+     */
+    /* TODO(ekr@rtfm.com): Send NewSession Ticket if server. */
+    if (ss->sec.isServer) {
+        rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData,
+                                  InstallCipherSpecBoth);
+        if (rv != SECSuccess) {
+            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+            return SECFailure;
+        }
+
+        rv = tls13_FinishHandshake(ss);
+    } else {
+        if (ss->ssl3.hs.authCertificatePending) {
+            /* TODO(ekr@rtfm.com): Handle pending auth */
+            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+            PORT_Assert(0);
+            return SECFailure;
+        }
+        rv = tls13_SendClientSecondRound(ss);
+        if (rv != SECSuccess)
+            return SECFailure;  /* Error code and alerts handled below */
+    }
+
+    return rv;
+}
+
+static SECStatus
+tls13_FinishHandshake(sslSocket *ss)
+{
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
+
+    /* The first handshake is now completed. */
+    ss->handshake           = NULL;
+
+    TLS13_SET_HS_STATE(ss, idle_handshake);
+
+    ssl_FinishHandshake(ss);
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_SendClientSecondRound(sslSocket *ss)
+{
+    SECStatus rv;
+    PRBool sendClientCert;
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+    sendClientCert = !ss->ssl3.sendEmptyCert &&
+		     ss->ssl3.clientCertChain  != NULL &&
+		     ss->ssl3.clientPrivateKey != NULL;
+
+    /* Defer client authentication sending if we are still
+     * waiting for server authentication. See the long block
+     * comment in ssl3_SendClientSecondRound for more detail.
+     */
+    if (ss->ssl3.hs.restartTarget) {
+	PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    if (ss->ssl3.hs.authCertificatePending && (sendClientCert ||
+                                               ss->ssl3.sendEmptyCert)) {
+	SSL_TRC(3, ("%d: TLS13[%p]: deferring ssl3_SendClientSecondRound because"
+		    " certificate authentication is still pending.",
+		    SSL_GETPID(), ss->fd));
+	ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound;
+	return SECWouldBlock;
+    }
+
+    ssl_GetXmitBufLock(ss);		/*******************************/
+    if (ss->ssl3.sendEmptyCert) {
+	ss->ssl3.sendEmptyCert = PR_FALSE;
+	rv = ssl3_SendEmptyCertificate(ss);
+	/* Don't send verify */
+	if (rv != SECSuccess) {
+	    goto loser;	/* error code is set. */
+    	}
+    } else if (sendClientCert) {
+	rv = ssl3_SendCertificate(ss);
+	if (rv != SECSuccess) {
+	    goto loser;	/* error code is set. */
+    	}
+    }
+
+    if (sendClientCert) {
+	rv = ssl3_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
+        SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+        ss->ssl3.clientPrivateKey = NULL;
+	if (rv != SECSuccess) {
+	    goto loser;	/* err is set. */
+        }
+    }
+
+    rv = tls13_SendFinished(ss);
+    if (rv != SECSuccess) {
+	goto loser;	/* err code was set. */
+    }
+    ssl_ReleaseXmitBufLock(ss);		/*******************************/
+
+    /* The handshake is now finished */
+    return tls13_FinishHandshake(ss);
+
+loser:
+    ssl_ReleaseXmitBufLock(ss);		/*******************************/
+    return SECFailure;
+}
+
+static SECStatus
+tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+
+    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
+                              idle_handshake);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    UNIMPLEMENTED();
+
+    /* Ignore */
+    return SECSuccess;
+}
+
+
+typedef enum {
+    ExtensionNotUsed,
+    ExtensionClientOnly,
+    ExtensionSendClear,
+    ExtensionSendEncrypted,
+    ExtensionUnknown,
+} Tls13ExtensionStatus;
+
+static const struct {
+    SSLExtensionType ex_value;
+    Tls13ExtensionStatus status;
+} KnownExtensions[] = {
+    {
+        ssl_server_name_xtn,
+        ExtensionSendEncrypted
+    },
+    {
+        ssl_cert_status_xtn,
+        ExtensionNotUsed /* TODO(ekr@rtfm.com): Disabled because broken
+                            in TLS 1.3. */
+        /* ExtensionSendEncrypted */
+    },
+    {
+        ssl_elliptic_curves_xtn,
+        ExtensionSendClear
+    },
+    {
+        ssl_ec_point_formats_xtn,
+        ExtensionNotUsed
+    },
+    {
+        ssl_signature_algorithms_xtn,
+        ExtensionClientOnly
+    },
+    {
+        ssl_use_srtp_xtn,
+        ExtensionSendEncrypted
+    },
+    {
+        ssl_app_layer_protocol_xtn,
+        ExtensionSendEncrypted
+    },
+    {
+        ssl_padding_xtn,
+        ExtensionNotUsed
+    },
+    {
+        ssl_extended_master_secret_xtn,
+        ExtensionNotUsed
+    },
+    {
+        ssl_session_ticket_xtn,
+        ExtensionClientOnly
+    },
+    {
+        ssl_tls13_key_share_xtn,
+        ExtensionSendClear
+    },
+    {
+        ssl_next_proto_nego_xtn,
+        ExtensionNotUsed
+    },
+    {
+        ssl_renegotiation_info_xtn,
+        ExtensionNotUsed
+    },
+    {
+        ssl_tls13_draft_version_xtn,
+        ExtensionClientOnly
+    }
+};
+
+PRBool
+tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
+{
+    unsigned int i;
+
+    PORT_Assert(message == client_hello |
+                message == server_hello ||
+                message == encrypted_extensions);
+
+    for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
+        if (KnownExtensions[i].ex_value == extension) {
+            break;
+        }
+    }
+
+    switch(KnownExtensions[i].status) {
+        case ExtensionNotUsed:
+            return PR_FALSE;
+        case ExtensionClientOnly:
+            return message == client_hello;
+        case ExtensionSendClear:
+            return message == client_hello ||
+                    message == server_hello;
+        case ExtensionSendEncrypted:
+            return message == client_hello ||
+                    message == encrypted_extensions;
+        case ExtensionUnknown:
+            return PR_TRUE;
+    }
+
+    PORT_Assert(0);
+
+    /* Not reached */
+    return PR_TRUE;
+}
+
+/* Helper function to encode a uint32 into a buffer */
+unsigned char *
+tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to)
+{
+    PORT_Assert(bytes > 0 && bytes <= 4);
+
+    PRUint32 encoded = PR_htonl(value);
+    memcpy(to, ((unsigned char *)(&encoded)) + (4-bytes), bytes);
+    return to + bytes;
+}
+
+/* TLS 1.3 doesn't actually have additional data but the aead function
+ * signature overloads additional data to carry the record sequence
+ * number and that's what we put here. The TLS 1.3 AEAD functions
+ * just use this input as the sequence number and not as additional
+ * data. */
+static void
+tls13_FormatAdditionalData(unsigned char *aad, unsigned int length,
+                           SSL3SequenceNumber seqNum)
+{
+    unsigned char *ptr = aad;
+
+    PORT_Assert(length == 8);
+    ptr = tls13_EncodeUintX(seqNum.high, 4, ptr);
+    ptr = tls13_EncodeUintX(seqNum.low, 4, ptr);
+    PORT_Assert((ptr - aad) == length);
+}
+
+SECStatus
+tls13_ProtectRecord(sslSocket *ss,
+                    SSL3ContentType type,
+                    const SSL3Opaque *pIn,
+                    PRUint32 contentLen,
+                    sslBuffer *wrBuf)
+{
+    ssl3CipherSpec *cwSpec = ss->ssl3.cwSpec;
+    const ssl3BulkCipherDef* cipher_def = cwSpec->cipher_def;
+    SECStatus rv;
+    PRUint16 headerLen;
+    int cipherBytes = 0;
+    const int tagLen = cipher_def->tag_size;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: protect record of length %u, seq=0x%0x%0x",
+                SSL_GETPID(), ss->fd, contentLen,
+                cwSpec->write_seq_num.high,
+                cwSpec->write_seq_num.low
+        ));
+
+    headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
+
+    if (headerLen + contentLen + 1 + tagLen > wrBuf->space) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    /* Copy the data into the wrBuf. We're going to encrypt in-place
+     * in the AEAD branch anyway */
+    PORT_Memcpy(wrBuf->buf + headerLen, pIn, contentLen);
+
+    if (cipher_def->calg == ssl_calg_null) {
+        /* Shortcut for plaintext */
+        cipherBytes = contentLen;
+    } else {
+        unsigned char aad[8];
+        PORT_Assert(cipher_def->type == type_aead);
+
+        /* Add the content type at the end. */
+        wrBuf->buf[headerLen + contentLen] = type;
+
+        /* Stomp the content type to be application_data */
+        type = content_application_data;
+
+        tls13_FormatAdditionalData(aad, sizeof(aad),
+                                   cwSpec->write_seq_num);
+        cipherBytes = contentLen + 1; /* Room for the content type on the end. */
+        rv = cwSpec->aead(
+            ss->sec.isServer ? &cwSpec->server : &cwSpec->client,
+            PR_FALSE,                                   /* do encrypt */
+            wrBuf->buf + headerLen,                     /* output  */
+            &cipherBytes,                               /* out len */
+            wrBuf->space - headerLen,                   /* max out */
+            wrBuf->buf + headerLen, contentLen + 1,     /* input   */
+            aad, sizeof(aad));
+        if (rv != SECSuccess) {
+            PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+            return SECFailure;
+        }
+    }
+
+    PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 256);
+
+    wrBuf->len = cipherBytes + headerLen;
+    wrBuf->buf[0] = type;
+
+    if (IS_DTLS(ss)) {
+        (void)tls13_EncodeUintX(2, dtls_TLSVersionToDTLSVersion(kRecordVersion),
+                    &wrBuf->buf[1]);
+        (void)tls13_EncodeUintX(cwSpec->write_seq_num.high, 4, &wrBuf->buf[3]);
+        (void)tls13_EncodeUintX(cwSpec->write_seq_num.low, 4, &wrBuf->buf[7]);
+        (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[11]);
+    } else {
+        (void)tls13_EncodeUintX(kRecordVersion, 2, &wrBuf->buf[1]);
+        (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[3]);
+    }
+    ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
+
+    return SECSuccess;
+}
+
+
+/* Unprotect a TLS 1.3 record and leave the result in plaintext.
+ *
+ * Called by ssl3_HandleRecord. Caller must hold the spec read lock.
+ * Therefore, we MUST not call SSL3_SendAlert().
+ *
+ * If SECFailure is returned, we:
+ * 1. Set |*alert| to the alert to be sent.
+ * 2. Call PORT_SetError() witn an appropriate code.
+ */
+SECStatus
+tls13_UnprotectRecord(sslSocket* ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
+                      SSL3AlertDescription* alert)
+{
+    ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
+    const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def;
+    unsigned char aad[8];
+    SECStatus rv;
+
+    *alert = bad_record_mac; /* Default alert for most issues. */
+
+    SSL_TRC(3, ("%d: TLS13[%d]: unprotect record of length %u",
+		SSL_GETPID(), ss->fd, cText->buf->len));
+
+    /* We can perform this test in variable time because the record's total
+     * length and the ciphersuite are both public knowledge. */
+    if (cText->buf->len < cipher_def->tag_size) {
+        PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+	return SECFailure;
+    }
+
+    /* Check the version number in the record */
+    if (cText->version != kRecordVersion) {
+        /* Do we need a better error here? */
+        PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+        return SECFailure;
+    }
+
+    /* Decrypt */
+    PORT_Assert(cipher_def->type == type_aead);
+    tls13_FormatAdditionalData(aad, sizeof(aad),
+                               IS_DTLS(ss) ?
+                               cText->seq_num :
+                               crSpec->read_seq_num);
+    rv = crSpec->aead(
+        ss->sec.isServer ? &crSpec->client : &crSpec->server,
+        PR_TRUE,                          /* do decrypt */
+        plaintext->buf,                   /* out */
+        (int*) &plaintext->len,           /* outlen */
+        plaintext->space,                 /* maxout */
+        cText->buf->buf,                  /* in */
+        cText->buf->len,                  /* inlen */
+        aad, sizeof(aad));
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+        return SECFailure;
+    }
+
+    /* The record is right-padded with 0s, followed by the true
+     * content type, so read from the right until we receive a
+     * nonzero byte. */
+    while (plaintext->len > 0 && !(plaintext->buf[plaintext->len-1])) {
+        --plaintext->len;
+    }
+
+    /* Bogus padding. */
+    if (plaintext->len < 1) {
+        /* It's safe to report this specifically because it happened
+         * after the MAC has been verified. */
+        PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
+        return SECFailure;
+    }
+
+    /* Record the type. */
+    cText->type = plaintext->buf[plaintext->len-1];
+    --plaintext->len;
+
+    return SECSuccess;
+}
+
new file mode 100644
--- /dev/null
+++ b/lib/ssl/tls13con.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * 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 __tls13con_h_
+#define __tls13con_h_
+
+typedef enum {
+    StaticSharedSecret,
+    EphemeralSharedSecret
+} SharedSecretType;
+
+SECStatus tls13_UnprotectRecord(
+    sslSocket* ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
+    SSL3AlertDescription *alert);
+unsigned char *
+tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to);
+
+void tls13_SetHsState(sslSocket *ss, SSL3WaitState ws,
+                      const char *func, const char *file, int line);
+#define TLS13_SET_HS_STATE(ss, ws) \
+    tls13_SetHsState(ss, ws, __func__, __FILE__, __LINE__)
+
+/* Return PR_TRUE if the socket is in one of the given states, else return
+ * PR_FALSE. Only call the macro not the function, because the trailing
+ * wait_invalid is needed to terminate the argument list. */
+PRBool tls13_InHsState(sslSocket *ss, ...);
+#define TLS13_IN_HS_STATE(ss, ...) \
+    tls13_InHsState(ss, __VA_ARGS__, wait_invalid)
+
+SSLHashType tls13_GetHash(sslSocket *ss);
+CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
+void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
+                      SSL3AlertDescription desc);
+SECStatus tls13_SetupClientHello(sslSocket *ss);
+SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
+                                                PRUint32 length,
+                                                SSL3Hashes *hashesPtr);
+SECStatus tls13_HandleClientKeyShare(sslSocket *ss);
+SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
+SECStatus tls13_HandleServerKeyShare(sslSocket *ss);
+SECStatus tls13_AddContextToHashes(sslSocket *ss,
+                                   SSL3Hashes *hashes /* IN/OUT */,
+                                   SSLHashType algorithm, PRBool sending);
+void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
+void tls13_DestroyKeyShares(PRCList *list);
+PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message);
+SECStatus tls13_ProtectRecord(sslSocket *ss,
+                              SSL3ContentType type,
+                              const SSL3Opaque *pIn,
+                              PRUint32 contentLen,
+                              sslBuffer *wrBuf);
+
+#endif /* __tls13con_h_ */
new file mode 100644
--- /dev/null
+++ b/lib/ssl/tls13hkdf.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * TLS 1.3 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/. */
+
+#include "keyhi.h"
+#include "pk11func.h"
+#include "secitem.h"
+#include "sslt.h"
+#include "sslerr.h"
+
+// TODO(ekr@rtfm.com): Export this separately.
+unsigned char *tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to);
+
+/* This table contains the mapping between TLS hash identifiers and the
+ * PKCS#11 identifiers */
+static const struct {
+    SSLHashType hash;
+    CK_MECHANISM_TYPE pkcs11Mech;
+    unsigned int hashSize;
+} kTlsHkdfInfo[] = {
+    { ssl_hash_none, 0, 0 },
+    { ssl_hash_md5, 0, 0 },
+    { ssl_hash_sha1, 0, 0 },
+    { ssl_hash_sha224, 0 },
+    { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 },
+    { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 },
+    { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 }
+};
+
+SECStatus
+tls13_HkdfExtract(PK11SymKey* ikm1, PK11SymKey* ikm2, SSLHashType baseHash,
+                  PK11SymKey **prkp)
+{
+    CK_NSS_HKDFParams params;
+    SECItem paramsi;
+    SECStatus rv;
+    SECItem *salt;
+    PK11SymKey *prk;
+
+    params.bExtract = CK_TRUE;
+    params.bExpand = CK_FALSE;
+    params.pInfo = NULL;
+    params.ulInfoLen = 0UL;
+
+    if (ikm1) {
+        /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary
+         * but is imposed on us by the present HKDF interface. */
+        rv = PK11_ExtractKeyValue(ikm1);
+        if (rv != SECSuccess)
+            return rv;
+
+        salt = PK11_GetKeyData(ikm1);
+        if (!salt)
+            return SECFailure;
+
+        params.pSalt = salt->data;
+        params.ulSaltLen = salt->len;
+        PORT_Assert(salt->len > 0);
+    } else {
+        /* Per documentation for CKM_NSS_HKDF_*:
+         *
+         *  If the optional salt is given, it is used; otherwise, the salt is
+         *  set to a sequence of zeros equal in length to the HMAC output.
+         */
+        params.pSalt = NULL;
+        params.ulSaltLen = 0UL;
+    }
+    paramsi.data = (unsigned char *)&params;
+    paramsi.len = sizeof(params);
+
+    PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech);
+    PORT_Assert(kTlsHkdfInfo[baseHash].hashSize);
+    PORT_Assert(kTlsHkdfInfo[baseHash].hash==baseHash);
+    prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech,
+                      &paramsi, kTlsHkdfInfo[baseHash].pkcs11Mech,
+                      CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize);
+    if (!prk)
+        return SECFailure;
+
+    *prkp = prk;
+    return SECSuccess;
+}
+
+SECStatus
+tls13_HkdfExpandLabel(PK11SymKey* prk, SSLHashType baseHash,
+                      const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+                      const char *label, unsigned int labelLen,
+                      CK_MECHANISM_TYPE algorithm, unsigned int keySize,
+                      PK11SymKey **keyp)
+{
+    CK_NSS_HKDFParams params;
+    SECItem paramsi = {siBuffer, NULL, 0};
+    PRUint8 info[100];
+    PRUint8 *ptr = info;
+    unsigned int infoLen;
+    PK11SymKey *derived;
+    const char *kLabelPrefix = "TLS 1.3, ";
+    const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
+
+    if (handshakeHash) {
+        PORT_Assert(handshakeHashLen == kTlsHkdfInfo[baseHash].hashSize);
+    } else {
+        PORT_Assert(!handshakeHashLen);
+    }
+
+    /*
+     *  [draft-ietf-tls-tls13-11] Section 7.1:
+     *
+     *  HKDF-Expand-Label(Secret, Label, HashValue, Length) =
+     *       HKDF-Expand(Secret, HkdfLabel, Length)
+     *
+     *  Where HkdfLabel is specified as:
+     *
+     *  struct HkdfLabel {
+     *    uint16 length;
+     *    opaque label<9..255>;
+     *    opaque hash_value<0..255>;
+     *  };
+     *
+     *  Where:
+     *  - HkdfLabel.length is Length
+     *  - HkdfLabel.hash_value is HashValue.
+     *  - HkdfLabel.label is "TLS 1.3, " + Label
+     *
+     */
+    infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen;
+    if (infoLen > sizeof(info)) {
+        PORT_Assert(0);
+        goto abort;
+    }
+
+    ptr = tls13_EncodeUintX(keySize, 2, ptr);
+    ptr = tls13_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr);
+    PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen);
+    ptr += kLabelPrefixLen;
+    PORT_Memcpy(ptr, label, labelLen);
+    ptr += labelLen;
+    ptr = tls13_EncodeUintX(handshakeHashLen, 1, ptr);
+    if (handshakeHash) {
+        PORT_Memcpy(ptr, handshakeHash, handshakeHashLen);
+        ptr += handshakeHashLen;
+    }
+    PORT_Assert((ptr - info) == infoLen);
+
+    params.bExtract = CK_FALSE;
+    params.bExpand = CK_TRUE;
+    params.pInfo = info;
+    params.ulInfoLen = infoLen;
+    paramsi.data = (unsigned char *)&params;
+    paramsi.len = sizeof(params);
+
+    derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech,
+                                   &paramsi, algorithm,
+                                   CKA_DERIVE, keySize,
+                                   CKF_SIGN | CKF_VERIFY);
+    if (!derived)
+        return SECFailure;
+
+    *keyp = derived;
+
+    return SECSuccess;
+
+abort:
+    PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+    return SECFailure;
+}
+
+
+SECStatus
+tls13_HkdfExpandLabelRaw(PK11SymKey* prk, SSLHashType baseHash,
+                         const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+                         const char *label, unsigned int labelLen,
+                         unsigned char *output, unsigned int outputLen)
+{
+    PK11SymKey *derived = NULL;
+    SECItem *rawkey;
+    SECStatus rv;
+
+    rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen,
+                               label, labelLen,
+                               kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen,
+                               &derived);
+    rv = PK11_ExtractKeyValue(derived);
+    if (rv != SECSuccess) {
+        goto abort;
+    }
+
+    rawkey = PK11_GetKeyData(derived);
+    if (!rawkey) {
+        goto abort;
+    }
+
+    PORT_Assert(rawkey->len == outputLen);
+    memcpy(output, rawkey->data, outputLen);
+    PK11_FreeSymKey(derived);
+
+    return SECSuccess;
+
+abort:
+    if (derived) {
+        PK11_FreeSymKey(derived);
+    }
+    PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+    return SECFailure;
+}
new file mode 100644
--- /dev/null
+++ b/lib/ssl/tls13hkdf.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * 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 __tls13hkdf_h_
+#define __tls13hkdf_h_
+
+#include "keyhi.h"
+#include "sslt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SECStatus tls13_HkdfExtract(
+    PK11SymKey* ikm1, PK11SymKey* ikm2, SSLHashType baseHash,
+    PK11SymKey **prkp);
+SECStatus tls13_HkdfExpandLabelRaw(
+    PK11SymKey* prk, SSLHashType baseHash,
+    const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+    const char *label, unsigned int labelLen,
+    unsigned char *output, unsigned int outputLen);
+SECStatus tls13_HkdfExpandLabel(
+    PK11SymKey* prk, SSLHashType baseHash,
+    const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+    const char *label, unsigned int labelLen,
+    CK_MECHANISM_TYPE algorithm, unsigned int keySize,
+    PK11SymKey **keyp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif