Bug 1350602 - TLS 1.3 draft-19 - CertificateRequest, r=ekr NSS_TLS13_DRAFT19_BRANCH
authorMartin Thomson <martin.thomson@gmail.com>
Thu, 06 Apr 2017 10:56:46 +1000
branchNSS_TLS13_DRAFT19_BRANCH
changeset 13321 7060c5e7cf6606c39b49649c39306e77ea4b99f6
parent 13259 61e5d6d62a98d0cdc75360c47da3be351010cdd3
child 13322 4b37459146b294d41774fd1b3c81cb3b0012eaf9
push id2170
push usermartin.thomson@gmail.com
push dateWed, 03 May 2017 22:55:27 +0000
reviewersekr
bugs1350602
Bug 1350602 - TLS 1.3 draft-19 - CertificateRequest, r=ekr I ended up changing the extension handler function a little to deal with messages that allow unknown extensions better. I also changed tls13_ExtensionAllowed to only deal with those extensions that TLS 1.3 cares about. We now don't send point formats in TLS 1.3; I considered doing the same for renegotiation info, but decided against it. Differential Revision: https://nss-review.dev.mozaws.net/D280
gtests/ssl_gtest/ssl_extension_unittest.cc
gtests/ssl_gtest/tls_filter.cc
lib/ssl/ssl3con.c
lib/ssl/ssl3ext.c
lib/ssl/ssl3ext.h
lib/ssl/ssl3exthandle.c
lib/ssl/ssl3exthandle.h
lib/ssl/sslcert.c
lib/ssl/sslimpl.h
lib/ssl/sslt.h
lib/ssl/tls13con.c
lib/ssl/tls13con.h
lib/ssl/tls13exthandle.c
lib/ssl/tls13exthandle.h
--- a/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -1032,22 +1032,26 @@ class TlsBogusExtensionTestPre13 : publi
 class TlsBogusExtensionTest13 : public TlsBogusExtensionTest {
  protected:
   void ConnectAndFail(uint8_t message) override {
     if (message == kTlsHandshakeHelloRetryRequest) {
       ConnectExpectAlert(client_, kTlsAlertUnsupportedExtension);
       return;
     }
 
+    FailWithAlert(kTlsAlertUnsupportedExtension);
+  }
+
+  void FailWithAlert(uint8_t alert) {
     client_->StartConnect();
     server_->StartConnect();
     client_->Handshake();  // ClientHello
     server_->Handshake();  // ServerHello
 
-    client_->ExpectSendAlert(kTlsAlertUnsupportedExtension);
+    client_->ExpectSendAlert(alert);
     client_->Handshake();
     if (mode_ == STREAM) {
       server_->ExpectSendAlert(kTlsAlertBadRecordMac);
     }
     server_->Handshake();
   }
 };
 
@@ -1062,19 +1066,22 @@ TEST_P(TlsBogusExtensionTest13, AddBogus
 TEST_P(TlsBogusExtensionTest13, AddBogusExtensionEncryptedExtensions) {
   Run(kTlsHandshakeEncryptedExtensions);
 }
 
 TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificate) {
   Run(kTlsHandshakeCertificate);
 }
 
+// It's perfectly valid to set unknown extensions in CertificateRequest.
 TEST_P(TlsBogusExtensionTest13, AddBogusExtensionCertificateRequest) {
   server_->RequestClientAuth(false);
-  Run(kTlsHandshakeCertificateRequest);
+  AddFilter(kTlsHandshakeCertificateRequest, 0xff);
+  FailWithAlert(kTlsAlertDecryptError);
+  client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
 }
 
 TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
   server_->ConfigNamedGroups(groups);
 
   Run(kTlsHandshakeHelloRetryRequest);
 }
--- a/gtests/ssl_gtest/tls_filter.cc
+++ b/gtests/ssl_gtest/tls_filter.cc
@@ -443,23 +443,16 @@ bool FindEncryptedExtensions(TlsParser* 
   return true;
 }
 
 static bool FindCertReqExtensions(TlsParser* parser,
                                   const TlsVersioned& header) {
   if (!parser->SkipVariable(1)) {  // request context
     return false;
   }
-  // TODO remove the next two for -19
-  if (!parser->SkipVariable(2)) {  // signature_algorithms
-    return false;
-  }
-  if (!parser->SkipVariable(2)) {  // certificate_authorities
-    return false;
-  }
   return true;
 }
 
 // Only look at the EE cert for this one.
 static bool FindCertificateExtensions(TlsParser* parser,
                                       const TlsVersioned& header) {
   if (!parser->SkipVariable(1)) {  // request context
     return false;
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -6437,18 +6437,18 @@ ssl3_PickServerSignatureScheme(sslSocket
     if (!isTLS12 || !ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) {
         /* If the client didn't provide any signature_algorithms extension then
          * we can assume that they support SHA-1: RFC5246, Section 7.4.1.4.1. */
         return ssl_PickFallbackSignatureScheme(ss, keyPair->pubKey);
     }
 
     /* Sets error code, if needed. */
     return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey,
-                                   ss->xtnData.clientSigSchemes,
-                                   ss->xtnData.numClientSigScheme,
+                                   ss->xtnData.sigSchemes,
+                                   ss->xtnData.numSigSchemes,
                                    PR_FALSE /* requireSha1 */);
 }
 
 static SECStatus
 ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
                               unsigned int numSchemes)
 {
     SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey;
@@ -7298,32 +7298,32 @@ typedef struct dnameNode {
  * 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)
+                                CERTDistNames *ca_list)
 {
     PRUint32 remaining;
     int nnames = 0;
     dnameNode *node;
     SECStatus rv;
     int i;
 
     rv = ssl3_ConsumeHandshakeNumber(ss, &remaining, 2, b, length);
     if (rv != SECSuccess)
         return SECFailure; /* malformed, alert has been sent */
 
     if (remaining > *length)
         goto alert_loser;
 
-    ca_list->head = node = PORT_ArenaZNew(arena, dnameNode);
+    ca_list->head = node = PORT_ArenaZNew(ca_list->arena, dnameNode);
     if (node == NULL)
         goto no_mem;
 
     while (remaining > 0) {
         PRUint32 len;
 
         if (remaining < 2)
             goto alert_loser; /* malformed */
@@ -7339,24 +7339,24 @@ ssl3_ParseCertificateRequestCAs(sslSocke
         node->name.data = *b;
         *b += len;
         *length -= len;
         remaining -= len;
         nnames++;
         if (remaining <= 0)
             break; /* success */
 
-        node->next = PORT_ArenaZNew(arena, dnameNode);
+        node->next = PORT_ArenaZNew(ca_list->arena, dnameNode);
         node = node->next;
         if (node == NULL)
             goto no_mem;
     }
 
     ca_list->nnames = nnames;
-    ca_list->names = PORT_ArenaNewArray(arena, SECItem, nnames);
+    ca_list->names = PORT_ArenaNewArray(ca_list->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;
     }
@@ -7490,17 +7490,17 @@ ssl3_HandleCertificateRequest(sslSocket 
                                        &signatureSchemeCount,
                                        &b, &length);
         if (rv != SECSuccess) {
             PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
             goto loser; /* malformed, alert has been sent */
         }
     }
 
-    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list);
+    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, &ca_list);
     if (rv != SECSuccess)
         goto done; /* alert sent in ssl3_ParseCertificateRequestCAs */
 
     if (length != 0)
         goto alert_loser; /* malformed */
 
     ss->ssl3.hs.ws = wait_hello_done;
 
@@ -9630,20 +9630,20 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, 
 
 static SECStatus
 ssl3_SendCertificateRequest(sslSocket *ss)
 {
     PRBool isTLS12;
     const PRUint8 *certTypes;
     SECStatus rv;
     int length;
-    SECItem *names;
+    const SECItem *names;
     unsigned int calen;
     unsigned int nnames;
-    SECItem *name;
+    const SECItem *name;
     int i;
     int certTypesLength;
     PRUint8 sigAlgs[MAX_SIGNATURE_SCHEMES * 2];
     unsigned int sigAlgsLength = 0;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
                 SSL_GETPID(), ss->fd));
 
@@ -10179,18 +10179,18 @@ SECStatus
 ssl3_SendEmptyCertificate(sslSocket *ss)
 {
     SECStatus rv;
     unsigned int len = 0;
     PRBool isTLS13 = PR_FALSE;
     const SECItem *context;
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-        PORT_Assert(ss->ssl3.hs.certificateRequest);
-        context = &ss->ssl3.hs.certificateRequest->context;
+        PORT_Assert(ss->ssl3.hs.clientCertRequested);
+        context = &ss->xtnData.certReqContext;
         len = context->len + 1;
         isTLS13 = PR_TRUE;
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
     if (rv != SECSuccess) {
         return rv;
     }
@@ -10409,18 +10409,18 @@ ssl3_SendCertificate(sslSocket *ss)
 
 #ifdef NISCC_TEST
     rv = get_fake_cert(&fakeCert, &ndex);
 #endif
 
     if (isTLS13) {
         contextLen = 1; /* Size of the context length */
         if (!ss->sec.isServer) {
-            PORT_Assert(ss->ssl3.hs.certificateRequest);
-            context = ss->ssl3.hs.certificateRequest->context;
+            PORT_Assert(ss->ssl3.hs.clientCertRequested);
+            context = ss->xtnData.certReqContext;
             contextLen += context.len;
         }
     }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
 #ifdef NISCC_TEST
             if (fakeCert.len > 0 && i == ndex) {
                 certChainLen += fakeCert.len + 3;
@@ -12884,17 +12884,16 @@ ssl3_InitState(sslSocket *ss)
     ss->ssl3.hs.resumptionMasterSecret = NULL;
     ss->ssl3.hs.dheSecret = NULL;
     ss->ssl3.hs.pskBinderKey = NULL;
     ss->ssl3.hs.clientEarlyTrafficSecret = NULL;
     ss->ssl3.hs.clientHsTrafficSecret = NULL;
     ss->ssl3.hs.serverHsTrafficSecret = NULL;
     ss->ssl3.hs.clientTrafficSecret = NULL;
     ss->ssl3.hs.serverTrafficSecret = NULL;
-    ss->ssl3.hs.certificateRequest = NULL;
     PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
 
     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,
@@ -13226,21 +13225,16 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
     SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE);
 
-    if (ss->ssl3.hs.certificateRequest) {
-        PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
-        ss->ssl3.hs.certificateRequest = NULL;
-    }
-
     /* free up the CipherSpecs */
     ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/);
     ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE /*freeSrvName*/);
 
     /* Destroy the DTLS data */
     if (IS_DTLS(ss)) {
         dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
         if (ss->ssl3.hs.recvdFragments.buf) {
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -26,17 +26,17 @@ static const ssl3ExtensionHandler client
     { ssl_supported_groups_xtn, &ssl_HandleSupportedGroupsXtn },
     { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
     { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { 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_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
     { ssl_tls13_psk_key_exchange_modes_xtn,
       &tls13_ServerHandlePskKeyExchangeModesXtn },
     { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn },
@@ -83,30 +83,33 @@ static const ssl3ExtensionHandler newSes
 /* This table is used by the client to handle server certificates in TLS 1.3 */
 static const ssl3ExtensionHandler serverCertificateHandlers[] = {
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
     { -1, NULL }
 };
 
 static const ssl3ExtensionHandler certificateRequestHandlers[] = {
+    { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
+    { ssl_tls13_certificate_authorities_xtn,
+      &tls13_ClientHandleCertAuthoritiesXtn },
     { -1, NULL }
 };
 
 /* Tables of functions to format TLS hello extensions, one function per
  * extension.
  * These static tables are for the formatting of client hello extensions.
  * The server's table of hello senders is dynamic, in the socket struct,
  * and sender functions are registered there.
  * NB: the order of these extensions can have an impact on compatibility. Some
  * servers (e.g. Tomcat) will terminate the connection if the last extension in
  * the client hello is empty (for example, the extended master secret
  * extension, if it were listed last). See bug 1243641.
  */
-static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] =
+static const ssl3HelloExtensionSender clientHelloSendersTLS[] =
     {
       { ssl_server_name_xtn, &ssl3_SendServerNameXtn },
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
       { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
       { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
       { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
       { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
@@ -117,29 +120,29 @@ static const ssl3HelloExtensionSender cl
       { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
       { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
        * client hello is empty. They are not intolerant of TLS 1.2, so list
        * signature_algorithms at the end. See bug 1243641. */
       { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
       { ssl_tls13_short_header_xtn, &tls13_SendShortHeaderXtn },
-      { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
+      { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
       { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
       { ssl_tls13_psk_key_exchange_modes_xtn,
         &tls13_ClientSendPskKeyExchangeModesXtn },
       { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension },
       /* The pre_shared_key extension MUST be last. */
       { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
-      /* any extra entries will appear as { 0, NULL }    */
+      { 0, NULL }
     };
 
-static const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = {
-    { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }
-    /* any extra entries will appear as { 0, NULL }    */
+static const ssl3HelloExtensionSender clientHelloSendersSSL3[] = {
+    { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
+    { 0, NULL }
 };
 
 static PRBool
 arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type)
 {
     unsigned int i;
     for (i = 0; i < len; i++) {
         if (ex_type == array[i])
@@ -253,16 +256,21 @@ SECStatus
 ssl3_HandleParsedExtensions(sslSocket *ss,
                             SSL3HandshakeType handshakeMessage)
 {
     const ssl3ExtensionHandler *handlers;
     /* HelloRetryRequest doesn't set ss->version. It might be safe to
      * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */
     PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) ||
                      (handshakeMessage == hello_retry_request);
+    /* The following messages can include extensions that were not included in
+     * the original ClientHello. */
+    PRBool allowNotOffered = (handshakeMessage == client_hello) ||
+                             (handshakeMessage == certificate_request) ||
+                             (handshakeMessage == new_session_ticket);
     PRCList *cursor;
 
     switch (handshakeMessage) {
         case client_hello:
             handlers = clientHelloHandlers;
             break;
         case new_session_ticket:
             PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
@@ -297,35 +305,45 @@ ssl3_HandleParsedExtensions(sslSocket *s
 
     for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions);
          cursor != &ss->ssl3.hs.remoteExtensions;
          cursor = PR_NEXT_LINK(cursor)) {
         TLSExtension *extension = (TLSExtension *)cursor;
         const ssl3ExtensionHandler *handler;
 
         /* Check whether the server sent an extension which was not advertised
-         * in the ClientHello */
-        if (!ss->sec.isServer &&
-            !ssl3_ClientExtensionAdvertised(ss, extension->type) &&
-            (handshakeMessage != new_session_ticket) &&
-            (extension->type != ssl_tls13_cookie_xtn)) {
+         * in the ClientHello.
+         *
+         * Note that a TLS 1.3 server should check if CertificateRequest
+         * extensions were sent.  But the extensions used for CertificateRequest
+         * do not have any response, so we rely on
+         * ssl3_ClientExtensionAdvertised to return false on the server.  That
+         * results in the server only rejecting any extension. */
+        if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn) &&
+            !ssl3_ClientExtensionAdvertised(ss, extension->type)) {
             (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
             PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
             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;
+        if (isTLS13) {
+            switch (tls13_ExtensionStatus(extension->type, handshakeMessage)) {
+                case tls13_extension_allowed:
+                    break;
+                case tls13_extension_unknown:
+                    if (allowNotOffered) {
+                        continue; /* Skip over unknown extensions. */
+                    }
+                /* Fall through. */
+                case tls13_extension_disallowed:
+                    tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
+                                     unsupported_extension);
+                    return SECFailure;
             }
-            tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
-                             unsupported_extension);
-            return SECFailure;
         }
 
         /* Special check for this being the last extension if it's
          * PreSharedKey */
         if (ss->sec.isServer && isTLS13 &&
             (extension->type == ssl_tls13_pre_shared_key_xtn) &&
             (PR_NEXT_LINK(cursor) != &ss->ssl3.hs.remoteExtensions)) {
             tls13_FatalError(ss,
@@ -345,16 +363,17 @@ ssl3_HandleParsedExtensions(sslSocket *s
                                             &extension->data);
                 if (rv != SECSuccess) {
                     if (!ss->ssl3.fatalAlertSent) {
                         /* send a generic alert if the handler didn't already */
                         (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
                     }
                     return SECFailure;
                 }
+                break;
             }
         }
     }
     return SECSuccess;
 }
 
 /* Syntactic sugar around ssl3_ParseExtensions and
  * ssl3_HandleParsedExtensions. */
@@ -385,24 +404,31 @@ ssl3_RegisterExtensionSender(const sslSo
                              PRUint16 ex_type,
                              ssl3HelloExtensionSenderFunc cb)
 {
     int i;
     ssl3HelloExtensionSender *sender;
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         sender = &xtnData->serverHelloSenders[0];
     } else {
-        if (tls13_ExtensionAllowed(ex_type, server_hello)) {
-            PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions));
+        if (tls13_ExtensionStatus(ex_type, server_hello) ==
+            tls13_extension_allowed) {
+            PORT_Assert(tls13_ExtensionStatus(ex_type, encrypted_extensions) ==
+                        tls13_extension_disallowed);
             sender = &xtnData->serverHelloSenders[0];
-        } else if (tls13_ExtensionAllowed(ex_type, certificate)) {
+        } else if (tls13_ExtensionStatus(ex_type, encrypted_extensions) ==
+                   tls13_extension_allowed) {
+            sender = &xtnData->encryptedExtensionsSenders[0];
+        } else if (tls13_ExtensionStatus(ex_type, certificate) ==
+                   tls13_extension_allowed) {
             sender = &xtnData->certificateSenders[0];
         } else {
-            PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions));
-            sender = &xtnData->encryptedExtensionsSenders[0];
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
         }
     }
     for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
         if (!sender->ex_sender) {
             sender->ex_type = ex_type;
             sender->ex_sender = cb;
             return SECSuccess;
         }
@@ -419,34 +445,33 @@ ssl3_RegisterExtensionSender(const sslSo
 }
 
 /* call each of the extension senders and return the accumulated length */
 PRInt32
 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
                                const ssl3HelloExtensionSender *sender)
 {
     PRInt32 total_exten_len = 0;
-    int i;
 
     if (!sender) {
         if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
             sender = &clientHelloSendersTLS[0];
         } else {
             sender = &clientHelloSendersSSL3[0];
         }
     }
 
-    for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
-        if (sender->ex_sender) {
-            PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes);
-            if (extLen < 0)
-                return -1;
-            maxBytes -= extLen;
-            total_exten_len += extLen;
+    while (sender->ex_sender) {
+        PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes);
+        if (extLen < 0) {
+            return -1;
         }
+        maxBytes -= extLen;
+        total_exten_len += extLen;
+        ++sender;
     }
     return total_exten_len;
 }
 
 void
 ssl3_DestroyRemoteExtensions(PRCList *list)
 {
     PRCList *cur_p;
@@ -470,19 +495,24 @@ ssl3_InitExtensionData(TLSExtensionData 
 
 /* Free everything that has been allocated and then reset back to
  * the starting state. */
 void
 ssl3_ResetExtensionData(TLSExtensionData *xtnData)
 {
     /* Clean up. */
     ssl3_FreeSniNameArray(xtnData);
-    PORT_Free(xtnData->clientSigSchemes);
+    PORT_Free(xtnData->sigSchemes);
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
     tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
+    SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE);
+    if (xtnData->certReqAuthorities.arena) {
+        PORT_FreeArena(xtnData->certReqAuthorities.arena, PR_FALSE);
+        xtnData->certReqAuthorities.arena = NULL;
+    }
 
     /* Now reinit. */
     ssl3_InitExtensionData(xtnData);
 }
 
 /* Thunks to let extension handlers operate on const sslSocket* objects. */
 SECStatus
 ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
--- a/lib/ssl/ssl3ext.h
+++ b/lib/ssl/ssl3ext.h
@@ -81,20 +81,23 @@ struct TLSExtensionDataStr {
      * nor copied: the pointer points to the handshake message buffer and is
      * only valid in the scope of ssl3_HandleServerHello.
      */
     SECItem signedCertTimestamps;
 
     PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */
 
     /* clientSigAndHash contains the contents of the signature_algorithms
-     * extension (if any) from the client. This is only valid for TLS 1.2
-     * or later. */
-    SSLSignatureScheme *clientSigSchemes;
-    unsigned int numClientSigScheme;
+     * extension (if any) the other side supports. This is only valid for TLS
+     * 1.2 or later. In TLS 1.3, it is also used for CertificateRequest. */
+    SSLSignatureScheme *sigSchemes;
+    unsigned int numSigSchemes;
+
+    SECItem certReqContext;
+    CERTDistNames certReqAuthorities;
 
     /* In a client: if the server supports Next Protocol Negotiation, then
      * this is the protocol that was negotiated.
      */
     SECItem nextProto;
     SSLNextProtoState nextProtoState;
 
     PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
--- a/lib/ssl/ssl3exthandle.c
+++ b/lib/ssl/ssl3exthandle.c
@@ -375,16 +375,18 @@ ssl_AlpnTagAllowed(const sslSocket *ss, 
     return PR_FALSE;
 }
 
 /* handle an incoming Next Protocol Negotiation extension. */
 SECStatus
 ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
     if (ss->firstHsDone || data->len != 0) {
         /* Clients MUST send an empty NPN extension, if any. */
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
@@ -516,16 +518,17 @@ ssl3_ServerHandleAppProtoXtn(const sslSo
     }
     return SECSuccess;
 }
 
 SECStatus
 ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
     PORT_Assert(!ss->firstHsDone);
 
     if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
         /* If the server negotiated ALPN then it has already told us what
          * protocol to use, so it doesn't make sense for us to try to negotiate
          * a different one by sending the NPN handshake message. However, if
          * we've negotiated NPN then we're required to send the NPN handshake
          * message. Thus, these two extensions cannot both be negotiated on the
@@ -1271,16 +1274,18 @@ loser:
 
 /* When a client receives a SessionTicket extension a NewSessionTicket
  * message is expected during the handshake.
  */
 SECStatus
 ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
     if (data->len != 0) {
         return SECSuccess; /* Ignore the extension. */
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
@@ -1735,16 +1740,17 @@ loser:
 
     return rv;
 }
 
 SECStatus
 ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     /* Ignore the SessionTicket extension if processing is disabled. */
     if (!ss->opt.enableSessionTickets) {
         return SECSuccess;
     }
 
     /* If we are doing TLS 1.3, then ignore this. */
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -1834,21 +1840,24 @@ ssl3_SendRenegotiationInfoXtn(
                 ssl_renegotiation_info_xtn;
         }
     }
     return needed;
 }
 
 /* This function runs in both the client and server.  */
 SECStatus
-ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv = SECSuccess;
     PRUint32 len = 0;
 
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
     if (ss->firstHsDone) {
         len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
                                : ss->ssl3.hs.finishedBytes * 2;
     }
     if (data->len != 1 + len || data->data[0] != len) {
         ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
@@ -2087,38 +2096,39 @@ ssl3_ServerHandleUseSRTPXtn(const sslSoc
     xtnData->dtlsSRTPCipherSuite = cipher;
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
 
     return ssl3_RegisterExtensionSender(ss, xtnData,
                                         ssl_use_srtp_xtn,
                                         ssl3_ServerSendUseSRTPXtn);
 }
 
-/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension
- * from a client.
- * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+/* ssl3_HandleSigAlgsXtn handles the signature_algorithms extension from a
+ * client.  In TLS 1.3, the client uses this to parse CertificateRequest
+ * extensions.  See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 SECStatus
-ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                      PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
 
     /* Ignore this extension if we aren't doing TLS 1.2 or greater. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
         return SECSuccess;
     }
 
-    if (xtnData->clientSigSchemes) {
-        PORT_Free(xtnData->clientSigSchemes);
-        xtnData->clientSigSchemes = NULL;
+    if (xtnData->sigSchemes) {
+        PORT_Free(xtnData->sigSchemes);
+        xtnData->sigSchemes = NULL;
     }
     rv = ssl_ParseSignatureSchemes(ss, NULL,
-                                   &xtnData->clientSigSchemes,
-                                   &xtnData->numClientSigScheme,
+                                   &xtnData->sigSchemes,
+                                   &xtnData->numSigSchemes,
                                    &data->data, &data->len);
-    if (rv != SECSuccess || xtnData->numClientSigScheme == 0) {
+    if (rv != SECSuccess || xtnData->numSigSchemes == 0) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
     /* Check for trailing data. */
     if (data->len != 0) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
@@ -2128,17 +2138,18 @@ ssl3_ServerHandleSigAlgsXtn(const sslSoc
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
  * 1.2 ClientHellos. */
 PRInt32
-ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                    PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2];
     PRUint32 len;
     SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
         return 0;
@@ -2292,16 +2303,18 @@ ssl3_SendExtendedMasterSecretXtn(const s
 loser:
     return -1;
 }
 
 SECStatus
 ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                    SECItem *data)
 {
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) {
         return SECSuccess;
     }
 
     if (!ss->opt.enableExtendedMS) {
         return SECSuccess;
     }
 
@@ -2443,16 +2456,18 @@ ssl3_ServerHandleSignedCertTimestampXtn(
  */
 SECStatus
 ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                     PRUint16 ex_type,
                                     SECItem *data)
 {
     int i;
 
+    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
+
     if (data->len < 2 || data->len > 255 || !data->data ||
         data->len != (unsigned int)data->data[0] + 1) {
         ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
     for (i = data->len; --i > 0;) {
         if (data->data[i] == 0) {
             /* indicate that we should send a reply */
--- a/lib/ssl/ssl3exthandle.h
+++ b/lib/ssl/ssl3exthandle.h
@@ -39,20 +39,20 @@ PRInt32 ssl3_ServerSendStatusRequestXtn(
                                         PRBool append, PRUint32 maxBytes);
 SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type, SECItem *data);
 SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type,
                                             SECItem *data);
 PRInt32 ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                         PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                  PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
-                                      SECItem *data);
+PRInt32 ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            PRBool append, PRUint32 maxBytes);
+SECStatus ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                PRUint16 ex_type, SECItem *data);
 
 PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
                                         PRBool append, PRUint32 maxBytes);
 
 PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                               PRBool append,
                                               PRUint32 maxBytes);
 SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
--- a/lib/ssl/sslcert.c
+++ b/lib/ssl/sslcert.c
@@ -41,33 +41,33 @@ ssl_SetupCAListOnce(void *arg)
     if (SECSuccess == rv) {
         ssl_server_ca_list.names = CERT_GetSSLCACerts(dbHandle);
         return PR_SUCCESS;
     }
     return PR_FAILURE;
 }
 
 SECStatus
-ssl_SetupCAList(sslSocket *ss)
+ssl_SetupCAList(const sslSocket *ss)
 {
     if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup,
                                          &ssl_SetupCAListOnce,
                                          (void *)(ss->dbHandle))) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
     return SECSuccess;
 }
 
 SECStatus
-ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen,
-                             SECItem **names, unsigned int *nnames)
+ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calen,
+                             const SECItem **names, unsigned int *nnames)
 {
-    SECItem *name;
-    CERTDistNames *ca_list;
+    const SECItem *name;
+    const CERTDistNames *ca_list;
     unsigned int i;
 
     *calen = 0;
     *names = NULL;
     *nnames = 0;
 
     /* ssl3.ca_list is initialized to NULL, and never changed. */
     ca_list = ss->ssl3.ca_list;
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -755,25 +755,16 @@ typedef struct TLS13EarlyDataStr {
 
 typedef enum {
     handshake_hash_unknown = 0,
     handshake_hash_combo = 1,  /* The MD5/SHA-1 combination */
     handshake_hash_single = 2, /* A single hash */
     handshake_hash_record
 } SSL3HandshakeHashType;
 
-/* This holds state for TLS 1.3 CertificateRequest handling. */
-typedef struct TLS13CertificateRequestStr {
-    PLArenaPool *arena;
-    SECItem context;
-    SSLSignatureScheme *signatureSchemes;
-    unsigned int signatureSchemeCount;
-    CERTDistNames ca_list;
-} TLS13CertificateRequest;
-
 /*
 ** 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; /* May also contain SSL3WaitState | 0x80 for TLS 1.3 */
@@ -864,30 +855,29 @@ typedef struct SSL3HandshakeStateStr {
     PK11SymKey *pskBinderKey;             /* Used to compute the PSK binder. */
     PK11SymKey *clientEarlyTrafficSecret; /* The secret we use for 0-RTT. */
     PK11SymKey *clientHsTrafficSecret;    /* The source keys for handshake */
     PK11SymKey *serverHsTrafficSecret;    /* traffic keys. */
     PK11SymKey *clientTrafficSecret;      /* The source keys for application */
     PK11SymKey *serverTrafficSecret;      /* traffic keys */
     PK11SymKey *earlyExporterSecret;      /* for 0-RTT exporters */
     PK11SymKey *exporterSecret;           /* for exporters */
-    /* The certificate request from the server. */
-    TLS13CertificateRequest *certificateRequest;
-    PRCList cipherSpecs;            /* The cipher specs in the sequence they
+    PRCList cipherSpecs;                  /* The cipher specs in the sequence they
                                      * will be applied. */
-    sslZeroRttState zeroRttState;   /* Are we doing a 0-RTT handshake? */
-    sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */
-    ssl3CipherSuite zeroRttSuite;   /* The cipher suite we used for 0-RTT. */
-    PRCList bufferedEarlyData;      /* Buffered TLS 1.3 early data
+    sslZeroRttState zeroRttState;         /* Are we doing a 0-RTT handshake? */
+    sslZeroRttIgnore zeroRttIgnore;       /* Are we ignoring 0-RTT? */
+    ssl3CipherSuite zeroRttSuite;         /* The cipher suite we used for 0-RTT. */
+    PRCList bufferedEarlyData;            /* Buffered TLS 1.3 early data
                                      * on server.*/
-    PRBool helloRetry;              /* True if HelloRetryRequest has been sent
+    PRBool helloRetry;                    /* True if HelloRetryRequest has been sent
                                      * or received. */
-    ssl3KEADef kea_def_mutable;     /* Used to hold the writable kea_def
+    PRBool clientCertRequested;           /* True if CertificateRequest received. */
+    ssl3KEADef kea_def_mutable;           /* Used to hold the writable kea_def
                                      * we use for TLS 1.3 */
-    PRBool shortHeaders;            /* Assigned if we are doing short headers. */
+    PRBool shortHeaders;                  /* Assigned if we are doing short headers. */
 } SSL3HandshakeState;
 
 /*
 ** This is the "ssl3" struct, as in "ss->ssl3".
 ** note:
 ** usually,   crSpec == cwSpec and prSpec == pwSpec.
 ** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
 ** But there are never more than 2 actual specs.
@@ -1787,21 +1777,22 @@ SECStatus ssl3_HandleNoCertificate(sslSo
 SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
 void ssl3_CleanupPeerCerts(sslSocket *ss);
 SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
 SECStatus ssl3_AuthCertificate(sslSocket *ss);
 SECStatus ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b,
                                     PRUint32 length);
 SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf,
                              unsigned maxLen, PRUint32 *len);
-SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp,
-                                       SECItem **namesp, unsigned int *nnamesp);
+SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
+                                       unsigned int *calenp,
+                                       const SECItem **namesp,
+                                       unsigned int *nnamesp);
 SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b,
-                                          PRUint32 *length, PLArenaPool *arena,
-                                          CERTDistNames *ca_list);
+                                          PRUint32 *length, CERTDistNames *ca_list);
 SECStatus ssl3_CompleteHandleCertificateRequest(
     sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
     unsigned int signatureSchemeCount, CERTDistNames *ca_list);
 SECStatus ssl3_SendServerHello(sslSocket *ss);
 SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
                                       ssl3CipherSpec *spec,
                                       SSL3Hashes *hashes,
                                       PRUint32 sender);
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -397,16 +397,17 @@ typedef enum {
     ssl_session_ticket_xtn = 35,
     ssl_tls13_key_share_xtn = 40,
     ssl_tls13_pre_shared_key_xtn = 41,
     ssl_tls13_early_data_xtn = 42,
     ssl_tls13_supported_versions_xtn = 43,
     ssl_tls13_cookie_xtn = 44,
     ssl_tls13_psk_key_exchange_modes_xtn = 45,
     ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
+    ssl_tls13_certificate_authorities_xtn = 47,
     ssl_next_proto_nego_xtn = 13172,
     ssl_renegotiation_info_xtn = 0xff01,
     ssl_tls13_short_header_xtn = 0xff03
 } SSLExtensionType;
 
 /* This is the old name for the supported_groups extensions. */
 #define ssl_elliptic_curves_xtn ssl_supported_groups_xtn
 
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -12,16 +12,17 @@
 #include "keyhi.h"
 #include "pk11func.h"
 #include "prerr.h"
 #include "secitem.h"
 #include "secmod.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "sslerr.h"
+#include "ssl3exthandle.h"
 #include "tls13hkdf.h"
 #include "tls13con.h"
 #include "tls13exthandle.h"
 
 typedef enum {
     TrafficKeyClearText = 0,
     TrafficKeyEarlyApplicationData = 1,
     TrafficKeyHandshake = 2,
@@ -1199,18 +1200,18 @@ tls13_SelectServerCert(sslSocket *ss)
 
         if (SSL_CERT_IS_ONLY(cert, ssl_auth_rsa_decrypt)) {
             continue;
         }
 
         rv = ssl_PickSignatureScheme(ss,
                                      cert->serverKeyPair->pubKey,
                                      cert->serverKeyPair->privKey,
-                                     ss->xtnData.clientSigSchemes,
-                                     ss->xtnData.numClientSigScheme,
+                                     ss->xtnData.sigSchemes,
+                                     ss->xtnData.numSigSchemes,
                                      PR_FALSE);
         if (rv == SECSuccess) {
             /* Found one. */
             ss->sec.serverCert = cert;
             ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
                 ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
             ss->sec.authKeyBits = cert->serverKeyBits;
             return SECSuccess;
@@ -1593,16 +1594,22 @@ tls13_HandleClientKeyShare(sslSocket *ss
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set already. */
     }
 
     rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys);
     return rv; /* Error code set already. */
 }
 
+static const ssl3HelloExtensionSender tls13_cert_req_senders[] = {
+    { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
+    { ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn },
+    { 0, NULL }
+};
+
 /*
  *     [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>;
@@ -1615,66 +1622,46 @@ tls13_HandleClientKeyShare(sslSocket *ss
  *         DistinguishedName certificate_authorities<0..2^16-1>;
  *         CertificateExtension certificate_extensions<0..2^16-1>;
  *     } CertificateRequest;
  */
 static SECStatus
 tls13_SendCertificateRequest(sslSocket *ss)
 {
     SECStatus rv;
-    unsigned int calen;
-    SECItem *names;
-    unsigned int nnames;
-    SECItem *name;
-    int i;
-    PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2];
-    unsigned int sigSchemesLength = 0;
-    int length;
+    PRInt32 extLen;
 
     SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
                 SSL_GETPID(), ss->fd));
 
-    rv = ssl3_EncodeSigAlgs(ss, sigSchemes, sizeof(sigSchemes),
-                            &sigSchemesLength);
-    if (rv != SECSuccess) {
-        return rv;
-    }
-
-    rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
-    if (rv != SECSuccess) {
-        return rv;
-    }
-    length = 1 + 0 /* length byte for empty request context */ +
-             2 + sigSchemesLength + 2 + calen + 2;
-
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
+    extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, 0xffff,
+                                            tls13_cert_req_senders);
+    PORT_Assert(extLen > 0); /* These can't be empty. */
+
+    rv = ssl3_AppendHandshakeHeader(ss, certificate_request,
+                                    1 + 0 + /* empty request context */
+                                        2 + extLen /* len + extensions */);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
+
+    /* Context. */
     rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
-    rv = ssl3_AppendHandshakeVariable(ss, sigSchemes, sigSchemesLength, 2);
-    if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
-    }
-    rv = ssl3_AppendHandshakeNumber(ss, calen, 2);
+    /* Extensions. */
+    rv = ssl3_AppendHandshakeNumber(ss, extLen, 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. */
+    extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extLen,
+                                            tls13_cert_req_senders);
+    if (extLen < 0) {
+        return SECFailure; /* rely on the extension sender setting code */
     }
 
     return SECSuccess;
 }
 
 SECStatus
 tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
@@ -1763,19 +1750,17 @@ tls13_HandleHelloRetryRequest(sslSocket 
 
     return SECSuccess;
 }
 
 static SECStatus
 tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus rv;
-    TLS13CertificateRequest *certRequest = NULL;
     SECItem context = { siBuffer, NULL, 0 };
-    PLArenaPool *arena;
     SECItem extensionsData = { siBuffer, NULL, 0 };
 
     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));
 
@@ -1784,81 +1769,61 @@ tls13_HandleCertificateRequest(sslSocket
                               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);
-    PORT_Assert(ss->ssl3.hs.certificateRequest == NULL);
-
-    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-    if (!arena) {
-        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
-        return SECFailure;
-    }
+    PORT_Assert(!ss->ssl3.hs.clientCertRequested);
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
-    if (rv != SECSuccess)
-        goto loser;
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
 
     /* We don't support post-handshake client auth, the certificate request
-     * context must always be null. */
+     * context must always be empty. */
     if (context.len > 0) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
-        goto loser;
-    }
-
-    certRequest = PORT_ArenaZNew(arena, TLS13CertificateRequest);
-    if (!certRequest)
-        goto loser;
-    certRequest->arena = arena;
-    certRequest->ca_list.arena = arena;
-
-    rv = ssl_ParseSignatureSchemes(ss, arena,
-                                   &certRequest->signatureSchemes,
-                                   &certRequest->signatureSchemeCount,
-                                   &b, &length);
-    if (rv != SECSuccess || certRequest->signatureSchemeCount == 0) {
-        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
-                    decode_error);
-        goto loser;
-    }
-
-    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena,
-                                         &certRequest->ca_list);
-    if (rv != SECSuccess)
-        goto loser; /* alert already sent */
-
-    /* Verify that the extensions are sane. */
+        return SECFailure;
+    }
+
     rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length);
     if (rv != SECSuccess) {
-        goto loser;
-    }
-
-    /* Process all the extensions (note: currently a no-op). */
+        return SECFailure;
+    }
+
+    if (length) {
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error);
+        return SECFailure;
+    }
+
+    /* Process all the extensions. */
     rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len,
                                certificate_request);
     if (rv != SECSuccess) {
-        goto loser;
-    }
-
-    rv = SECITEM_CopyItem(arena, &certRequest->context, &context);
-    if (rv != SECSuccess)
-        goto loser;
-
+        return SECFailure;
+    }
+
+    if (!ss->xtnData.numSigSchemes) {
+        FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
+                    missing_extension);
+        return SECFailure;
+    }
+
+    rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &context);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    ss->ssl3.hs.clientCertRequested = PR_TRUE;
     TLS13_SET_HS_STATE(ss, wait_server_cert);
-    ss->ssl3.hs.certificateRequest = certRequest;
-
     return SECSuccess;
-
-loser:
-    PORT_FreeArena(arena, PR_FALSE);
-    return SECFailure;
 }
 
 static SECStatus
 tls13_SendEncryptedServerSequence(sslSocket *ss)
 {
     SECStatus rv;
 
     rv = tls13_ComputeHandshakeSecrets(ss);
@@ -2210,30 +2175,29 @@ tls13_SendCertificate(sslSocket *ss)
     }
 
     /* Get the extensions length. This only applies to the leaf cert,
      * because we don't yet send extensions for non-leaf certs. */
     extensionsLen = ssl3_CallHelloExtensionSenders(
         ss, PR_FALSE, maxBytes, &ss->xtnData.certificateSenders[0]);
 
     if (!ss->sec.isServer) {
-        PORT_Assert(ss->ssl3.hs.certificateRequest);
-        context = ss->ssl3.hs.certificateRequest->context;
+        PORT_Assert(ss->ssl3.hs.clientCertRequested);
+        context = ss->xtnData.certReqContext;
     }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
             certChainLen +=
                 3 + certChain->certs[i].len + /* cert length + cert */
                 2 + (!i ? extensionsLen : 0); /* extensions length + extensions */
         }
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, certificate,
-                                    1 + context.len +
-                                        3 + certChainLen);
+                                    1 + context.len + 3 + certChainLen);
     if (rv != SECSuccess) {
         return SECFailure; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, context.data,
                                       context.len, 1);
     if (rv != SECSuccess) {
         return SECFailure; /* err set by AppendHandshake. */
@@ -3324,23 +3288,21 @@ tls13_HandleCertificateVerify(sslSocket 
     }
 
     /* Set the auth type. */
     if (!ss->sec.isServer) {
         ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
     }
 
     /* Request a client certificate now if one was requested. */
-    if (ss->ssl3.hs.certificateRequest) {
-        TLS13CertificateRequest *req = ss->ssl3.hs.certificateRequest;
-
+    if (ss->ssl3.hs.clientCertRequested) {
         PORT_Assert(!ss->sec.isServer);
-        rv = ssl3_CompleteHandleCertificateRequest(ss, req->signatureSchemes,
-                                                   req->signatureSchemeCount,
-                                                   &req->ca_list);
+        rv = ssl3_CompleteHandleCertificateRequest(
+            ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
+            &ss->xtnData.certReqAuthorities);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             return rv;
         }
     }
 
     TLS13_SET_HS_STATE(ss, wait_finished);
 
@@ -3675,19 +3637,25 @@ tls13_SendClientSecondFlight(sslSocket *
             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 (ss->ssl3.hs.clientCertRequested) {
+        SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+        if (ss->xtnData.certReqAuthorities.arena) {
+            PORT_FreeArena(ss->xtnData.certReqAuthorities.arena, PR_FALSE);
+            ss->xtnData.certReqAuthorities.arena = NULL;
+        }
+        PORT_Memset(&ss->xtnData.certReqAuthorities, 0,
+                    sizeof(ss->xtnData.certReqAuthorities));
+        ss->ssl3.hs.clientCertRequested = PR_FALSE;
     }
 
     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. */
@@ -3941,17 +3909,17 @@ tls13_HandleNewSessionTicket(sslSocket *
     if (rv != SECSuccess || !ticket_data.len) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
 
     /* Parse extensions. */
     rv = ssl3_ConsumeHandshakeVariable(ss, &data, 2, &b, &length);
-    if (rv != SECSuccess) {
+    if (rv != SECSuccess || length) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
 
     rv = ssl3_HandleExtensions(ss, &data.data,
                                &data.len, new_session_ticket);
     if (rv != SECSuccess) {
@@ -3959,22 +3927,16 @@ tls13_HandleNewSessionTicket(sslSocket *
                     decode_error);
         return SECFailure;
     }
     if (ss->xtnData.max_early_data_size) {
         ticket.flags |= ticket_allow_early_data;
         ticket.max_early_data_size = ss->xtnData.max_early_data_size;
     }
 
-    if (length != 0) {
-        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
-                    decode_error);
-        return SECFailure;
-    }
-
     if (!ss->opt.noCache) {
         PORT_Assert(ss->sec.ci.sid);
         rv = SECITEM_CopyItem(NULL, &ticket.ticket, &ticket_data);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
             return SECFailure;
         }
         PRINT_BUF(50, (ss, "Caching session ticket",
@@ -4023,74 +3985,69 @@ tls13_HandleNewSessionTicket(sslSocket *
 #define _M3(a, b, c) (_M1(a) | _M2(b, c))
 
 static const struct {
     PRUint16 ex_value;
     PRUint32 messages;
 } KnownExtensions[] = {
     { ssl_server_name_xtn, _M2(client_hello, encrypted_extensions) },
     { ssl_supported_groups_xtn, _M2(client_hello, encrypted_extensions) },
-    { ssl_ec_point_formats_xtn, 0 },
     { ssl_signature_algorithms_xtn, _M2(client_hello, certificate_request) },
     { ssl_use_srtp_xtn, _M2(client_hello, encrypted_extensions) },
     { ssl_app_layer_protocol_xtn, _M2(client_hello, encrypted_extensions) },
     { ssl_padding_xtn, _M1(client_hello) },
-    { ssl_extended_master_secret_xtn, 0 },
-    { ssl_session_ticket_xtn, 0 },
     { ssl_tls13_key_share_xtn, _M3(client_hello, server_hello,
                                    hello_retry_request) },
     { ssl_tls13_pre_shared_key_xtn, _M2(client_hello, server_hello) },
     { ssl_tls13_psk_key_exchange_modes_xtn, _M1(client_hello) },
     { ssl_tls13_early_data_xtn, _M3(client_hello, encrypted_extensions,
                                     new_session_ticket) },
-    { ssl_next_proto_nego_xtn, 0 },
-    { ssl_renegotiation_info_xtn, 0 },
     { ssl_signed_cert_timestamp_xtn, _M3(client_hello, certificate_request,
                                          certificate) },
     { ssl_cert_status_xtn, _M3(client_hello, certificate_request,
                                certificate) },
     { ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
     { ssl_tls13_short_header_xtn, _M2(client_hello, server_hello) },
+    { ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
+    { ssl_tls13_supported_versions_xtn, _M1(client_hello) }
 };
 
-PRBool
-tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
+tls13ExtensionStatus
+tls13_ExtensionStatus(PRUint16 extension, SSL3HandshakeType message)
 {
     unsigned int i;
 
     PORT_Assert((message == client_hello) ||
                 (message == server_hello) ||
                 (message == hello_retry_request) ||
                 (message == encrypted_extensions) ||
                 (message == new_session_ticket) ||
                 (message == certificate) ||
                 (message == certificate_request));
 
     for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
         /* Hacky check for message numbers > 30. */
         PORT_Assert(!(KnownExtensions[i].messages & (1U << 31)));
-        if (KnownExtensions[i].ex_value == extension)
+        if (KnownExtensions[i].ex_value == extension) {
             break;
-    }
-    if (i == PR_ARRAY_SIZE(KnownExtensions)) {
-        /* We have never heard of this extension which is OK
-         * in client_hello and new_session_ticket. */
-        return (message == client_hello) ||
-               (message == new_session_ticket);
-    }
-
-    /* Return PR_TRUE iff the message mask bit is set. */
+        }
+    }
+    if (i >= PR_ARRAY_SIZE(KnownExtensions)) {
+        return tls13_extension_unknown;
+    }
+
+    /* Return "disallowed" if the message mask bit isn't set. */
     if (!(_M1(message) & KnownExtensions[i].messages)) {
         SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
                     SSL_GETPID(), extension, message));
 
-        return PR_FALSE;
-    }
-
-    return PR_TRUE;
+        return tls13_extension_disallowed;
+    }
+
+    return tls13_extension_allowed;
 }
 
 #undef _M1
 #undef _M2
 #undef _M3
 
 /* TLS 1.3 doesn't actually have additional data but the aead function
  * signature overloads additional data to carry the record sequence
--- a/lib/ssl/tls13con.h
+++ b/lib/ssl/tls13con.h
@@ -9,16 +9,22 @@
 #ifndef __tls13con_h_
 #define __tls13con_h_
 
 typedef enum {
     StaticSharedSecret,
     EphemeralSharedSecret
 } SharedSecretType;
 
+typedef enum {
+    tls13_extension_allowed,
+    tls13_extension_disallowed,
+    tls13_extension_unknown
+} tls13ExtensionStatus;
+
 #define TLS13_MAX_FINISHED_SIZE 64
 
 SECStatus tls13_UnprotectRecord(
     sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
     SSL3AlertDescription *alert);
 
 #if defined(WIN32)
 #define __func__ __FUNCTION__
@@ -71,17 +77,18 @@ SECStatus tls13_HandleHelloRetryRequest(
                                         PRUint32 length);
 void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
 void tls13_DestroyKeyShares(PRCList *list);
 SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
 void tls13_DestroyEarlyData(PRCList *list);
 void tls13_CipherSpecAddRef(ssl3CipherSpec *spec);
 void tls13_CipherSpecRelease(ssl3CipherSpec *spec);
 void tls13_DestroyCipherSpecs(PRCList *list);
-PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message);
+tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension,
+                                           SSL3HandshakeType message);
 SECStatus tls13_ProtectRecord(sslSocket *ss,
                               ssl3CipherSpec *cwSpec,
                               SSL3ContentType type,
                               const SSL3Opaque *pIn,
                               PRUint32 contentLen,
                               sslBuffer *wrBuf);
 PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
 SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
--- a/lib/ssl/tls13exthandle.c
+++ b/lib/ssl/tls13exthandle.c
@@ -1180,8 +1180,102 @@ tls13_HandleShortHeaderXtn(
                                           tls13_SendShortHeaderXtn);
         if (rv != SECSuccess) {
             return SECFailure;
         }
     }
 
     return SECSuccess;
 }
+
+PRInt32
+tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             PRBool append, PRUint32 maxBytes)
+{
+    unsigned int extensionLen;
+    unsigned int calen;
+    const SECItem *name;
+    unsigned int nnames;
+    SECStatus rv;
+
+    PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+
+    rv = ssl_GetCertificateRequestCAs(ss, &calen, &name, &nnames);
+    if (rv != SECSuccess) {
+        return -1;
+    }
+
+    if (!calen) {
+        return 0;
+    }
+
+    extensionLen = 2 + 2 + 2 + calen; /* type, length, inner length, CA list */
+    if (maxBytes < extensionLen) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_certificate_authorities_xtn, 2);
+        if (rv != SECSuccess) {
+            return -1;
+        }
+        rv = ssl3_ExtAppendHandshakeNumber(ss, calen + 2, 2);
+        if (rv != SECSuccess) {
+            return -1;
+        }
+        rv = ssl3_ExtAppendHandshakeNumber(ss, calen, 2);
+        if (rv != SECSuccess) {
+            return -1;
+        }
+
+        while (nnames) {
+            rv = ssl3_ExtAppendHandshakeVariable(ss, name->data, name->len, 2);
+            if (rv != SECSuccess) {
+                return -1;
+            }
+            ++name;
+            --nnames;
+        }
+    }
+
+    return extensionLen;
+}
+
+SECStatus
+tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+    PLArenaPool *arena;
+
+    if (!data->len) {
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
+        return SECFailure;
+    }
+
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    xtnData->certReqAuthorities.arena = arena;
+    rv = ssl3_ParseCertificateRequestCAs((sslSocket *)ss,
+                                         &data->data, &data->len,
+                                         &xtnData->certReqAuthorities);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    if (data->len) {
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
+        goto loser;
+    }
+    return SECSuccess;
+
+loser:
+    PORT_FreeArena(arena, PR_FALSE);
+    xtnData->certReqAuthorities.arena = NULL;
+    return SECFailure;
+}
--- a/lib/ssl/tls13exthandle.h
+++ b/lib/ssl/tls13exthandle.h
@@ -66,9 +66,16 @@ SECStatus tls13_ServerHandlePskKeyExchan
                                                    PRUint16 ex_type, SECItem *data);
 PRInt32 tls13_SendShortHeaderXtn(const sslSocket *ss,
                                  TLSExtensionData *xtnData,
                                  PRBool append, PRUint32 maxBytes);
 SECStatus tls13_HandleShortHeaderXtn(
     const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
     SECItem *data);
 
+PRInt32 tls13_SendCertAuthoritiesXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     PRBool append, PRUint32 maxBytes);
+SECStatus tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
+                                               TLSExtensionData *xtnData,
+                                               PRUint16 ex_type, SECItem *data);
+
 #endif