Bug 1317947 - land NSS 0x5e59e858012d, r=me
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Fri, 09 Dec 2016 23:04:28 +0100
changeset 325611 fb400cfedafabeba3530e1c41cd71524c650ad31
parent 325610 ac2a2ae05c7012f69b8ba5a835625671193a4c8a
child 325612 16720e74a36fed6a0df2843d83d72a9141ea0368
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersme
bugs1317947
milestone53.0a1
Bug 1317947 - land NSS 0x5e59e858012d, r=me
security/nss/TAG-INFO
security/nss/automation/buildbot-slave/build.sh
security/nss/cmd/certutil/keystuff.c
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/strsclnt/strsclnt.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/gtests/ssl_gtest/test_io.cc
security/nss/gtests/ssl_gtest/test_io.h
security/nss/lib/freebl/freebl.gyp
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslnonce.c
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13exthandle.c
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-5f2db99c258f
+5e59e858012d
--- a/security/nss/automation/buildbot-slave/build.sh
+++ b/security/nss/automation/buildbot-slave/build.sh
@@ -238,29 +238,63 @@ test_jss()
 
     grep FAIL ${LOG_TMP} 
     [ $? -eq 1 ] || RET=1
 
     print_result "JSS - tests - ${BITS} bits - ${OPT}" ${RET} 0
     return ${RET}
 }
 
+create_objdir_dist_link()
+{
+    # compute relevant 'dist' OBJDIR_NAME subdirectory names for JSS and NSS
+    OS_TARGET=`uname -s`
+    OS_RELEASE=`uname -r | sed 's/-.*//' | sed 's/-.*//' | cut -d . -f1,2`
+    CPU_TAG=_`uname -m`
+    # OBJDIR_NAME_COMPILER appears to be defined for NSS but not JSS
+    OBJDIR_NAME_COMPILER=_cc
+    LIBC_TAG=_glibc
+    IMPL_STRATEGY=_PTH
+    if [ "${RUN_BITS}" = "64" ]; then
+        OBJDIR_TAG=_${RUN_BITS}_${RUN_OPT}.OBJ
+    else
+        OBJDIR_TAG=_${RUN_OPT}.OBJ
+    fi
+
+    # define NSS_OBJDIR_NAME
+    NSS_OBJDIR_NAME=${OS_TARGET}${OS_RELEASE}${CPU_TAG}${OBJDIR_NAME_COMPILER}
+    NSS_OBJDIR_NAME=${NSS_OBJDIR_NAME}${LIBC_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}
+    print_log "create_objdir_dist_link(): NSS_OBJDIR_NAME='${NSS_OBJDIR_NAME}'"
+
+    # define JSS_OBJDIR_NAME
+    JSS_OBJDIR_NAME=${OS_TARGET}${OS_RELEASE}${CPU_TAG}
+    JSS_OBJDIR_NAME=${JSS_OBJDIR_NAME}${LIBC_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}
+    print_log "create_objdir_dist_link(): JSS_OBJDIR_NAME='${JSS_OBJDIR_NAME}'"
+
+    if [ -e "${HGDIR}/dist/${NSS_OBJDIR_NAME}" ]; then
+        SOURCE=${HGDIR}/dist/${NSS_OBJDIR_NAME}
+        TARGET=${HGDIR}/dist/${JSS_OBJDIR_NAME}
+        ln -s ${SOURCE} ${TARGET} >/dev/null 2>&1
+    fi
+}
+
 build_and_test()
 {
     if [ -n "${BUILD_NSS}" ]; then
         build_nss
         [ $? -eq 0 ] || return 1
     fi
 
     if [ -n "${TEST_NSS}" ]; then
         test_nss
         [ $? -eq 0 ] || return 1
     fi
 
     if [ -n "${BUILD_JSS}" ]; then
+        create_objdir_dist_link
         build_jss
         [ $? -eq 0 ] || return 1
     fi
 
     if [ -n "${TEST_JSS}" ]; then
         test_jss
         [ $? -eq 0 ] || return 1
     fi
--- a/security/nss/cmd/certutil/keystuff.c
+++ b/security/nss/cmd/certutil/keystuff.c
@@ -47,19 +47,20 @@ const SEC_ASN1Template SECKEY_PQGParamsT
     { 0 }
 };
 
 /* returns 0 for success, -1 for failure (EOF encountered) */
 static int
 UpdateRNG(void)
 {
     char randbuf[RAND_BUF_SIZE];
-    int fd, count;
+    int fd;
     int c;
     int rv = 0;
+    size_t count;
 #ifdef XP_UNIX
     cc_t orig_cc_min;
     cc_t orig_cc_time;
     tcflag_t orig_lflag;
     struct termios tio;
 #endif
     char meter[] = {
         "\r|                                                            |"
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -2300,17 +2300,19 @@ main(int argc, char **argv)
             case 'U':
                 configureReuseECDHE = (PORT_Atoi(optstate->value) != 0);
                 break;
 
             case 'V':
                 if (SECU_ParseSSLVersionRangeString(optstate->value,
                                                     enabledVersions, &enabledVersions) !=
                     SECSuccess) {
+                    fprintf(stderr, "Bad version specified.\n");
                     Usage(progName);
+                    exit(1);
                 }
                 break;
 
             case 'W':
                 configureWeakDHE = (PORT_Atoi(optstate->value) != 0);
                 break;
 
             case 'Y':
--- a/security/nss/cmd/strsclnt/strsclnt.c
+++ b/security/nss/cmd/strsclnt/strsclnt.c
@@ -1345,16 +1345,17 @@ main(int argc, char **argv)
             case 'U':
                 ThrottleUp = PR_TRUE;
                 break;
 
             case 'V':
                 if (SECU_ParseSSLVersionRangeString(optstate->value,
                                                     enabledVersions, &enabledVersions) !=
                     SECSuccess) {
+                    fprintf(stderr, "Bad version specified.\n");
                     Usage(progName);
                 }
                 break;
 
             case 'a':
                 sniHostName = PL_strdup(optstate->value);
                 break;
 
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -1605,16 +1605,17 @@ main(int argc, char **argv)
             case 'U':
                 enableSignedCertTimestamps = 1;
                 break;
 
             case 'V':
                 if (SECU_ParseSSLVersionRangeString(optstate->value,
                                                     enabledVersions, &enabledVersions) !=
                     SECSuccess) {
+                    fprintf(stderr, "Bad version specified.\n");
                     Usage(progName);
                 }
                 break;
 
             case 'Y':
                 PrintCipherUsage(progName);
                 exit(0);
                 break;
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -204,16 +204,27 @@ TEST_P(TlsConnectTls13, UnknownAlert) {
 TEST_P(TlsConnectTls13, AlertWrongLevel) {
   Connect();
   SSLInt_SendAlert(server_->ssl_fd(), kTlsAlertWarning,
                    kTlsAlertUnexpectedMessage);
   client_->ExpectReadWriteError();
   client_->WaitForErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT, 2000);
 }
 
+TEST_F(TlsConnectStreamTls13, Tls13FailedWriteSecondFlight) {
+  EnsureTlsSetup();
+  client_->StartConnect();
+  server_->StartConnect();
+  client_->Handshake();
+  server_->Handshake();  // Send first flight.
+  client_->adapter()->CloseWrites();
+  client_->Handshake();  // This will get an error, but shouldn't crash.
+  client_->CheckErrorCode(SSL_ERROR_SOCKET_WRITE_FAILURE);
+}
+
 INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
                                            TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     GenericDatagram, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsModesDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
 
--- a/security/nss/gtests/ssl_gtest/test_io.cc
+++ b/security/nss/gtests/ssl_gtest/test_io.cc
@@ -366,17 +366,17 @@ int32_t DummyPrSocket::Recv(void *buf, i
 
   input_.pop();
   delete front;
 
   return static_cast<int32_t>(count);
 }
 
 int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
-  if (!peer_) {
+  if (!peer_ || !writeable_) {
     PR_SetError(PR_IO_ERROR, 0);
     return -1;
   }
 
   DataBuffer packet(static_cast<const uint8_t *>(buf),
                     static_cast<size_t>(length));
   DataBuffer filtered;
   PacketFilter::Action action = PacketFilter::KEEP;
--- a/security/nss/gtests/ssl_gtest/test_io.h
+++ b/security/nss/gtests/ssl_gtest/test_io.h
@@ -61,30 +61,36 @@ class DummyPrSocket {
   void SetPacketFilter(PacketFilter* filter);
   // Drops peer, packet filter and any outstanding packets.
   void Reset();
 
   void PacketReceived(const DataBuffer& data);
   int32_t Read(void* data, int32_t len);
   int32_t Recv(void* buf, int32_t buflen);
   int32_t Write(const void* buf, int32_t length);
+  void CloseWrites() { writeable_ = false; }
 
   Mode mode() const { return mode_; }
   bool readable() const { return !input_.empty(); }
-  bool writable() { return true; }
 
  private:
   DummyPrSocket(const std::string& name, Mode mode)
-      : name_(name), mode_(mode), peer_(nullptr), input_(), filter_(nullptr) {}
+      : name_(name),
+        mode_(mode),
+        peer_(nullptr),
+        input_(),
+        filter_(nullptr),
+        writeable_(true) {}
 
   const std::string name_;
   Mode mode_;
   DummyPrSocket* peer_;
   std::queue<Packet*> input_;
   PacketFilter* filter_;
+  bool writeable_;
 };
 
 // Marker interface.
 class PollTarget {};
 
 enum Event { READABLE_EVENT, TIMER_EVENT /* Must be last */ };
 
 typedef void (*PollCallback)(PollTarget*, Event);
--- a/security/nss/lib/freebl/freebl.gyp
+++ b/security/nss/lib/freebl/freebl.gyp
@@ -154,18 +154,16 @@
               ],
             }],
           ],
         }],
         [ 'OS=="win"', {
           'sources': [
             #TODO: building with mingw should not need this.
             'ecl/uint128.c',
-            #TODO: clang-cl needs -msse3 here
-            'intel-gcm-wrap.c',
           ],
           'libraries': [
             'advapi32.lib',
           ],
           'conditions': [
             [ 'target_arch=="x64"', {
               'sources': [
                 'arcfour-amd64-masm.asm',
@@ -178,16 +176,26 @@
             }, {
               # not x64
               'sources': [
                 'mpi/mpi_x86_asm.c',
                 'intel-aes-x86-masm.asm',
                 'intel-gcm-x86-masm.asm',
               ],
             }],
+            [ 'cc_is_clang==1', {
+              'dependencies': [
+                'intel-gcm-wrap_c_lib',
+              ],
+            }, {
+              # MSVC
+              'sources': [
+                'intel-gcm-wrap.c',
+              ],
+            }],
           ],
         }],
         ['target_arch=="ia32" or target_arch=="x64"', {
           'sources': [
             # All intel architectures get the 64 bit version
             'ecl/curve25519_64.c',
           ],
         }, {
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -10250,17 +10250,17 @@ ssl3_HandleNewSessionTicket(sslSocket *s
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
         return SECFailure;
     }
 
     /* RFC5077 Section 3.3: "The client MUST NOT treat the ticket as valid
      * until it has verified the server's Finished message." See the comment in
      * ssl3_FinishHandshake for more details.
      */
-    ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time();
+    ss->ssl3.hs.newSessionTicket.received_timestamp = PR_Now();
     if (length < 4) {
         (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
         return SECFailure;
     }
 
     rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 4, &b, &length);
     if (rv != SECSuccess) {
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -367,21 +367,17 @@ ssl3_SendSessionTicketXtn(
          * will only be holding the lock when we are the client and when we're
          * attempting to resume an existing session.
          */
 
         session_ticket = &sid->u.ssl3.locked.sessionTicket;
         if (session_ticket->ticket.data) {
             if (xtnData->ticketTimestampVerified) {
                 extension_length += session_ticket->ticket.len;
-            } else if (!append &&
-                       (session_ticket->ticket_lifetime_hint == 0 ||
-                        (session_ticket->ticket_lifetime_hint +
-                             session_ticket->received_timestamp >
-                         ssl_Time()))) {
+            } else if (!append && ssl_TicketTimeValid(session_ticket)) {
                 extension_length += session_ticket->ticket.len;
                 xtnData->ticketTimestampVerified = PR_TRUE;
             }
         }
     }
 
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -112,18 +112,20 @@ typedef enum {
 
     /* 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
+    no_application_protocol = 120,
 
+    /* invalid alert */
+    no_alert = 256
 } SSL3AlertDescription;
 
 typedef struct {
     SSL3AlertLevel level;
     SSL3AlertDescription description;
 } SSL3Alert;
 
 typedef enum {
@@ -279,17 +281,17 @@ typedef struct {
 /*
  * TLS extension related data structures and constants.
  */
 
 /* SessionTicket extension related data structures. */
 
 /* NewSessionTicket handshake message. */
 typedef struct {
-    PRUint32 received_timestamp;
+    PRTime received_timestamp;
     PRUint32 ticket_lifetime_hint;
     PRUint32 flags;
     PRUint32 ticket_age_add;
     PRUint32 max_early_data_size;
     SECItem ticket;
 } NewSessionTicket;
 
 typedef enum {
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1837,16 +1837,17 @@ SECStatus ssl3_SetCipherSuite(sslSocket 
 
 #ifdef DEBUG
 extern void ssl3_CheckCipherSuiteOrderConsistency();
 #endif
 
 extern int ssl_MapLowLevelError(int hiLevelError);
 
 extern PRUint32 ssl_Time(void);
+extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
 
 extern void SSL_AtomicIncrementLong(long *x);
 
 SECStatus ssl3_ApplyNSSPolicy(void);
 
 extern HASH_HashType
 ssl3_GetTls12HashType(sslSocket *ss);
 
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * This file implements the CLIENT Session ID cache.
  *
  * 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 "cert.h"
@@ -455,16 +456,30 @@ ssl_Time(void)
     now = PR_Now();
     LL_I2L(ll, 1000000L);
     LL_DIV(now, now, ll);
     LL_L2UI(myTime, now);
 #endif
     return myTime;
 }
 
+PRBool
+ssl_TicketTimeValid(const NewSessionTicket *ticket)
+{
+    PRTime endTime;
+
+    if (ticket->ticket_lifetime_hint == 0) {
+        return PR_TRUE;
+    }
+
+    endTime = ticket->received_timestamp +
+              (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_MSEC);
+    return endTime > PR_Now();
+}
+
 void
 ssl3_SetSIDSessionTicket(sslSessionID *sid,
                          /*in/out*/ NewSessionTicket *newSessionTicket)
 {
     PORT_Assert(sid);
     PORT_Assert(newSessionTicket);
     PORT_Assert(newSessionTicket->ticket.data);
     PORT_Assert(newSessionTicket->ticket.len != 0);
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -158,25 +158,31 @@ tls13_FatalError(sslSocket *ss, PRErrorC
 #ifdef TRACE
 #define STATE_CASE(a) \
     case a:           \
         return #a
 static char *
 tls13_HandshakeState(SSL3WaitState st)
 {
     switch (st) {
+        STATE_CASE(idle_handshake);
         STATE_CASE(wait_client_hello);
         STATE_CASE(wait_client_cert);
+        STATE_CASE(wait_client_key);
         STATE_CASE(wait_cert_verify);
+        STATE_CASE(wait_change_cipher);
         STATE_CASE(wait_finished);
         STATE_CASE(wait_server_hello);
+        STATE_CASE(wait_certificate_status);
         STATE_CASE(wait_server_cert);
+        STATE_CASE(wait_server_key);
         STATE_CASE(wait_cert_request);
+        STATE_CASE(wait_hello_done);
+        STATE_CASE(wait_new_session_ticket);
         STATE_CASE(wait_encrypted_extensions);
-        STATE_CASE(idle_handshake);
         default:
             break;
     }
     PORT_Assert(0);
     return "unknown";
 }
 #endif
 
@@ -421,20 +427,17 @@ tls13_SetupClientHello(sslSocket *ss)
         sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     /* The caller must be holding sid->u.ssl3.lock for reading. */
     session_ticket = &sid->u.ssl3.locked.sessionTicket;
     PORT_Assert(session_ticket && session_ticket->ticket.data);
 
-    if (session_ticket->ticket_lifetime_hint == 0 ||
-        (session_ticket->ticket_lifetime_hint +
-             session_ticket->received_timestamp >
-         ssl_Time())) {
+    if (ssl_TicketTimeValid(session_ticket)) {
         ss->statelessResume = PR_TRUE;
     }
 
     if (ss->statelessResume) {
         SECStatus rv;
 
         PORT_Assert(ss->sec.ci.sid);
         rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
@@ -3615,21 +3618,81 @@ tls13_FinishHandshake(sslSocket *ss)
 
     TLS13_SET_HS_STATE(ss, idle_handshake);
 
     ssl_FinishHandshake(ss);
 
     return SECSuccess;
 }
 
+/* Do the parts of sending the client's second round that require
+ * the XmitBuf lock. */
+static SECStatus
+tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
+                             SSL3AlertDescription *sendAlert)
+{
+    SECStatus rv;
+
+    PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+    *sendAlert = internal_error;
+
+    if (ss->ssl3.sendEmptyCert) {
+        ss->ssl3.sendEmptyCert = PR_FALSE;
+        rv = ssl3_SendEmptyCertificate(ss);
+        /* Don't send verify */
+        if (rv != SECSuccess) {
+            return SECFailure; /* error code is set. */
+        }
+    } else if (sendClientCert) {
+        rv = tls13_SendCertificate(ss);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error code is set. */
+        }
+    }
+    if (ss->ssl3.hs.certificateRequest) {
+        PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
+        ss->ssl3.hs.certificateRequest = NULL;
+    }
+
+    if (sendClientCert) {
+        rv = tls13_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
+        SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+        ss->ssl3.clientPrivateKey = NULL;
+        if (rv != SECSuccess) {
+            return SECFailure; /* err is set. */
+        }
+    }
+
+    rv = tls13_SendFinished(ss, ss->ssl3.hs.clientHsTrafficSecret);
+    if (rv != SECSuccess) {
+        return SECFailure; /* err code was set. */
+    }
+    rv = ssl3_FlushHandshake(ss, IS_DTLS(ss) ? ssl_SEND_FLAG_NO_RETRANSMIT : 0);
+    if (rv != SECSuccess) {
+        /* No point in sending an alert here because we're not going to
+         * be able to send it if we couldn't flush the handshake. */
+        *sendAlert = no_alert;
+        return SECFailure;
+    }
+
+    rv = dtls_StartHolddownTimer(ss);
+    if (rv != SECSuccess) {
+        return SECFailure; /* err code was set. */
+    }
+
+    return SECSuccess;
+}
+
 static SECStatus
 tls13_SendClientSecondRound(sslSocket *ss)
 {
     SECStatus rv;
     PRBool sendClientCert;
+    SSL3AlertDescription sendAlert = no_alert;
 
     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;
 
@@ -3680,72 +3743,35 @@ tls13_SendClientSecondRound(sslSocket *s
     rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
                              CipherSpecRead, PR_FALSE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
     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 = tls13_SendCertificate(ss);
-        if (rv != SECSuccess) {
-            goto loser; /* error code is set. */
+    rv = tls13_SendClientSecondFlight(ss, sendClientCert, &sendAlert);
+    ssl_ReleaseXmitBufLock(ss); /*******************************/
+    if (rv != SECSuccess) {
+        if (sendAlert != no_alert) {
+            FATAL_ERROR(ss, PORT_GetError(), sendAlert);
+        } else {
+            LOG_ERROR(ss, PORT_GetError());
         }
-    }
-    if (ss->ssl3.hs.certificateRequest) {
-        PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
-        ss->ssl3.hs.certificateRequest = NULL;
-    }
-
-    if (sendClientCert) {
-        rv = tls13_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, ss->ssl3.hs.clientHsTrafficSecret);
-    if (rv != SECSuccess) {
-        goto loser; /* err code was set. */
-    }
-    rv = ssl3_FlushHandshake(ss, IS_DTLS(ss) ? ssl_SEND_FLAG_NO_RETRANSMIT : 0);
-    if (rv != SECSuccess) {
-        goto loser;
-    }
-
-    rv = dtls_StartHolddownTimer(ss);
-    if (rv != SECSuccess) {
-        goto loser; /* err code was set. */
-    }
-    ssl_ReleaseXmitBufLock(ss); /*******************************/
-
+        return SECFailure;
+    }
     rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
                              CipherSpecWrite, PR_TRUE);
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     /* The handshake is now finished */
     return tls13_FinishHandshake(ss);
-
-loser:
-    ssl_ReleaseXmitBufLock(ss); /*******************************/
-    FATAL_ERROR(ss, PORT_GetError(), internal_error);
-    return SECFailure;
 }
 
 /*
  *  enum { (65535) } TicketExtensionType;
  *
  *  struct {
  *      TicketExtensionType extension_type;
  *      opaque extension_data<0..2^16-1>;
@@ -3862,17 +3888,17 @@ tls13_HandleNewSessionTicket(sslSocket *
         return SECFailure;
     }
     if (!ss->firstHsDone || ss->sec.isServer) {
         FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
                     unexpected_message);
         return SECFailure;
     }
 
-    ticket.received_timestamp = ssl_Time();
+    ticket.received_timestamp = PR_Now();
     rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
                                      &length);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
     ticket.ticket.type = siBuffer;
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -482,17 +482,17 @@ tls13_ClientSendPreSharedKeyXtn(const ss
 
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
-        PRUint32 age;
+        PRTime age;
         unsigned int prefixLength;
         PRUint8 binder[TLS13_MAX_FINISHED_SIZE];
         unsigned int binderLen;
 
         /* extension_type */
         rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
@@ -503,17 +503,18 @@ tls13_ClientSendPreSharedKeyXtn(const ss
         if (rv != SECSuccess)
             goto loser;
         rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data,
                                              session_ticket->ticket.len, 2);
         if (rv != SECSuccess)
             goto loser;
 
         /* Obfuscated age. */
-        age = ssl_Time() - session_ticket->received_timestamp;
+        age = PR_Now() - session_ticket->received_timestamp;
+        age /= PR_USEC_PER_MSEC;
         age += session_ticket->ticket_age_add;
         rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4);
         if (rv != SECSuccess)
             goto loser;
 
         /* Now the binders. */
         prefixLength = ss->ssl3.hs.messages.len;
         rv = tls13_ComputePskBinder(CONST_CAST(sslSocket, ss), PR_TRUE,
@@ -742,21 +743,21 @@ tls13_ClientSendEarlyDataXtn(const sslSo
     if (append) {
         rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
         rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
+
+        xtnData->advertised[xtnData->numAdvertised++] =
+            ssl_tls13_early_data_xtn;
     }
 
-    xtnData->advertised[xtnData->numAdvertised++] =
-        ssl_tls13_early_data_xtn;
-
     return extension_length;
 }
 
 SECStatus
 tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                SECItem *data)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",