Bug 1325035 - Streamline session ticket key wrapping, r=ttaubert
authorMartin Thomson <martin.thomson@gmail.com>
Thu, 26 Jan 2017 06:41:37 +0900
changeset 13062 11048f8387bba05cc28857baaef57de1ed963803
parent 13061 1f65c04e55f13d04268fced697c86f25b84bf314
child 13063 391e604c7e0127f79c269d9b8f4f329c5dd34782
push id1959
push usermartin.thomson@gmail.com
push dateWed, 25 Jan 2017 22:19:45 +0000
reviewersttaubert
bugs1325035
Bug 1325035 - Streamline session ticket key wrapping, r=ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D127
gtests/ssl_gtest/libssl_internals.c
gtests/ssl_gtest/ssl_cert_ext_unittest.cc
gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
gtests/ssl_gtest/tls_agent.cc
gtests/ssl_gtest/tls_agent.h
gtests/ssl_gtest/tls_connect.cc
lib/ssl/ssl.def
lib/ssl/ssl.h
lib/ssl/ssl3con.c
lib/ssl/ssl3ecc.c
lib/ssl/ssl3exthandle.c
lib/ssl/sslcert.c
lib/ssl/sslcert.h
lib/ssl/sslimpl.h
lib/ssl/sslsnce.c
lib/ssl/tls13con.c
--- a/gtests/ssl_gtest/libssl_internals.c
+++ b/gtests/ssl_gtest/libssl_internals.c
@@ -57,20 +57,17 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom
   return ssl3_UpdateHandshakeHashes(ss, msg, msg_len);
 }
 
 PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
   sslSocket *ss = ssl_FindSocket(fd);
   return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
 }
 
-void SSLInt_ClearSessionTicketKey() {
-  ssl3_SessionTicketShutdown(NULL, NULL);
-  NSS_UnregisterShutdown(ssl3_SessionTicketShutdown, NULL);
-}
+void SSLInt_ClearSessionTicketKey() { ssl_ResetSessionTicketKeys(); }
 
 SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (ss) {
     ss->ssl3.mtu = mtu;
     return SECSuccess;
   }
   return SECFailure;
@@ -204,17 +201,17 @@ SECStatus SSLInt_Set0RttAlpn(PRFileDesc 
 }
 
 PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return PR_FALSE;
   }
 
-  return (PRBool)(!!ssl_FindServerCertByAuthType(ss, authType));
+  return (PRBool)(!!ssl_FindServerCert(ss, authType, NULL));
 }
 
 PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return PR_FALSE;
   }
 
--- a/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -57,55 +57,64 @@ class SignedCertificateTimestampsExtract
   std::unique_ptr<DataBuffer> auth_timestamps_;
   std::unique_ptr<DataBuffer> handshake_timestamps_;
 };
 
 static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
 static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
                                  sizeof(kSctValue)};
 static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
+static const SSLExtraServerCertData kExtraSctData = {ssl_auth_null, nullptr,
+                                                     nullptr, &kSctItem};
 
 // Test timestamps extraction during a successful handshake.
-TEST_P(TlsConnectGeneric, SignedCertificateTimestampsHandshake) {
+TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) {
   EnsureTlsSetup();
+
+  // We have to use the legacy API consistently here for configuring certs.
+  // Also, this doesn't work in TLS 1.3 because this only configures the SCT for
+  // RSA decrypt and PKCS#1 signing, not PSS.
+  ScopedCERTCertificate cert;
+  ScopedSECKEYPrivateKey priv;
+  ASSERT_TRUE(TlsAgent::LoadCertificate(TlsAgent::kServerRsa, &cert, &priv));
+  EXPECT_EQ(SECSuccess, SSL_ConfigSecureServerWithCertChain(
+                            server_->ssl_fd(), cert.get(), nullptr, priv.get(),
+                            ssl_kea_rsa));
   EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
                                                     &kSctItem, ssl_kea_rsa));
   EXPECT_EQ(SECSuccess,
             SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                           PR_TRUE));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
 
   timestamps_extractor.assertTimestamps(kSctBuffer);
 }
 
-TEST_P(TlsConnectGeneric, SignedCertificateTimestampsConfig) {
-  static const SSLExtraServerCertData kExtraData = {ssl_auth_rsa_sign, nullptr,
-                                                    nullptr, &kSctItem};
-
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsSuccess) {
   EnsureTlsSetup();
   EXPECT_TRUE(
-      server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraData));
+      server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData));
   EXPECT_EQ(SECSuccess,
             SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                           PR_TRUE));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
 
   timestamps_extractor.assertTimestamps(kSctBuffer);
 }
 
 // Test SSL_PeerSignedCertTimestamps returning zero-length SECItem
 // when the client / the server / both have not enabled the feature.
 TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveClient) {
   EnsureTlsSetup();
-  EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
-                                                    &kSctItem, ssl_kea_rsa));
+  EXPECT_TRUE(
+      server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraSctData));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
   timestamps_extractor.assertTimestamps(DataBuffer());
 }
 
 TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveServer) {
   EnsureTlsSetup();
@@ -136,18 +145,18 @@ static SECStatus CheckNoOCSP(TlsAgent* a
 
 static const uint8_t kOcspValue1[] = {1, 2, 3, 4, 5, 6};
 static const uint8_t kOcspValue2[] = {7, 8, 9};
 static const SECItem kOcspItems[] = {
     {siBuffer, const_cast<uint8_t*>(kOcspValue1), sizeof(kOcspValue1)},
     {siBuffer, const_cast<uint8_t*>(kOcspValue2), sizeof(kOcspValue2)}};
 static const SECItemArray kOcspResponses = {const_cast<SECItem*>(kOcspItems),
                                             PR_ARRAY_SIZE(kOcspItems)};
-const static SSLExtraServerCertData kOcspExtraData = {
-    ssl_auth_rsa_sign, nullptr, &kOcspResponses, nullptr};
+const static SSLExtraServerCertData kOcspExtraData = {ssl_auth_null, nullptr,
+                                                      &kOcspResponses, nullptr};
 
 TEST_P(TlsConnectGeneric, NoOcsp) {
   EnsureTlsSetup();
   client_->SetAuthCertificateCallback(CheckNoOCSP);
   Connect();
 }
 
 // The client doesn't get OCSP stapling unless it asks.
--- a/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -123,26 +123,32 @@ class TlsCipherSuiteTestBase : public Tl
       }
     }
   }
 
   void ConnectAndCheckCipherSuite() {
     Connect();
     SendReceive();
 
-    // Check that we used the right cipher suite.
+    // Check that we used the right cipher suite, auth type and kea type.
     uint16_t actual;
-    EXPECT_TRUE(client_->cipher_suite(&actual) && actual == cipher_suite_);
-    EXPECT_TRUE(server_->cipher_suite(&actual) && actual == cipher_suite_);
+    EXPECT_TRUE(client_->cipher_suite(&actual));
+    EXPECT_EQ(cipher_suite_, actual);
+    EXPECT_TRUE(server_->cipher_suite(&actual));
+    EXPECT_EQ(cipher_suite_, actual);
     SSLAuthType auth;
-    EXPECT_TRUE(client_->auth_type(&auth) && auth == auth_type_);
-    EXPECT_TRUE(server_->auth_type(&auth) && auth == auth_type_);
+    EXPECT_TRUE(client_->auth_type(&auth));
+    EXPECT_EQ(auth_type_, auth);
+    EXPECT_TRUE(server_->auth_type(&auth));
+    EXPECT_EQ(auth_type_, auth);
     SSLKEAType kea;
-    EXPECT_TRUE(client_->kea_type(&kea) && kea == kea_type_);
-    EXPECT_TRUE(server_->kea_type(&kea) && kea == kea_type_);
+    EXPECT_TRUE(client_->kea_type(&kea));
+    EXPECT_EQ(kea_type_, kea);
+    EXPECT_TRUE(server_->kea_type(&kea));
+    EXPECT_EQ(kea_type_, kea);
   }
 
   // Get the expected limit on the number of records that can be sent for the
   // cipher suite.
   uint64_t record_limit() const {
     switch (csinfo_.symCipher) {
       case ssl_calg_rc4:
       case ssl_calg_3des:
--- a/gtests/ssl_gtest/tls_agent.cc
+++ b/gtests/ssl_gtest/tls_agent.cc
@@ -97,33 +97,45 @@ TlsAgent::~TlsAgent() {
 
 void TlsAgent::SetState(State state) {
   if (state_ == state) return;
 
   LOG("Changing state from " << state_ << " to " << state);
   state_ = state;
 }
 
+/*static*/ bool TlsAgent::LoadCertificate(const std::string& name,
+                                          ScopedCERTCertificate* cert,
+                                          ScopedSECKEYPrivateKey* priv) {
+  cert->reset(PK11_FindCertFromNickname(name.c_str(), nullptr));
+  EXPECT_NE(nullptr, cert->get());
+  if (!cert->get()) return false;
+
+  priv->reset(PK11_FindKeyByAnyCert(cert->get(), nullptr));
+  EXPECT_NE(nullptr, priv->get());
+  if (!priv->get()) return false;
+
+  return true;
+}
+
 bool TlsAgent::ConfigServerCert(const std::string& name, bool updateKeyBits,
                                 const SSLExtraServerCertData* serverCertData) {
-  ScopedCERTCertificate cert(PK11_FindCertFromNickname(name.c_str(), nullptr));
-  EXPECT_NE(nullptr, cert.get());
-  if (!cert.get()) return false;
+  ScopedCERTCertificate cert;
+  ScopedSECKEYPrivateKey priv;
+  if (!TlsAgent::LoadCertificate(name, &cert, &priv)) {
+    return false;
+  }
 
-  ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get()));
-  EXPECT_NE(nullptr, pub.get());
-  if (!pub.get()) return false;
   if (updateKeyBits) {
+    ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get()));
+    EXPECT_NE(nullptr, pub.get());
+    if (!pub.get()) return false;
     server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub.get());
   }
 
-  ScopedSECKEYPrivateKey priv(PK11_FindKeyByAnyCert(cert.get(), nullptr));
-  EXPECT_NE(nullptr, priv.get());
-  if (!priv.get()) return false;
-
   SECStatus rv =
       SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, ssl_kea_null);
   EXPECT_EQ(SECFailure, rv);
   rv = SSL_ConfigServerCert(ssl_fd_, cert.get(), priv.get(), serverCertData,
                             serverCertData ? sizeof(*serverCertData) : 0);
   return rv == SECSuccess;
 }
 
@@ -176,40 +188,33 @@ void TlsAgent::SetupClientAuth() {
   EXPECT_TRUE(EnsureTlsSetup());
   ASSERT_EQ(CLIENT, role_);
 
   EXPECT_EQ(SECSuccess,
             SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook,
                                       reinterpret_cast<void*>(this)));
 }
 
-bool TlsAgent::GetClientAuthCredentials(CERTCertificate** cert,
-                                        SECKEYPrivateKey** priv) const {
-  *cert = PK11_FindCertFromNickname(name_.c_str(), nullptr);
-  EXPECT_NE(nullptr, *cert);
-  if (!*cert) return false;
-
-  *priv = PK11_FindKeyByAnyCert(*cert, nullptr);
-  EXPECT_NE(nullptr, *priv);
-  if (!*priv) return false;  // Leak cert.
-
-  return true;
-}
-
 SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
                                           CERTDistNames* caNames,
-                                          CERTCertificate** cert,
-                                          SECKEYPrivateKey** privKey) {
+                                          CERTCertificate** clientCert,
+                                          SECKEYPrivateKey** clientKey) {
   TlsAgent* agent = reinterpret_cast<TlsAgent*>(self);
   ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
   EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
-  if (agent->GetClientAuthCredentials(cert, privKey)) {
-    return SECSuccess;
+
+  ScopedCERTCertificate cert;
+  ScopedSECKEYPrivateKey priv;
+  if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) {
+    return SECFailure;
   }
-  return SECFailure;
+
+  *clientCert = cert.release();
+  *clientKey = priv.release();
+  return SECSuccess;
 }
 
 bool TlsAgent::GetPeerChainLength(size_t* count) {
   CERTCertList* chain = SSL_PeerCertificateChain(ssl_fd_);
   if (!chain) return false;
   *count = 0;
 
   for (PRCList* cursor = PR_NEXT_LINK(&chain->list); cursor != &chain->list;
--- a/gtests/ssl_gtest/tls_agent.h
+++ b/gtests/ssl_gtest/tls_agent.h
@@ -13,16 +13,17 @@
 #include <functional>
 #include <iostream>
 
 #include "test_io.h"
 #include "tls_filter.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
+#include "scoped_ptrs.h"
 
 extern bool g_ssl_gtest_verbose;
 
 namespace nss_test {
 
 #define LOG(msg) std::cerr << role_str() << ": " << msg << std::endl
 #define LOGV(msg)                      \
   do {                                 \
@@ -110,25 +111,26 @@ class TlsAgent : public PollTarget {
   void EnableGroupsByAuthType(SSLAuthType authType);
   void EnableSingleCipher(uint16_t cipher);
 
   void Handshake();
   // Marks the internal state as CONNECTING in anticipation of renegotiation.
   void PrepareForRenegotiate();
   // Prepares for renegotiation, then actually triggers it.
   void StartRenegotiate();
+  static bool LoadCertificate(const std::string& name,
+                              ScopedCERTCertificate* cert,
+                              ScopedSECKEYPrivateKey* priv);
   bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
                         const SSLExtraServerCertData* serverCertData = nullptr);
   bool ConfigServerCertWithChain(const std::string& name);
   bool EnsureTlsSetup(PRFileDesc* modelSocket = nullptr);
 
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
-  bool GetClientAuthCredentials(CERTCertificate** cert,
-                                SECKEYPrivateKey** priv) const;
 
   void ConfigureSessionCache(SessionResumptionMode mode);
   void SetSessionTicketsEnabled(bool en);
   void SetSessionCacheEnabled(bool en);
   void Set0RttEnabled(bool en);
   void SetShortHeadersEnabled();
   void SetVersionRange(uint16_t minver, uint16_t maxver);
   void GetVersionRange(uint16_t* minver, uint16_t* maxver);
--- a/gtests/ssl_gtest/tls_connect.cc
+++ b/gtests/ssl_gtest/tls_connect.cc
@@ -8,16 +8,17 @@
 extern "C" {
 #include "libssl_internals.h"
 }
 
 #include <iostream>
 
 #include "databuffer.h"
 #include "gtest_utils.h"
+#include "scoped_ptrs.h"
 #include "sslproto.h"
 
 extern std::string g_working_dir_path;
 
 namespace nss_test {
 
 static const std::string kTlsModesStreamArr[] = {"TLS"};
 ::testing::internal::ParamGenerator<std::string>
@@ -340,16 +341,23 @@ void TlsConnectTestBase::CheckKeys(SSLKE
   }
 
   SSLSignatureScheme scheme;
   switch (auth_type) {
     case ssl_auth_rsa_decrypt:
       scheme = ssl_sig_none;
       break;
     case ssl_auth_rsa_sign:
+      if (version_ >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        scheme = ssl_sig_rsa_pss_sha256;
+      } else {
+        scheme = ssl_sig_rsa_pkcs1_sha256;
+      }
+      break;
+    case ssl_auth_rsa_pss:
       scheme = ssl_sig_rsa_pss_sha256;
       break;
     case ssl_auth_ecdsa:
       scheme = ssl_sig_ecdsa_secp256r1_sha256;
       break;
     case ssl_auth_dsa:
       scheme = ssl_sig_dsa_sha1;
       break;
@@ -385,16 +393,17 @@ void TlsConnectTestBase::ConnectExpectFa
     fail_agent = client_;
   } else {
     fail_agent = server_;
   }
   ASSERT_TRUE_WAIT(fail_agent->state() == TlsAgent::STATE_ERROR, 5000);
 }
 
 void TlsConnectTestBase::ConfigureVersion(uint16_t version) {
+  version_ = version;
   client_->SetVersionRange(version, version);
   server_->SetVersionRange(version, version);
 }
 
 void TlsConnectTestBase::SetExpectedVersion(uint16_t version) {
   client_->SetExpectedVersion(version);
   server_->SetExpectedVersion(version);
 }
@@ -435,20 +444,26 @@ void TlsConnectTestBase::EnableSomeEcdhC
   }
 }
 
 void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
                                                SessionResumptionMode server) {
   client_->ConfigureSessionCache(client);
   server_->ConfigureSessionCache(server);
   if ((server & RESUME_TICKET) != 0) {
-    // This is an abomination.  NSS encrypts session tickets with the server's
-    // RSA public key.  That means we need the server to have an RSA certificate
-    // even if it won't be used for the connection.
-    server_->ConfigServerCert(TlsAgent::kServerRsaDecrypt);
+    ScopedCERTCertificate cert;
+    ScopedSECKEYPrivateKey privKey;
+    ASSERT_TRUE(TlsAgent::LoadCertificate(TlsAgent::kServerRsaDecrypt, &cert,
+                                          &privKey));
+
+    ScopedSECKEYPublicKey pubKey(CERT_ExtractPublicKey(cert.get()));
+    ASSERT_TRUE(pubKey);
+
+    EXPECT_EQ(SECSuccess,
+              SSL_SetSessionTicketKeyPair(pubKey.get(), privKey.get()));
   }
 }
 
 void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
   EXPECT_NE(RESUME_BOTH, expected);
 
   int resume_count = expected ? 1 : 0;
   int stateless_count = (expected & RESUME_TICKET) ? 1 : 0;
--- a/lib/ssl/ssl.def
+++ b/lib/ssl/ssl.def
@@ -216,8 +216,14 @@ SSL_NamedGroupConfig;
 ;+    global:
 SSL_ExportEarlyKeyingMaterial;
 SSL_SendAdditionalKeyShares;
 SSL_SignatureSchemePrefSet;
 SSL_SignatureSchemePrefGet;
 ;+    local:
 ;+*;
 ;+};
+;+NSS_3.30 {    # NSS 3.30 release
+;+    global:
+SSL_SetSessionTicketKeyPair;
+;+    local:
+;+*;
+;+};
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -909,16 +909,29 @@ SSL_IMPORT SECStatus SSL_ConfigSecureSer
 ** SSL_ConfigSecureServerCert can be used to pass a certificate chain.
 */
 SSL_IMPORT SECStatus
 SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
                                     const CERTCertificateList *certChainOpt,
                                     SECKEYPrivateKey *key, SSLKEAType kea);
 
 /*
+** SSL_SetSessionTicketKeyPair configures an asymmetric key pair for use in
+** wrapping session ticket keys, used by the server.  This function currently
+** only accepts an RSA public/private key pair.
+**
+** Prior to the existence of this function, NSS used an RSA private key
+** associated with a configured certificate to perform session ticket
+** encryption.  If this function isn't used, the keys provided with a configured
+** RSA certificate are used for wrapping session ticket keys.
+*/
+SSL_IMPORT SECStatus
+SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey);
+
+/*
 ** Configure a secure server's session-id cache. Define the maximum number
 ** of entries in the cache, the longevity of the entires, and the directory
 ** where the cache files will be placed.  These values can be zero, and
 ** if so, the implementation will choose defaults.
 ** This version of the function is for use in applications that have only one
 ** process that uses the cache (even if that process has multiple threads).
 */
 SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCache(int maxCacheEntries,
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -268,20 +268,16 @@ ssl_CompressionEnabled(sslSocket *ss, SS
 }
 
 static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = {
     ct_RSA_sign,
     ct_ECDSA_sign,
     ct_DSS_sign,
 };
 
-/* This global item is used only in servers.  It is is initialized by
-** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
-*/
-CERTDistNames *ssl3_server_ca_list = NULL;
 static SSL3Statistics ssl3stats;
 
 /* Record protection algorithms, indexed by SSL3BulkCipher.
  *
  * The |max_records| field (|mr| below) is set to a number that is higher than
  * recommended in some literature (esp. TLS 1.3) because we currently abort the
  * connection when this limit is reached and we want to ensure that we only
  * rarely hit this limit.  See bug 1268745 for details.
@@ -858,33 +854,31 @@ ssl_HasCert(const sslSocket *ss, SSLAuth
     PRCList *cursor;
     if (authType == ssl_auth_null || authType == ssl_auth_psk || authType == ssl_auth_tls13_any) {
         return PR_TRUE;
     }
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
-        if (cert->certType.authType != authType) {
-            continue;
-        }
         if (!cert->serverKeyPair ||
             !cert->serverKeyPair->privKey ||
-            !cert->serverCertChain) {
+            !cert->serverCertChain ||
+            !SSL_CERT_IS(cert, authType)) {
             continue;
         }
         /* When called from ssl3_config_match_init(), all the EC curves will be
          * enabled, so this will essentially do nothing (unless we implement
          * curve configuration).  However, once we have seen the
          * supported_groups extension and this is called from config_match(),
          * this will filter out certificates with an unsupported curve. */
         if ((authType == ssl_auth_ecdsa ||
              authType == ssl_auth_ecdh_ecdsa ||
              authType == ssl_auth_ecdh_rsa) &&
-            !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
+            !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
             continue;
         }
         return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 const ssl3BulkCipherDef *
@@ -5578,76 +5572,105 @@ ssl3_HandleHelloRequest(sslSocket *ss)
 
     ssl_GetXmitBufLock(ss);
     rv = ssl3_SendClientHello(ss, client_hello_renegotiation);
     ssl_ReleaseXmitBufLock(ss);
 
     return rv;
 }
 
-#define UNKNOWN_WRAP_MECHANISM 0x7fffffff
-
 static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = {
     CKM_DES3_ECB,
     CKM_CAST5_ECB,
     CKM_DES_ECB,
     CKM_KEY_WRAP_LYNKS,
     CKM_IDEA_ECB,
     CKM_CAST3_ECB,
     CKM_CAST_ECB,
     CKM_RC5_ECB,
     CKM_RC2_ECB,
     CKM_CDMF_ECB,
     CKM_SKIPJACK_WRAP,
     CKM_SKIPJACK_CBC64,
     CKM_AES_ECB,
     CKM_CAMELLIA_ECB,
-    CKM_SEED_ECB,
-    UNKNOWN_WRAP_MECHANISM
+    CKM_SEED_ECB
 };
 
-static int
-ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech)
-{
-    const CK_MECHANISM_TYPE *pMech = wrapMechanismList;
-
-    while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) {
-        ++pMech;
-    }
-    return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1
-                                              : (pMech - wrapMechanismList);
+static SECStatus
+ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech, unsigned int *wrapMechIndex)
+{
+    unsigned int i;
+    for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
+        if (wrapMechanismList[i] == mech) {
+            *wrapMechIndex = i;
+            return SECSuccess;
+        }
+    }
+    PORT_Assert(0);
+    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    return SECFailure;
+}
+
+/* Each process sharing the server session ID cache has its own array of SymKey
+ * pointers for the symmetric wrapping keys that are used to wrap the master
+ * secrets.  There is one key for each authentication type.  These Symkeys
+ * correspond to the wrapped SymKeys kept in the server session cache.
+ */
+const SSLAuthType ssl_wrap_key_auth_type[SSL_NUM_WRAP_KEYS] = {
+    ssl_auth_rsa_decrypt,
+    ssl_auth_rsa_sign,
+    ssl_auth_rsa_pss,
+    ssl_auth_ecdsa,
+    ssl_auth_ecdh_rsa,
+    ssl_auth_ecdh_ecdsa
+};
+
+static SECStatus
+ssl_FindIndexByWrapKey(const sslServerCert *serverCert, unsigned int *wrapKeyIndex)
+{
+    unsigned int i;
+    for (i = 0; i < SSL_NUM_WRAP_KEYS; ++i) {
+        if (SSL_CERT_IS(serverCert, ssl_wrap_key_auth_type[i])) {
+            *wrapKeyIndex = i;
+            return SECSuccess;
+        }
+    }
+    /* Can't assert here because we still get people using DSA certificates. */
+    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+    return SECFailure;
 }
 
 static PK11SymKey *
 ssl_UnwrapSymWrappingKey(
     SSLWrappedSymWrappingKey *pWswk,
     SECKEYPrivateKey *svrPrivKey,
-    SSLAuthType authType,
+    unsigned int wrapKeyIndex,
     CK_MECHANISM_TYPE masterWrapMech,
     void *pwArg)
 {
     PK11SymKey *unwrappedWrappingKey = NULL;
     SECItem wrappedKey;
     PK11SymKey *Ks;
     SECKEYPublicKey pubWrapKey;
     ECCWrappedKeyInfo *ecWrapped;
 
     /* found the wrapping key on disk. */
     PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
-    PORT_Assert(pWswk->authType == authType);
+    PORT_Assert(pWswk->wrapKeyIndex == wrapKeyIndex);
     if (pWswk->symWrapMechanism != masterWrapMech ||
-        pWswk->authType != authType) {
+        pWswk->wrapKeyIndex != wrapKeyIndex) {
         goto loser;
     }
     wrappedKey.type = siBuffer;
     wrappedKey.data = pWswk->wrappedSymmetricWrappingkey;
     wrappedKey.len = pWswk->wrappedSymKeyLen;
     PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
 
-    switch (authType) {
+    switch (ssl_wrap_key_auth_type[wrapKeyIndex]) {
 
         case ssl_auth_rsa_decrypt:
         case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
             unwrappedWrappingKey =
                 PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
                                      masterWrapMech, CKA_UNWRAP, 0);
             break;
 
@@ -5710,24 +5733,18 @@ ssl_UnwrapSymWrappingKey(
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             goto loser;
     }
 loser:
     return unwrappedWrappingKey;
 }
 
-/* Each process sharing the server session ID cache has its own array of SymKey
- * pointers for the symmetric wrapping keys that are used to wrap the master
- * secrets.  There is one key for each authentication type.  These Symkeys
- * correspond to the wrapped SymKeys kept in the server session cache.
- */
-
 typedef struct {
-    PK11SymKey *symWrapKey[ssl_auth_size];
+    PK11SymKey *symWrapKey[SSL_NUM_WRAP_KEYS];
 } ssl3SymWrapKey;
 
 static PZLock *symWrapKeysLock = NULL;
 static ssl3SymWrapKey symWrapKeys[SSL_NUM_WRAP_MECHS];
 
 SECStatus
 ssl_FreeSymWrapKeysLock(void)
 {
@@ -5745,17 +5762,17 @@ SSL3_ShutdownServerCache(void)
 {
     int i, j;
 
     if (!symWrapKeysLock)
         return SECSuccess; /* lock was never initialized */
     PZ_Lock(symWrapKeysLock);
     /* get rid of all symWrapKeys */
     for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
-        for (j = 0; j < ssl_auth_size; ++j) {
+        for (j = 0; j < SSL_NUM_WRAP_KEYS; ++j) {
             PK11SymKey **pSymWrapKey;
             pSymWrapKey = &symWrapKeys[i].symWrapKey[j];
             if (*pSymWrapKey) {
                 PK11_FreeSymKey(*pSymWrapKey);
                 *pSymWrapKey = NULL;
             }
         }
     }
@@ -5779,55 +5796,59 @@ ssl_InitSymWrapKeysLock(void)
  *
  * Note that this function performs some fairly inadvisable functions with
  * certificate private keys.  ECDSA keys are used with ECDH; similarly, RSA
  * signing keys are used to encrypt.  Bug 1248320.
  */
 PK11SymKey *
 ssl3_GetWrappingKey(sslSocket *ss,
                     PK11SlotInfo *masterSecretSlot,
-                    const sslServerCert *serverCert,
                     CK_MECHANISM_TYPE masterWrapMech,
                     void *pwArg)
 {
     SSLAuthType authType;
     SECKEYPrivateKey *svrPrivKey;
     SECKEYPublicKey *svrPubKey = NULL;
     PK11SymKey *unwrappedWrappingKey = NULL;
     PK11SymKey **pSymWrapKey;
     CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM;
     int length;
-    int symWrapMechIndex;
+    unsigned int wrapMechIndex;
+    unsigned int wrapKeyIndex;
     SECStatus rv;
     SECItem wrappedKey;
     SSLWrappedSymWrappingKey wswk;
     PK11SymKey *Ks = NULL;
     SECKEYPublicKey *pubWrapKey = NULL;
     SECKEYPrivateKey *privWrapKey = NULL;
     ECCWrappedKeyInfo *ecWrapped;
+    const sslServerCert *serverCert = ss->sec.serverCert;
 
     PORT_Assert(serverCert);
     PORT_Assert(serverCert->serverKeyPair);
     PORT_Assert(serverCert->serverKeyPair->privKey);
     PORT_Assert(serverCert->serverKeyPair->pubKey);
     if (!serverCert || !serverCert->serverKeyPair ||
         !serverCert->serverKeyPair->privKey ||
         !serverCert->serverKeyPair->pubKey) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return NULL; /* hmm */
     }
-    authType = serverCert->certType.authType;
+
+    rv = ssl_FindIndexByWrapKey(serverCert, &wrapKeyIndex);
+    if (rv != SECSuccess)
+        return NULL; /* unusable wrapping key. */
+
+    rv = ssl_FindIndexByWrapMechanism(masterWrapMech, &wrapMechIndex);
+    if (rv != SECSuccess)
+        return NULL; /* invalid masterWrapMech. */
+
+    authType = ssl_wrap_key_auth_type[wrapKeyIndex];
     svrPrivKey = serverCert->serverKeyPair->privKey;
-
-    symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech);
-    PORT_Assert(symWrapMechIndex >= 0);
-    if (symWrapMechIndex < 0)
-        return NULL; /* invalid masterWrapMech. */
-
-    pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType];
+    pSymWrapKey = &symWrapKeys[wrapMechIndex].symWrapKey[wrapKeyIndex];
 
     ssl_InitSessionCacheLocks(PR_TRUE);
 
     PZ_Lock(symWrapKeysLock);
 
     unwrappedWrappingKey = *pSymWrapKey;
     if (unwrappedWrappingKey != NULL) {
         if (PK11_VerifyKeyOK(unwrappedWrappingKey)) {
@@ -5836,20 +5857,21 @@ ssl3_GetWrappingKey(sslSocket *ss,
         }
         /* slot series has changed, so this key is no good any more. */
         PK11_FreeSymKey(unwrappedWrappingKey);
         *pSymWrapKey = unwrappedWrappingKey = NULL;
     }
 
     /* Try to get wrapped SymWrapping key out of the (disk) cache. */
     /* Following call fills in wswk on success. */
-    if (ssl_GetWrappingKey(symWrapMechIndex, authType, &wswk)) {
+    rv = ssl_GetWrappingKey(wrapMechIndex, wrapKeyIndex, &wswk);
+    if (rv == SECSuccess) {
         /* found the wrapped sym wrapping key on disk. */
         unwrappedWrappingKey =
-            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType,
+            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
                                      masterWrapMech, pwArg);
         if (unwrappedWrappingKey) {
             goto install;
         }
     }
 
     if (!masterSecretSlot) /* caller doesn't want to create a new one. */
         goto loser;
@@ -5988,35 +6010,36 @@ ssl3_GetWrappingKey(sslSocket *ss,
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM);
 
     wswk.symWrapMechanism = masterWrapMech;
-    wswk.symWrapMechIndex = symWrapMechIndex;
     wswk.asymWrapMechanism = asymWrapMechanism;
-    wswk.authType = authType;
+    wswk.wrapMechIndex = wrapMechIndex;
+    wswk.wrapKeyIndex = wrapKeyIndex;
     wswk.wrappedSymKeyLen = wrappedKey.len;
 
     /* put it on disk. */
     /* If the wrapping key for this KEA type has already been set,
      * then abandon the value we just computed and
      * use the one we got from the disk.
      */
-    if (ssl_SetWrappingKey(&wswk)) {
+    rv = ssl_SetWrappingKey(&wswk);
+    if (rv == SECSuccess) {
         /* somebody beat us to it.  The original contents of our wswk
          * has been replaced with the content on disk.  Now, discard
          * the key we just created and unwrap this new one.
          */
         PK11_FreeSymKey(unwrappedWrappingKey);
 
         unwrappedWrappingKey =
-            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType,
+            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
                                      masterWrapMech, pwArg);
     }
 
 install:
     if (unwrappedWrappingKey) {
         *pSymWrapKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
     }
 
@@ -8250,29 +8273,27 @@ ssl3_SelectServerCert(sslSocket *ss)
      * b) the right named curve (EC only)
      *
      * We might want to do some sort of ranking here later.  For now, it's all
      * based on what order they are configured in. */
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
-        if (cert->certType.authType != kea_def->authKeyType) {
+        if (!SSL_CERT_IS(cert, kea_def->authKeyType)) {
             continue;
         }
-        if ((cert->certType.authType == ssl_auth_ecdsa ||
-             cert->certType.authType == ssl_auth_ecdh_rsa ||
-             cert->certType.authType == ssl_auth_ecdh_ecdsa) &&
-            !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
+        if (SSL_CERT_IS_EC(cert) &&
+            !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
             continue;
         }
 
         /* Found one. */
         ss->sec.serverCert = cert;
-        ss->sec.authType = cert->certType.authType;
+        ss->sec.authType = kea_def->authKeyType;
         ss->sec.authKeyBits = cert->serverKeyBits;
 
         /* Don't pick a signature scheme if we aren't going to use it. */
         if (kea_def->signKeyType == nullKey) {
             return SECSuccess;
         }
         return ssl3_PickServerSignatureScheme(ss);
     }
@@ -8786,26 +8807,30 @@ compression_found:
      * as if the client had sent us no sid to begin with, and make a new one.
      * The exception here is attempts to resume extended_master_secret
      * sessions without the extension, which causes an alert.
      */
     if (sid != NULL)
         do {
             ssl3CipherSpec *pwSpec;
             SECItem wrappedMS; /* wrapped key */
-            const sslServerCert *serverCert;
 
             if (sid->version != ss->version ||
                 sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite ||
                 sid->u.ssl3.compression != ss->ssl3.hs.compression) {
                 break; /* not an error */
             }
 
-            serverCert = ssl_FindServerCert(ss, &sid->certType);
-            if (!serverCert || !serverCert->serverCert) {
+            /* server sids don't remember the server cert we previously sent,
+            ** but they do remember the slot we originally used, so we
+            ** can locate it again, provided that the current ssl socket
+            ** has had its server certs configured the same as the previous one.
+            */
+            ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType, sid->namedCurve);
+            if (!ss->sec.serverCert || !ss->sec.serverCert->serverCert) {
                 /* A compatible certificate must not have been configured.  It
                  * might not be the same certificate, but we only find that out
                  * when the ticket fails to decrypt. */
                 break;
             }
 
             /* [draft-ietf-tls-session-hash-06; Section 5.3]
              * o  If the original session did not use the "extended_master_secret"
@@ -8843,17 +8868,17 @@ compression_found:
 
             ssl_GetSpecWriteLock(ss);
             haveSpecWriteLock = PR_TRUE;
             pwSpec = ss->ssl3.pwSpec;
             if (sid->u.ssl3.keys.msIsWrapped) {
                 PK11SymKey *wrapKey; /* wrapping key */
                 CK_FLAGS keyFlags = 0;
 
-                wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert,
+                wrapKey = ssl3_GetWrappingKey(ss, NULL,
                                               sid->u.ssl3.masterWrapMech,
                                               ss->pkcs11PinArg);
                 if (!wrapKey) {
                     /* we have a SID cache entry, but no wrapping key for it??? */
                     break;
                 }
 
                 if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
@@ -8902,23 +8927,18 @@ compression_found:
                 SSL_AtomicIncrementLong(&ssl3stats.hch_sid_stateless_resumes);
             ss->ssl3.hs.isResuming = PR_TRUE;
 
             ss->sec.authType = sid->authType;
             ss->sec.authKeyBits = sid->authKeyBits;
             ss->sec.keaType = sid->keaType;
             ss->sec.keaKeyBits = sid->keaKeyBits;
 
-            /* server sids don't remember the server cert we previously sent,
-            ** but they do remember the slot we originally used, so we
-            ** can locate it again, provided that the current ssl socket
-            ** has had its server certs configured the same as the previous one.
-            */
-            ss->sec.serverCert = serverCert;
-            ss->sec.localCert = CERT_DupCertificate(serverCert->serverCert);
+            ss->sec.localCert =
+                CERT_DupCertificate(ss->sec.serverCert->serverCert);
 
             /* Copy cached name in to pending spec */
             if (sid != NULL &&
                 sid->version > SSL_LIBRARY_VERSION_3_0 &&
                 sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) {
                 /* Set server name from sid */
                 SECItem *sidName = &sid->u.ssl3.srvName;
                 SECItem *pwsName = &ss->ssl3.hs.srvVirtName;
@@ -9626,69 +9646,44 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, 
     if (p == buf) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
     *len = p - buf;
     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;
     const PRUint8 *certTypes;
     SECStatus rv;
     int length;
     SECItem *names;
-    int calen;
-    int nnames;
+    unsigned int calen;
+    unsigned int nnames;
     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));
 
     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_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+    rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+    if (rv != SECSuccess) {
+        return rv;
+    }
     certTypes = certificate_types;
     certTypesLength = sizeof certificate_types;
 
     length = 1 + certTypesLength + 2 + calen;
     if (isTLS12) {
         rv = ssl3_EncodeSigAlgs(ss, sigAlgs, sizeof(sigAlgs), &sigAlgsLength);
         if (rv != SECSuccess) {
             return rv;
@@ -11326,17 +11321,17 @@ fail:
     return rv;
 }
 
 /* wrap the master secret, and put it into the SID.
  * Caller holds the Spec read lock.
  */
 SECStatus
 ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
-                              ssl3CipherSpec *spec, SSLAuthType authType)
+                              ssl3CipherSpec *spec)
 {
     PK11SymKey *wrappingKey = NULL;
     PK11SlotInfo *symKeySlot;
     void *pwArg = ss->pkcs11PinArg;
     SECStatus rv = SECFailure;
     PRBool isServer = ss->sec.isServer;
     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
 
@@ -11380,18 +11375,17 @@ ssl3_CacheWrappedMasterSecret(sslSocket 
                 PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey);
             }
         }
     } else {
         /* server socket using session cache. */
         mechanism = PK11_GetBestWrapMechanism(symKeySlot);
         if (mechanism != CKM_INVALID_MECHANISM) {
             wrappingKey =
-                ssl3_GetWrappingKey(ss, symKeySlot, ss->sec.serverCert,
-                                    mechanism, pwArg);
+                ssl3_GetWrappingKey(ss, symKeySlot, mechanism, pwArg);
             if (wrappingKey) {
                 mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */
             }
         }
     }
 
     sid->u.ssl3.masterWrapMech = mechanism;
     PK11_FreeSlot(symKeySlot);
@@ -11588,19 +11582,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
     sid->authType = ss->sec.authType;
     sid->authKeyBits = ss->sec.authKeyBits;
     sid->keaType = ss->sec.keaType;
     sid->keaKeyBits = ss->sec.keaKeyBits;
     sid->lastAccessTime = sid->creationTime = ssl_Time();
     sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
-        memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType));
-    } else {
-        sid->certType.authType = ssl_auth_null;
+        sid->namedCurve = ss->sec.serverCert->namedCurve;
     }
 
     if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
         ss->xtnData.nextProto.data) {
         if (SECITEM_CopyItem(
                 NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
             return SECFailure; /* error already set. */
         }
@@ -11614,18 +11606,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
             ss->ssl3.crSpec->msItem.len;
         memcpy(sid->u.ssl3.keys.wrapped_master_secret,
                ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len);
         sid->u.ssl3.masterValid = PR_TRUE;
         sid->u.ssl3.keys.msIsWrapped = PR_FALSE;
         rv = SECSuccess;
     } else {
         rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid,
-                                           ss->ssl3.crSpec,
-                                           ss->ssl3.hs.kea_def->authKeyType);
+                                           ss->ssl3.crSpec);
         sid->u.ssl3.keys.msIsWrapped = PR_TRUE;
     }
     ssl_ReleaseSpecReadLock(ss); /*************************************/
 
     return rv;
 }
 
 /* The return type is SECStatus instead of void because this function needs
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -435,33 +435,29 @@ ssl_GetECGroupForServerSocket(sslSocket 
     unsigned int requiredECCbits;
 
     PORT_Assert(cert);
     if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) {
         PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
         return NULL;
     }
 
-    if (cert->certType.authType == ssl_auth_rsa_sign) {
+    if (SSL_CERT_IS(cert, ssl_auth_rsa_sign) ||
+        SSL_CERT_IS(cert, ssl_auth_rsa_pss)) {
         certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
-        certKeySize =
-            SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
-    } else if (cert->certType.authType == ssl_auth_ecdsa ||
-               cert->certType.authType == ssl_auth_ecdh_rsa ||
-               cert->certType.authType == ssl_auth_ecdh_ecdsa) {
-        const sslNamedGroupDef *groupDef = cert->certType.namedCurve;
-
+        certKeySize = SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
+    } else if (SSL_CERT_IS_EC(cert)) {
         /* We won't select a certificate unless the named curve has been
          * negotiated (or supported_curves was absent), double check that. */
-        PORT_Assert(groupDef->keaType == ssl_kea_ecdh);
-        PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef));
-        if (!ssl_NamedGroupEnabled(ss, groupDef)) {
+        PORT_Assert(cert->namedCurve->keaType == ssl_kea_ecdh);
+        PORT_Assert(ssl_NamedGroupEnabled(ss, cert->namedCurve));
+        if (!ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
             return NULL;
         }
-        certKeySize = groupDef->bits;
+        certKeySize = cert->namedCurve->bits;
     } else {
         PORT_Assert(0);
         return NULL;
     }
     bulkCipher = ssl_GetBulkCipherDef(ss->ssl3.hs.suite_def);
     requiredECCbits = bulkCipher->key_size * BPB * 2;
     PORT_Assert(requiredECCbits ||
                 ss->ssl3.hs.suite_def->bulk_cipher_alg == cipher_null);
--- a/lib/ssl/ssl3exthandle.c
+++ b/lib/ssl/ssl3exthandle.c
@@ -11,31 +11,23 @@
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "blapit.h"
 #include "prinit.h"
 #include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
 
-static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
-static PK11SymKey *session_ticket_enc_key = NULL;
-static PK11SymKey *session_ticket_mac_key = NULL;
-
-static PRCallOnceType generate_session_keys_once;
-
 static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss,
                                                   SECItem *data, EncryptedSessionTicket *enc_session_ticket);
 static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
                                    PRUint32 bytes);
 static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
 static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num,
                                          PRInt32 lenSize);
-static SECStatus ssl3_GetSessionTicketKeys(sslSocket *ss,
-                                           PK11SymKey **aes_key, PK11SymKey **mac_key);
 static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
 
 /*
  * 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
@@ -71,93 +63,16 @@ ssl3_AppendNumberToItem(SECItem *item, P
             *p++ = (PRUint8)(num >> 8);
         case 1:
             *p = (PRUint8)num;
     }
     rv = ssl3_AppendToItem(item, &b[0], lenSize);
     return rv;
 }
 
-SECStatus
-ssl3_SessionTicketShutdown(void *appData, void *nssData)
-{
-    if (session_ticket_enc_key) {
-        PK11_FreeSymKey(session_ticket_enc_key);
-        session_ticket_enc_key = NULL;
-    }
-    if (session_ticket_mac_key) {
-        PK11_FreeSymKey(session_ticket_mac_key);
-        session_ticket_mac_key = NULL;
-    }
-    PORT_Memset(&generate_session_keys_once, 0,
-                sizeof(generate_session_keys_once));
-    return SECSuccess;
-}
-
-static PRStatus
-ssl3_GenerateSessionTicketKeys(void *data)
-{
-    SECStatus rv;
-    sslSocket *ss = (sslSocket *)data;
-    sslServerCertType certType = { ssl_auth_rsa_decrypt, NULL };
-    const sslServerCert *sc;
-    SECKEYPrivateKey *svrPrivKey;
-    SECKEYPublicKey *svrPubKey;
-
-    sc = ssl_FindServerCert(ss, &certType);
-    if (!sc || !sc->serverKeyPair) {
-        SSL_DBG(("%d: SSL[%d]: No ssl_auth_rsa_decrypt cert and key pair",
-                 SSL_GETPID(), ss->fd));
-        goto loser;
-    }
-    svrPrivKey = sc->serverKeyPair->privKey;
-    svrPubKey = sc->serverKeyPair->pubKey;
-    if (svrPrivKey == NULL || svrPubKey == NULL) {
-        SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.",
-                 SSL_GETPID(), ss->fd));
-        goto loser;
-    }
-
-    /* Get a copy of the session keys from shared memory. */
-    PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX,
-                sizeof(SESS_TICKET_KEY_NAME_PREFIX));
-    if (!ssl_GetSessionTicketKeys(svrPrivKey, svrPubKey, ss->pkcs11PinArg,
-                                  &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN],
-                                  &session_ticket_enc_key, &session_ticket_mac_key))
-        return PR_FAILURE;
-
-    rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL);
-    if (rv != SECSuccess)
-        goto loser;
-
-    return PR_SUCCESS;
-
-loser:
-    ssl3_SessionTicketShutdown(NULL, NULL);
-    return PR_FAILURE;
-}
-
-static SECStatus
-ssl3_GetSessionTicketKeys(sslSocket *ss, PK11SymKey **aes_key,
-                          PK11SymKey **mac_key)
-{
-    if (PR_CallOnceWithArg(&generate_session_keys_once,
-                           ssl3_GenerateSessionTicketKeys, ss) !=
-        PR_SUCCESS)
-        return SECFailure;
-
-    if (session_ticket_enc_key == NULL ||
-        session_ticket_mac_key == NULL)
-        return SECFailure;
-
-    *aes_key = session_ticket_enc_key;
-    *mac_key = session_ticket_mac_key;
-    return SECSuccess;
-}
-
 /* Format an SNI extension, using the name from the socket's URL,
  * unless that name is a dotted decimal string.
  * Used by client and server.
  */
 PRInt32
 ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                        PRUint32 maxBytes)
 {
@@ -955,32 +870,32 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
     PRBool ms_is_wrapped;
     unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH];
     SECItem ms_item = { 0, NULL, 0 };
     PRUint32 padding_length;
     PRUint32 ticket_length;
     PRUint32 cert_length = 0;
     PRUint8 length_buf[4];
     PRUint32 now;
+    unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
     PK11SymKey *aes_key = NULL;
     PK11SymKey *mac_key = NULL;
     CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
     PK11Context *aes_ctx;
     CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
     PK11Context *hmac_ctx = NULL;
     unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
     unsigned int computed_mac_length;
     unsigned char iv[AES_BLOCK_SIZE];
     SECItem ivItem;
     SECItem *srvName = NULL;
     PRUint32 srvNameLen = 0;
     CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value,
                                           * must be >= 0 */
     ssl3CipherSpec *spec;
-    const sslServerCertType *certType;
     SECItem alpnSelection = { siBuffer, NULL, 0 };
 
     SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
@@ -990,17 +905,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
 
     /* Get IV and encryption keys */
     ivItem.data = iv;
     ivItem.len = sizeof(iv);
     rv = PK11_GenerateRandom(iv, sizeof(iv));
     if (rv != SECSuccess)
         goto loser;
 
-    rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key);
+    rv = ssl_GetSessionTicketKeys(ss, key_name, &aes_key, &mac_key);
     if (rv != SECSuccess)
         goto loser;
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         spec = ss->ssl3.cwSpec;
     } else {
         spec = ss->ssl3.pwSpec;
     }
@@ -1009,18 +924,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         ms_item.data = spec->msItem.data;
         ms_item.len = spec->msItem.len;
         ms_is_wrapped = PR_FALSE;
     } else {
         /* Extract the master secret wrapped. */
         sslSessionID sid;
         PORT_Memset(&sid, 0, sizeof(sslSessionID));
 
-        rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec,
-                                           ss->ssl3.hs.kea_def->authKeyType);
+        rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec);
         if (rv == SECSuccess) {
             if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms))
                 goto loser;
             memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret,
                    sid.u.ssl3.keys.wrapped_master_secret_len);
             ms_item.data = wrapped_ms;
             ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len;
             msWrapMech = sid.u.ssl3.masterWrapMech;
@@ -1103,32 +1017,25 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4);
     if (rv != SECSuccess)
         goto loser;
 
     /* certificate type */
-    certType = &ss->sec.serverCert->certType;
-    PORT_Assert(certType->authType == ss->sec.authType);
-    switch (ss->sec.authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            PORT_Assert(certType->namedCurve);
-            PORT_Assert(certType->namedCurve->keaType == ssl_kea_ecdh);
-            /* EC curves only use the second of the two bytes. */
-            PORT_Assert(certType->namedCurve->name < 256);
-            rv = ssl3_AppendNumberToItem(&plaintext,
-                                         certType->namedCurve->name, 1);
-            break;
-        default:
-            rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
-            break;
+    PORT_Assert(SSL_CERT_IS(ss->sec.serverCert, ss->sec.authType));
+    if (SSL_CERT_IS_EC(ss->sec.serverCert)) {
+        const sslServerCert *cert = ss->sec.serverCert;
+        PORT_Assert(cert->namedCurve);
+        /* EC curves only use the second of the two bytes. */
+        PORT_Assert(cert->namedCurve->name < 256);
+        rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1);
+    } else {
+        rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
     }
     if (rv != SECSuccess)
         goto loser;
 
     /* master_secret */
     rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1);
     if (rv != SECSuccess)
         goto loser;
@@ -1345,16 +1252,17 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     SessionTicket *parsed_session_ticket = NULL;
     sslSessionID *sid = NULL;
     SSL3Statistics *ssl3stats;
     PRUint32 i;
     SECItem extension_data;
     EncryptedSessionTicket enc_session_ticket;
     unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
     unsigned int computed_mac_length;
+    unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
     PK11SymKey *aes_key = NULL;
     PK11SymKey *mac_key = NULL;
     PK11Context *hmac_ctx;
     CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
     PK11Context *aes_ctx;
     CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
     unsigned char *padding;
     PRUint32 padding_length;
@@ -1382,17 +1290,17 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     extension_data.len = data->len;
 
     if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) !=
         SECSuccess) {
         return SECSuccess; /* Pretend it isn't there */
     }
 
     /* Get session ticket keys. */
-    rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key);
+    rv = ssl_GetSessionTicketKeys(ss, key_name, &aes_key, &mac_key);
     if (rv != SECSuccess) {
         SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.",
                  SSL_GETPID(), ss->fd));
         goto loser;
     }
 
     /* If the ticket sent by the client was generated under a key different
      * from the one we have, bypass ticket processing.
@@ -1533,34 +1441,29 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     if (rv != SECSuccess)
         goto no_ticket;
     parsed_session_ticket->keaType = (SSLKEAType)temp;
     rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
     if (rv != SECSuccess)
         goto no_ticket;
     parsed_session_ticket->keaKeyBits = temp;
 
-    /* Read certificate slot */
-    parsed_session_ticket->certType.authType = parsed_session_ticket->authType;
+    /* Read the optional named curve. */
     rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
     if (rv != SECSuccess)
         goto no_ticket;
-    switch (parsed_session_ticket->authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa: {
-            const sslNamedGroupDef *group =
-                ssl_LookupNamedGroup((SSLNamedGroup)temp);
-            if (!group || group->keaType != ssl_kea_ecdh) {
-                goto no_ticket;
-            }
-            parsed_session_ticket->certType.namedCurve = group;
-        } break;
-        default:
-            break;
+    if (parsed_session_ticket->authType == ssl_auth_ecdsa ||
+        parsed_session_ticket->authType == ssl_auth_ecdh_rsa ||
+        parsed_session_ticket->authType == ssl_auth_ecdh_ecdsa) {
+        const sslNamedGroupDef *group =
+            ssl_LookupNamedGroup((SSLNamedGroup)temp);
+        if (!group || group->keaType != ssl_kea_ecdh) {
+            goto no_ticket;
+        }
+        parsed_session_ticket->namedCurve = group;
     }
 
     /* Read wrapped master_secret. */
     rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
     if (rv != SECSuccess)
         goto no_ticket;
     parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
 
@@ -1677,18 +1580,17 @@ ssl3_ProcessSessionTicketCommon(sslSocke
         /* Copy over parameters. */
         sid->version = parsed_session_ticket->ssl_version;
         sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite;
         sid->u.ssl3.compression = parsed_session_ticket->compression_method;
         sid->authType = parsed_session_ticket->authType;
         sid->authKeyBits = parsed_session_ticket->authKeyBits;
         sid->keaType = parsed_session_ticket->keaType;
         sid->keaKeyBits = parsed_session_ticket->keaKeyBits;
-        memcpy(&sid->certType, &parsed_session_ticket->certType,
-               sizeof(sslServerCertType));
+        sid->namedCurve = parsed_session_ticket->namedCurve;
 
         if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
                              &extension_data) != SECSuccess)
             goto no_ticket;
         sid->u.ssl3.locked.sessionTicket.flags = parsed_session_ticket->flags;
 
         if (parsed_session_ticket->ms_length >
             sizeof(sid->u.ssl3.keys.wrapped_master_secret))
--- a/lib/ssl/sslcert.c
+++ b/lib/ssl/sslcert.c
@@ -8,69 +8,121 @@
 
 #include "ssl.h"
 #include "sslimpl.h"
 #include "secoid.h"   /* for SECOID_GetAlgorithmTag */
 #include "pk11func.h" /* for PK11_ReferenceSlot */
 #include "nss.h"      /* for NSS_RegisterShutdown */
 #include "prinit.h"   /* for PR_CallOnceWithArg */
 
-static const PRCallOnceType pristineCallOnce;
-static PRCallOnceType setupServerCAListOnce;
+/* This global item is used only in servers.  It is is initialized by
+ * SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
+ */
+static struct {
+    PRCallOnceType setup;
+    CERTDistNames *names;
+} ssl_server_ca_list;
 
 static SECStatus
-serverCAListShutdown(void *appData, void *nssData)
+ssl_ServerCAListShutdown(void *appData, void *nssData)
 {
-    PORT_Assert(ssl3_server_ca_list);
-    if (ssl3_server_ca_list) {
-        CERT_FreeDistNames(ssl3_server_ca_list);
-        ssl3_server_ca_list = NULL;
+    PORT_Assert(ssl_server_ca_list.names);
+    if (ssl_server_ca_list.names) {
+        CERT_FreeDistNames(ssl_server_ca_list.names);
     }
-    setupServerCAListOnce = pristineCallOnce;
+    PORT_Memset(&ssl_server_ca_list, 0, sizeof(ssl_server_ca_list));
     return SECSuccess;
 }
 
 static PRStatus
-serverCAListSetup(void *arg)
+ssl_SetupCAListOnce(void *arg)
 {
     CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
-    SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
+    SECStatus rv = NSS_RegisterShutdown(ssl_ServerCAListShutdown, NULL);
     PORT_Assert(SECSuccess == rv);
     if (SECSuccess == rv) {
-        ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
+        ssl_server_ca_list.names = CERT_GetSSLCACerts(dbHandle);
         return PR_SUCCESS;
     }
     return PR_FAILURE;
 }
 
+SECStatus
+ssl_SetupCAList(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)
+{
+    SECItem *name;
+    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;
+    if (!ca_list) {
+        if (ssl_SetupCAList(ss) != SECSuccess) {
+            return SECFailure;
+        }
+        ca_list = ssl_server_ca_list.names;
+    }
+
+    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;
+    }
+    return SECSuccess;
+}
+
 sslServerCert *
-ssl_NewServerCert(const sslServerCertType *certType)
+ssl_NewServerCert()
 {
     sslServerCert *sc = PORT_ZNew(sslServerCert);
     if (!sc) {
         return NULL;
     }
-    memcpy(&sc->certType, certType, sizeof(sc->certType));
+    sc->authTypes = 0;
+    sc->namedCurve = NULL;
     sc->serverCert = NULL;
     sc->serverCertChain = NULL;
     sc->certStatusArray = NULL;
     sc->signedCertTimestamps.len = 0;
     return sc;
 }
 
 sslServerCert *
 ssl_CopyServerCert(const sslServerCert *oc)
 {
     sslServerCert *sc;
 
-    sc = ssl_NewServerCert(&oc->certType);
+    sc = ssl_NewServerCert();
     if (!sc) {
         return NULL;
     }
 
+    sc->authTypes = oc->authTypes;
+    sc->namedCurve = oc->namedCurve;
+
     if (oc->serverCert && oc->serverCertChain) {
         sc->serverCert = CERT_DupCertificate(oc->serverCert);
         if (!sc->serverCert)
             goto loser;
         sc->serverCertChain = CERT_DupCertList(oc->serverCertChain);
         if (!sc->serverCertChain)
             goto loser;
     } else {
@@ -124,88 +176,41 @@ ssl_FreeServerCert(sslServerCert *sc)
         SECITEM_FreeArray(sc->certStatusArray, PR_TRUE);
     }
     if (sc->signedCertTimestamps.len) {
         SECITEM_FreeItem(&sc->signedCertTimestamps, PR_FALSE);
     }
     PORT_ZFree(sc, sizeof(*sc));
 }
 
-sslServerCert *
-ssl_FindServerCert(const sslSocket *ss,
-                   const sslServerCertType *certType)
+const sslServerCert *
+ssl_FindServerCert(const sslSocket *ss, SSLAuthType authType,
+                   const sslNamedGroupDef *namedCurve)
 {
     PRCList *cursor;
 
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
-        if (cert->certType.authType != certType->authType) {
+        if (!SSL_CERT_IS(cert, authType)) {
             continue;
         }
-        switch (cert->certType.authType) {
-            case ssl_auth_ecdsa:
-            case ssl_auth_ecdh_rsa:
-            case ssl_auth_ecdh_ecdsa:
-                /* Note: For deprecated APIs, we need to be able to find and
-                   match a slot with any named curve. */
-                if (certType->namedCurve &&
-                    cert->certType.namedCurve != certType->namedCurve) {
-                    continue;
-                }
-                break;
-            default:
-                break;
+        if (SSL_CERT_IS_EC(cert)) {
+            /* Note: For deprecated APIs, we need to be able to find and
+               match a slot with any named curve. */
+            if (namedCurve && cert->namedCurve != namedCurve) {
+                continue;
+            }
         }
         return cert;
     }
     return NULL;
 }
 
-sslServerCert *
-ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType)
-{
-    sslServerCertType certType;
-    certType.authType = authType;
-    /* Setting the named curve to NULL ensures that all EC certificates
-     * are matched when searching for this slot. */
-    certType.namedCurve = NULL;
-    return ssl_FindServerCert(ss, &certType);
-}
-
-SECStatus
-ssl_OneTimeCertSetup(sslSocket *ss, const sslServerCert *sc)
-{
-    if (PR_SUCCESS != PR_CallOnceWithArg(&setupServerCAListOnce,
-                                         &serverCAListSetup,
-                                         (void *)(ss->dbHandle))) {
-        return SECFailure;
-    }
-    return SECSuccess;
-}
-
-/* Determine which slot a certificate fits into.  SSLAuthType is known, but
- * extra information needs to be worked out from the cert and key. */
-static void
-ssl_PopulateCertType(sslServerCertType *certType, SSLAuthType authType,
-                     CERTCertificate *cert, sslKeyPair *keyPair)
-{
-    certType->authType = authType;
-    switch (authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            certType->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey);
-            break;
-        default:
-            break;
-    }
-}
-
 static SECStatus
 ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert,
                        const CERTCertificateList *certChain)
 {
     if (sc->serverCert) {
         CERT_DestroyCertificate(sc->serverCert);
     }
     if (sc->serverCertChain) {
@@ -227,31 +232,53 @@ ssl_PopulateServerCert(sslServerCert *sc
                                    PR_TRUE);
     }
     return sc->serverCertChain ? SECSuccess : SECFailure;
 }
 
 static SECStatus
 ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair)
 {
-    /* Copy over the key pair. */
     if (sc->serverKeyPair) {
         ssl_FreeKeyPair(sc->serverKeyPair);
+        sc->serverKeyPair = NULL;
     }
     if (keyPair) {
+        KeyType keyType = SECKEY_GetPublicKeyType(keyPair->pubKey);
+        PORT_Assert(keyType == SECKEY_GetPrivateKeyType(keyPair->privKey));
+
+        if (keyType == ecKey) {
+            sc->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey);
+            if (!sc->namedCurve) {
+                /* Unsupported curve. */
+                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+                return SECFailure;
+            }
+        }
+
         /* Get the size of the cert's public key, and remember it. */
         sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
         if (sc->serverKeyBits == 0) {
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
         }
 
         SECKEY_CacheStaticFlags(keyPair->privKey);
         sc->serverKeyPair = ssl_GetKeyPairRef(keyPair);
+
+        if (SSL_CERT_IS(sc, ssl_auth_rsa_decrypt)) {
+            /* This will update the global session ticket key pair with this
+             * key, if a value hasn't been set already. */
+            if (ssl_MaybeSetSessionTicketKeyPair(keyPair) != SECSuccess) {
+                return SECFailure;
+            }
+        }
     } else {
         sc->serverKeyPair = NULL;
+        sc->namedCurve = NULL;
     }
     return SECSuccess;
 }
 
 static SECStatus
 ssl_PopulateOCSPResponses(sslServerCert *sc,
                           const SECItemArray *stapledOCSPResponses)
 {
@@ -276,84 +303,92 @@ ssl_PopulateSignedCertTimestamps(sslServ
     }
     if (signedCertTimestamps && signedCertTimestamps->len) {
         return SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
                                 signedCertTimestamps);
     }
     return SECSuccess;
 }
 
+/* Find any existing certificates that overlap with the new certificate and
+ * either remove any supported authentication types that overlap with the new
+ * certificate or - if they have no types left - remove them entirely. */
+static void
+ssl_ClearMatchingCerts(sslSocket *ss, sslAuthTypeMask authTypes,
+                       const sslNamedGroupDef *namedCurve)
+{
+    PRCList *cursor = PR_NEXT_LINK(&ss->serverCerts);
+
+    while (cursor != &ss->serverCerts) {
+        sslServerCert *sc = (sslServerCert *)cursor;
+        cursor = PR_NEXT_LINK(cursor);
+        if ((sc->authTypes & authTypes) == 0) {
+            continue;
+        }
+        /* namedCurve will be NULL only for legacy functions. */
+        if (namedCurve != NULL && sc->namedCurve != namedCurve) {
+            continue;
+        }
+
+        sc->authTypes &= ~authTypes;
+        if (sc->authTypes == 0) {
+            PR_REMOVE_LINK(&sc->link);
+            ssl_FreeServerCert(sc);
+        }
+    }
+}
+
 static SECStatus
-ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
-               sslKeyPair *keyPair, const SSLExtraServerCertData *data)
+ssl_ConfigCert(sslSocket *ss, sslAuthTypeMask authTypes,
+               CERTCertificate *cert, sslKeyPair *keyPair,
+               const SSLExtraServerCertData *data)
 {
-    sslServerCert *oldsc;
-    sslServerCertType certType;
     SECStatus rv;
     sslServerCert *sc = NULL;
     int error_code = SEC_ERROR_NO_MEMORY;
 
     PORT_Assert(cert);
     PORT_Assert(keyPair);
     PORT_Assert(data);
-    PORT_Assert(data->authType != ssl_auth_null);
+    PORT_Assert(authTypes);
 
-    if (!cert || !keyPair || !data || data->authType == ssl_auth_null) {
+    if (!cert || !keyPair || !data || !authTypes) {
         error_code = SEC_ERROR_INVALID_ARGS;
         goto loser;
     }
 
-    ssl_PopulateCertType(&certType, data->authType, cert, keyPair);
-
-    /* Delete any existing certificate that matches this one, since we can only
-     * use one certificate of a given type. */
-    oldsc = ssl_FindServerCert(ss, &certType);
-    if (oldsc) {
-        PR_REMOVE_LINK(&oldsc->link);
-        ssl_FreeServerCert(oldsc);
-    }
-    sc = ssl_NewServerCert(&certType);
+    sc = ssl_NewServerCert();
     if (!sc) {
         goto loser;
     }
 
+    sc->authTypes = authTypes;
     rv = ssl_PopulateServerCert(sc, cert, data->certChain);
     if (rv != SECSuccess) {
         goto loser;
     }
     rv = ssl_PopulateKeyPair(sc, keyPair);
     if (rv != SECSuccess) {
-        error_code = SEC_ERROR_INVALID_ARGS;
+        error_code = PORT_GetError();
         goto loser;
     }
     rv = ssl_PopulateOCSPResponses(sc, data->stapledOCSPResponses);
     if (rv != SECSuccess) {
         goto loser;
     }
     rv = ssl_PopulateSignedCertTimestamps(sc, data->signedCertTimestamps);
     if (rv != SECSuccess) {
         goto loser;
     }
+    ssl_ClearMatchingCerts(ss, sc->authTypes, sc->namedCurve);
     PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-
-    /* This one-time setup depends on having the certificate in place. */
-    rv = ssl_OneTimeCertSetup(ss, sc);
-    if (rv != SECSuccess) {
-        PR_REMOVE_LINK(&sc->link);
-        error_code = PORT_GetError();
-        goto loser;
-    }
     return SECSuccess;
 
 loser:
-    if (sc) {
-        ssl_FreeServerCert(sc);
-    }
-    /* This is the only way any of the calls above can fail, except the one time
-     * setup, which doesn't land here. */
+    ssl_FreeServerCert(sc);
     PORT_SetError(error_code);
     return SECFailure;
 }
 
 static SSLAuthType
 ssl_GetEcdhAuthType(CERTCertificate *cert)
 {
     SECOidTag sigTag = SECOID_GetAlgorithmTag(&cert->signature);
@@ -377,153 +412,100 @@ ssl_GetEcdhAuthType(CERTCertificate *cer
         case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
         case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
             return ssl_auth_ecdh_ecdsa;
         default:
             return ssl_auth_null;
     }
 }
 
-/* This function examines the key usages of the given RSA-PKCS1 certificate
- * and configures one or multiple server certificates based on that data.
+/* This function examines the type of certificate and its key usage and
+ * chooses which authTypes apply.  For some certificates
+ * this can mean that multiple authTypes.
  *
- * If the data argument contains an authType value other than ssl_auth_null,
- * then only that slot will be used.  If that choice is invalid,
- * then this will fail. */
-static SECStatus
-ssl_ConfigRsaPkcs1CertByUsage(sslSocket *ss, CERTCertificate *cert,
-                              sslKeyPair *keyPair,
-                              SSLExtraServerCertData *data)
+ * If the targetAuthType is not ssl_auth_null, then only that type will be used.
+ * If that choice is invalid, then this function will fail. */
+static sslAuthTypeMask
+ssl_GetCertificateAuthTypes(CERTCertificate *cert, SSLAuthType targetAuthType)
 {
-    SECStatus rv = SECFailure;
-
-    PRBool ku_sig = (PRBool)(cert->keyUsage & KU_DIGITAL_SIGNATURE);
-    PRBool ku_enc = (PRBool)(cert->keyUsage & KU_KEY_ENCIPHERMENT);
-
-    if ((data->authType == ssl_auth_rsa_sign && ku_sig) ||
-        (data->authType == ssl_auth_rsa_pss && ku_sig) ||
-        (data->authType == ssl_auth_rsa_decrypt && ku_enc)) {
-        return ssl_ConfigCert(ss, cert, keyPair, data);
-    }
-
-    if (data->authType != ssl_auth_null || !(ku_sig || ku_enc)) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-
-    if (ku_sig) {
-        data->authType = ssl_auth_rsa_sign;
-        rv = ssl_ConfigCert(ss, cert, keyPair, data);
-        if (rv != SECSuccess) {
-            return rv;
-        }
-
-        /* This certificate is RSA, assume that it's also PSS. */
-        data->authType = ssl_auth_rsa_pss;
-        rv = ssl_ConfigCert(ss, cert, keyPair, data);
-        if (rv != SECSuccess) {
-            return rv;
-        }
-    }
-
-    if (ku_enc) {
-        /* If ku_sig=true we configure signature and encryption slots with the
-         * same cert. This is bad form, but there are enough dual-usage RSA
-         * certs that we can't really break by limiting this to one type. */
-        data->authType = ssl_auth_rsa_decrypt;
-        rv = ssl_ConfigCert(ss, cert, keyPair, data);
-        if (rv != SECSuccess) {
-            return rv;
-        }
-    }
-
-    return rv;
-}
-
-/* This function examines the type of certificate and its key usage and
- * configures a certificate based on that information.  For some certificates
- * this can mean that multiple server certificates are configured.
- *
- * If the data argument contains an authType value other than ssl_auth_null,
- * then only that slot will be used.  If that choice is invalid,
- * then this will fail. */
-static SECStatus
-ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert,
-                      sslKeyPair *keyPair, const SSLExtraServerCertData *data)
-{
-    SECStatus rv = SECFailure;
-    SSLExtraServerCertData arg;
+    sslAuthTypeMask authTypes = 0;
     SECOidTag tag;
 
-    PORT_Assert(data);
-    /* Take a (shallow) copy so that we can play with it */
-    memcpy(&arg, data, sizeof(arg));
-
     tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
     switch (tag) {
         case SEC_OID_X500_RSA_ENCRYPTION:
         case SEC_OID_PKCS1_RSA_ENCRYPTION:
-            return ssl_ConfigRsaPkcs1CertByUsage(ss, cert, keyPair, &arg);
+            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
+                authTypes |= 1 << ssl_auth_rsa_sign;
+                /* This certificate is RSA, assume that it's also PSS. */
+                authTypes |= 1 << ssl_auth_rsa_pss;
+            }
+
+            if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
+                /* If ku_sig=true we configure signature and encryption slots with the
+                 * same cert. This is bad form, but there are enough dual-usage RSA
+                 * certs that we can't really break by limiting this to one type. */
+                authTypes |= 1 << ssl_auth_rsa_decrypt;
+            }
+            break;
 
         case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
             if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_rsa_pss;
+                authTypes |= 1 << ssl_auth_rsa_pss;
             }
             break;
 
         case SEC_OID_ANSIX9_DSA_SIGNATURE:
             if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_dsa;
+                authTypes |= 1 << ssl_auth_dsa;
             }
             break;
 
         case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
+                authTypes |= 1 << ssl_auth_ecdsa;
+            }
+            /* Again, bad form to have dual usage and we don't prevent it. */
             if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
-                if ((cert->keyUsage & KU_DIGITAL_SIGNATURE) &&
-                    arg.authType == ssl_auth_null) {
-                    /* See above regarding bad practice. */
-                    arg.authType = ssl_auth_ecdsa;
-                    rv = ssl_ConfigCert(ss, cert, keyPair, &arg);
-                    if (rv != SECSuccess) {
-                        return rv;
-                    }
-                }
-
-                arg.authType = ssl_GetEcdhAuthType(cert);
-            } else if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_ecdsa;
+                authTypes |= 1 << ssl_GetEcdhAuthType(cert);
             }
             break;
 
         default:
             break;
     }
 
     /* Check that we successfully picked an authType */
-    if (arg.authType == ssl_auth_null) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
+    if (targetAuthType != ssl_auth_null) {
+        authTypes &= 1 << targetAuthType;
     }
-    /* |data->authType| has to either agree or be ssl_auth_null. */
-    if (data && data->authType != ssl_auth_null &&
-        data->authType != arg.authType) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-    return ssl_ConfigCert(ss, cert, keyPair, &arg);
+    return authTypes;
 }
 
 /* This function adopts pubKey and destroys it if things go wrong. */
 static sslKeyPair *
-ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey)
+ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, CERTCertificate *cert)
 {
     sslKeyPair *keyPair = NULL;
+    SECKEYPublicKey *pubKey = NULL;
     SECKEYPrivateKey *privKeyCopy = NULL;
     PK11SlotInfo *bestSlot;
 
+    pubKey = CERT_ExtractPublicKey(cert);
+    if (!pubKey) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return NULL;
+    }
+
+    if (SECKEY_GetPublicKeyType(pubKey) != SECKEY_GetPrivateKeyType(key)) {
+        SECKEY_DestroyPublicKey(pubKey);
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
     if (key->pkcs11Slot) {
         bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
         if (bestSlot) {
             privKeyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
             PK11_FreeSlot(bestSlot);
         }
     }
     if (!privKeyCopy) {
@@ -540,43 +522,41 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey 
     }
     if (privKeyCopy) {
         keyPair = ssl_NewKeyPair(privKeyCopy, pubKey);
     }
     if (!keyPair) {
         if (privKeyCopy) {
             SECKEY_DestroyPrivateKey(privKeyCopy);
         }
-        /* We adopted the public key, so we're responsible. */
-        if (pubKey) {
-            SECKEY_DestroyPublicKey(pubKey);
-        }
+        SECKEY_DestroyPublicKey(pubKey);
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
     }
     return keyPair;
 }
 
 /* Configure a certificate and private key.
  *
- * This function examines the certificate and key to determine which slot (or
- * slots) to place the information in.  As long as certificates are different
- * (based on having different values of sslServerCertType), then this function
- * can be called multiple times and the certificates will all be remembered.
+ * This function examines the certificate and key to determine the type (or
+ * types) of authentication the certificate supports.  As long as certificates
+ * are different (different authTypes and maybe keys in different ec groups),
+ * then this function can be called multiple times.
  */
 SECStatus
 SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
                      SECKEYPrivateKey *key,
                      const SSLExtraServerCertData *data, unsigned int data_len)
 {
     sslSocket *ss;
-    SECKEYPublicKey *pubKey;
     sslKeyPair *keyPair;
     SECStatus rv;
     SSLExtraServerCertData dataCopy = {
         ssl_auth_null, NULL, NULL, NULL
     };
+    sslAuthTypeMask authTypes;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         return SECFailure;
     }
 
     if (!cert || !key) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -586,31 +566,33 @@ SSL_ConfigServerCert(PRFileDesc *fd, CER
     if (data) {
         if (data_len > sizeof(dataCopy)) {
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
         }
         PORT_Memcpy(&dataCopy, data, data_len);
     }
 
-    pubKey = CERT_ExtractPublicKey(cert);
-    if (!pubKey) {
+    authTypes = ssl_GetCertificateAuthTypes(cert, dataCopy.authType);
+    if (!authTypes) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    keyPair = ssl_MakeKeyPairForCert(key, pubKey);
+    keyPair = ssl_MakeKeyPairForCert(key, cert);
     if (!keyPair) {
-        /* pubKey is adopted by ssl_MakeKeyPairForCert() */
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
         return SECFailure;
     }
 
-    rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy);
+    rv = ssl_ConfigCert(ss, authTypes, cert, keyPair, &dataCopy);
     ssl_FreeKeyPair(keyPair);
-    return rv;
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    return SECSuccess;
 }
 
 /*******************************************************************/
 /* Deprecated functions.
  *
  * The remainder of this file contains deprecated functions for server
  * certificate configuration.  These configure certificates incorrectly, but in
  * a way that allows old code to continue working without change.  All these
@@ -625,351 +607,291 @@ SSL_ConfigSecureServer(PRFileDesc *fd, C
     return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea);
 }
 
 /* This implements a limited check that is consistent with the checks performed
  * by older versions of NSS.  This is less rigorous than the checks in
  * ssl_ConfigCertByUsage(), only checking against the type of key and ignoring
  * things like usage. */
 static PRBool
-ssl_CertSuitableForAuthType(CERTCertificate *cert, SSLAuthType authType)
+ssl_CertSuitableForAuthType(CERTCertificate *cert, sslAuthTypeMask authTypes)
 {
     SECOidTag tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
-    switch (authType) {
-        case ssl_auth_rsa_decrypt:
-        case ssl_auth_rsa_sign:
-            return tag == SEC_OID_X500_RSA_ENCRYPTION ||
-                   tag == SEC_OID_PKCS1_RSA_ENCRYPTION;
-        case ssl_auth_dsa:
-            return tag == SEC_OID_ANSIX9_DSA_SIGNATURE;
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            return tag == SEC_OID_ANSIX962_EC_PUBLIC_KEY;
-        case ssl_auth_null:
-        case ssl_auth_kea:
-        case ssl_auth_rsa_pss: /* not supported with deprecated APIs */
-            return PR_FALSE;
+    sslAuthTypeMask mask = 0;
+    switch (tag) {
+        case SEC_OID_X500_RSA_ENCRYPTION:
+        case SEC_OID_PKCS1_RSA_ENCRYPTION:
+            mask |= 1 << ssl_auth_rsa_decrypt;
+            mask |= 1 << ssl_auth_rsa_sign;
+            break;
+        case SEC_OID_ANSIX9_DSA_SIGNATURE:
+            mask |= 1 << ssl_auth_dsa;
+            break;
+        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+            mask |= 1 << ssl_auth_ecdsa;
+            mask |= 1 << ssl_auth_ecdh_rsa;
+            mask |= 1 << ssl_auth_ecdh_ecdsa;
+            break;
         default:
-            PORT_Assert(0);
-            return PR_FALSE;
+            break;
     }
+    PORT_Assert(authTypes);
+    /* Simply test that no inappropriate auth types are set. */
+    return (authTypes & ~mask) == 0;
 }
 
-/* This finds an existing server cert slot and unlinks it, or it makes a new
+/* Lookup a cert for the legacy configuration functions.  An exact match on
+ * authTypes and ignoring namedCurve will ensure that values configured using
+ * legacy functions are overwritten by other legacy functions. */
+static sslServerCert *
+ssl_FindCertWithMask(sslSocket *ss, sslAuthTypeMask authTypes)
+{
+    PRCList *cursor;
+
+    for (cursor = PR_NEXT_LINK(&ss->serverCerts);
+         cursor != &ss->serverCerts;
+         cursor = PR_NEXT_LINK(cursor)) {
+        sslServerCert *cert = (sslServerCert *)cursor;
+        if (cert->authTypes == authTypes) {
+            return cert;
+        }
+    }
+    return NULL;
+}
+
+/* This finds an existing server cert in a matching slot that can be reused.
+ * Failing that, it removes any other certs that might conflict and makes a new
  * server cert slot of the right type. */
 static sslServerCert *
-ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType)
+ssl_FindOrMakeCert(sslSocket *ss, sslAuthTypeMask authTypes)
 {
     sslServerCert *sc;
-    sslServerCertType certType;
 
-    certType.authType = authType;
-    /* Setting the named curve to NULL ensures that all EC certificates
-     * are matched when searching for this slot. */
-    certType.namedCurve = NULL;
-    sc = ssl_FindServerCert(ss, &certType);
+    /* Reuse a perfect match.  Note that there is a problem here with use of
+     * multiple EC certificates that have keys on different curves: these
+     * deprecated functions will match the first found and overwrite that
+     * certificate, potentially leaving the other values with a duplicate curve.
+     * Configuring multiple EC certificates are only possible with the new
+     * functions, so this is not something that is worth fixing.  */
+    sc = ssl_FindCertWithMask(ss, authTypes);
     if (sc) {
         PR_REMOVE_LINK(&sc->link);
         return sc;
     }
 
-    return ssl_NewServerCert(&certType);
+    /* Ignore the namedCurve parameter. Like above, this means that legacy
+     * functions will clobber values set with the new functions blindly. */
+    ssl_ClearMatchingCerts(ss, authTypes, NULL);
+
+    sc = ssl_NewServerCert();
+    if (sc) {
+        sc->authTypes = authTypes;
+    }
+    return sc;
 }
 
-static void
-ssl_RemoveCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType)
+static sslAuthTypeMask
+ssl_KeaTypeToAuthTypeMask(SSLKEAType keaType)
 {
-    sslServerCert *sc;
+    switch (keaType) {
+        case ssl_kea_rsa:
+            return (1 << ssl_auth_rsa_decrypt) |
+                   (1 << ssl_auth_rsa_sign);
 
-    sc = ssl_FindServerCertByAuthType(ss, authType);
-    if (sc) {
-        (void)ssl_PopulateServerCert(sc, NULL, NULL);
-        (void)ssl_PopulateKeyPair(sc, NULL);
-        /* Leave the entry linked here because the old API expects that.  There
-         * might be OCSP stapling values or signed certificate timestamps still
-         * present that will subsequently be used. */
-        /* For ECC certificates, also leave the namedCurve parameter on the slot
-         * unchanged; the value will be updated when a key is added. */
+        case ssl_kea_dh:
+            return 1 << ssl_auth_dsa;
+
+        case ssl_kea_ecdh:
+            return (1 << ssl_auth_ecdsa) |
+                   (1 << ssl_auth_ecdh_rsa) |
+                   (1 << ssl_auth_ecdh_ecdsa);
+
+        default:
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
     }
+    return 0;
 }
 
 static SECStatus
-ssl_AddCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType,
-                            CERTCertificate *cert,
-                            const CERTCertificateList *certChainOpt,
-                            sslKeyPair *keyPair)
+ssl_AddCertChain(sslSocket *ss, CERTCertificate *cert,
+                 const CERTCertificateList *certChainOpt,
+                 SECKEYPrivateKey *key, sslAuthTypeMask authTypes)
 {
     sslServerCert *sc;
+    sslKeyPair *keyPair;
     SECStatus rv;
+    PRErrorCode err = SEC_ERROR_NO_MEMORY;
 
-    if (!ssl_CertSuitableForAuthType(cert, authType)) {
+    if (!ssl_CertSuitableForAuthType(cert, authTypes)) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    sc = ssl_FindOrMakeCertType(ss, authType);
+    sc = ssl_FindOrMakeCert(ss, authTypes);
     if (!sc) {
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    rv = ssl_PopulateServerCert(sc, cert, certChainOpt);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    keyPair = ssl_MakeKeyPairForCert(key, cert);
+    if (!keyPair) {
         return SECFailure;
     }
     rv = ssl_PopulateKeyPair(sc, keyPair);
+    ssl_FreeKeyPair(keyPair);
     if (rv != SECSuccess) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        goto loser;
-    }
-    /* Now that we have a key pair, update the details of the slot. Many of the
-     * legacy functions create a slot with a namedCurve of NULL, which
-     * makes the slot unusable; this corrects that. */
-    ssl_PopulateCertType(&sc->certType, authType, cert, keyPair);
-    rv = ssl_PopulateServerCert(sc, cert, certChainOpt);
-    if (rv != SECSuccess) {
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        err = PORT_GetError();
         goto loser;
     }
-    PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-    return ssl_OneTimeCertSetup(ss, sc);
-loser:
-    ssl_FreeServerCert(sc);
-    return SECFailure;
-}
-
-static SECStatus
-ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert,
-                  const CERTCertificateList *certChainOpt,
-                  SECKEYPrivateKey *key, SSLKEAType certType)
-{
-    SECKEYPublicKey *pubKey;
-    sslKeyPair *keyPair;
-    SECStatus rv;
-
-    pubKey = CERT_ExtractPublicKey(cert);
-    if (!pubKey) {
-        return SECFailure;
-    }
 
-    keyPair = ssl_MakeKeyPairForCert(key, pubKey);
-    if (!keyPair) {
-        /* Note: pubKey is adopted or freed by ssl_MakeKeyPairForCert()
-         * depending on whether it succeeds or not. */
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
-        return SECFailure;
-    }
-
-    switch (certType) {
-        case ssl_kea_rsa:
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt,
-                                             cert, certChainOpt, keyPair);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign,
-                                             cert, certChainOpt, keyPair);
-            break;
+    PR_APPEND_LINK(&sc->link, &ss->serverCerts);
+    return SECSuccess;
 
-        case ssl_kea_dh:
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa,
-                                             cert, certChainOpt, keyPair);
-            break;
-
-        case ssl_kea_ecdh:
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdsa,
-                                             cert, certChainOpt, keyPair);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_GetEcdhAuthType(cert),
-                                             cert, certChainOpt, keyPair);
-            break;
-
-        default:
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            rv = SECFailure;
-            break;
-    }
-
-    ssl_FreeKeyPair(keyPair);
-    return rv;
+loser:
+    ssl_FreeServerCert(sc);
+    PORT_SetError(err);
+    return SECFailure;
 }
 
 /* Public deprecated function */
 SECStatus
 SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
                                     const CERTCertificateList *certChainOpt,
                                     SECKEYPrivateKey *key, SSLKEAType certType)
 {
     sslSocket *ss;
+    sslAuthTypeMask authTypes;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         return SECFailure;
     }
 
     if (!cert != !key) { /* Configure both, or neither */
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    if (!cert) {
-        switch (certType) {
-            case ssl_kea_rsa:
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt);
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_sign);
-                break;
+    authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+    if (!authTypes) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
 
-            case ssl_kea_dh:
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa);
-                break;
-
-            case ssl_kea_ecdh:
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdsa);
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_rsa);
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_ecdsa);
-                break;
-
-            default:
-                PORT_SetError(SEC_ERROR_INVALID_ARGS);
-                return SECFailure;
+    if (!cert) {
+        sslServerCert *sc = ssl_FindCertWithMask(ss, authTypes);
+        if (sc) {
+            (void)ssl_PopulateServerCert(sc, NULL, NULL);
+            (void)ssl_PopulateKeyPair(sc, NULL);
+            /* Leave the entry linked here because the old API expects that.
+             * There might be OCSP stapling values or signed certificate
+             * timestamps still present that will subsequently be used. */
         }
         return SECSuccess;
     }
 
-    return ssl_AddCertsByKEA(ss, cert, certChainOpt, key, certType);
-}
-
-static SECStatus
-ssl_SetOCSPResponsesInSlot(sslSocket *ss, SSLAuthType authType,
-                           const SECItemArray *responses)
-{
-    sslServerCert *sc;
-    SECStatus rv;
-
-    sc = ssl_FindOrMakeCertType(ss, authType);
-    if (!sc) {
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
-        return SECFailure;
-    }
-    rv = ssl_PopulateOCSPResponses(sc, responses);
-    if (rv == SECSuccess) {
-        PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-    } else {
-        ssl_FreeServerCert(sc);
-    }
-    return rv;
+    return ssl_AddCertChain(ss, cert, certChainOpt, key, authTypes);
 }
 
 /* Public deprecated function */
 SECStatus
 SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
                             SSLKEAType certType)
 {
     sslSocket *ss;
+    sslServerCert *sc;
+    sslAuthTypeMask authTypes;
     SECStatus rv;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetStapledOCSPResponses",
                  SSL_GETPID(), fd));
         return SECFailure;
     }
 
-    switch (certType) {
-        case ssl_kea_rsa:
-            rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_decrypt, responses);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_sign, responses);
-
-        case ssl_kea_dh:
-            return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_dsa, responses);
-
-        case ssl_kea_ecdh:
-            rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdsa, responses);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_rsa, responses);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_ecdsa, responses);
-
-        default:
-            SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses",
-                     SSL_GETPID(), fd));
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            return SECFailure;
-    }
-}
-
-static SECStatus
-ssl_SetSignedTimestampsInSlot(sslSocket *ss, SSLAuthType authType,
-                              const SECItem *scts)
-{
-    sslServerCert *sc;
-    SECStatus rv;
-
-    sc = ssl_FindOrMakeCertType(ss, authType);
-    if (!sc) {
-        PORT_SetError(SEC_ERROR_NO_MEMORY);
+    authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+    if (!authTypes) {
+        SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses",
+                 SSL_GETPID(), fd));
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
-    rv = ssl_PopulateSignedCertTimestamps(sc, scts);
+
+    if (!responses) {
+        sc = ssl_FindCertWithMask(ss, authTypes);
+        if (sc) {
+            (void)ssl_PopulateOCSPResponses(sc, NULL);
+        }
+        return SECSuccess;
+    }
+
+    sc = ssl_FindOrMakeCert(ss, authTypes);
+    if (!sc) {
+        return SECFailure;
+    }
+
+    rv = ssl_PopulateOCSPResponses(sc, responses);
     if (rv == SECSuccess) {
         PR_APPEND_LINK(&sc->link, &ss->serverCerts);
     } else {
         ssl_FreeServerCert(sc);
     }
     return rv;
 }
 
 /* Public deprecated function */
 SECStatus
 SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts,
                             SSLKEAType certType)
 {
     sslSocket *ss;
+    sslServerCert *sc;
+    sslAuthTypeMask authTypes;
     SECStatus rv;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSignedCertTimestamps",
                  SSL_GETPID(), fd));
         return SECFailure;
     }
 
-    switch (certType) {
-        case ssl_kea_rsa:
-            rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_decrypt, scts);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_sign, scts);
-
-        case ssl_kea_dh:
-            return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts);
+    authTypes = ssl_KeaTypeToAuthTypeMask(certType);
+    if (!authTypes) {
+        SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps",
+                 SSL_GETPID(), fd));
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
 
-        case ssl_kea_ecdh:
-            rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, scts);
+    if (!scts) {
+        sc = ssl_FindCertWithMask(ss, authTypes);
+        if (sc) {
+            (void)ssl_PopulateSignedCertTimestamps(sc, NULL);
+        }
+        return SECSuccess;
+    }
 
-        default:
-            SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps",
-                     SSL_GETPID(), fd));
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            return SECFailure;
+    sc = ssl_FindOrMakeCert(ss, authTypes);
+    if (!sc) {
+        return SECFailure;
     }
+
+    rv = ssl_PopulateSignedCertTimestamps(sc, scts);
+    if (rv == SECSuccess) {
+        PR_APPEND_LINK(&sc->link, &ss->serverCerts);
+    } else {
+        ssl_FreeServerCert(sc);
+    }
+    return rv;
 }
 
 /* Public deprecated function. */
 SSLKEAType
 NSS_FindCertKEAType(CERTCertificate *cert)
 {
     int tag;
 
--- a/lib/ssl/sslcert.h
+++ b/lib/ssl/sslcert.h
@@ -8,52 +8,53 @@
 
 #ifndef __sslcert_h_
 #define __sslcert_h_
 
 #include "cert.h"
 #include "secitem.h"
 #include "keyhi.h"
 
-/* The following struct identifies a single slot into which a certificate can be
-** loaded.  The authType field determines the basic slot, then additional
-** parameters further narrow the slot.
-**
-** An EC key (ssl_auth_ecdsa or ssl_auth_ecdh_*) is assigned to a slot based on
-** the named curve of the key.
-*/
-typedef struct sslServerCertTypeStr {
-    SSLAuthType authType;
+/* This type is a bitvector that is indexed by SSLAuthType values.  Note that
+ * the bit for ssl_auth_null(0) - the least significant bit - isn't used. */
+typedef PRUint16 sslAuthTypeMask;
+PR_STATIC_ASSERT(sizeof(sslAuthTypeMask) * 8 >= ssl_auth_size);
+
+typedef struct sslServerCertStr {
+    PRCList link; /* The linked list link */
+
+    /* The auth types that this certificate provides. */
+    sslAuthTypeMask authTypes;
     /* For ssl_auth_ecdsa and ssl_auth_ecdh_*.  This is only the named curve
      * of the end-entity certificate key.  The keys in other certificates in
      * the chain aren't directly relevant to the operation of TLS (though it
      * might make certificate validation difficult, libssl doesn't care). */
     const sslNamedGroupDef *namedCurve;
-} sslServerCertType;
-
-typedef struct sslServerCertStr {
-    PRCList link; /* The linked list link */
-
-    sslServerCertType certType; /* The certificate slot this occupies */
 
     /* Configuration state for server sockets */
     CERTCertificate *serverCert;
     CERTCertificateList *serverCertChain;
     sslKeyPair *serverKeyPair;
     unsigned int serverKeyBits;
     /* Each certificate needs its own status. */
     SECItemArray *certStatusArray;
     /* Serialized signed certificate timestamps to be sent to the client
     ** in a TLS extension (server only). Each certificate needs its own
     ** timestamps item.
     */
     SECItem signedCertTimestamps;
 } sslServerCert;
 
-extern sslServerCert *ssl_NewServerCert(const sslServerCertType *slot);
+#define SSL_CERT_IS(c, t) ((c)->authTypes & (1 << (t)))
+#define SSL_CERT_IS_ONLY(c, t) ((c)->authTypes == (1 << (t)))
+#define SSL_CERT_IS_EC(c)                         \
+    ((c)->authTypes & ((1 << ssl_auth_ecdsa) |    \
+                       (1 << ssl_auth_ecdh_rsa) | \
+                       (1 << ssl_auth_ecdh_ecdsa)))
+
+extern sslServerCert *ssl_NewServerCert();
 extern sslServerCert *ssl_CopyServerCert(const sslServerCert *oc);
-extern sslServerCert *ssl_FindServerCert(const sslSocket *ss,
-                                         const sslServerCertType *slot);
-extern sslServerCert *ssl_FindServerCertByAuthType(const sslSocket *ss,
-                                                   SSLAuthType authType);
+extern const sslServerCert *ssl_FindServerCert(
+    const sslSocket *ss, SSLAuthType authType,
+    const sslNamedGroupDef *namedCurve);
 extern void ssl_FreeServerCert(sslServerCert *sc);
 
 #endif /* __sslcert_h_ */
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -120,17 +120,18 @@ typedef enum { SSLAppOpRead = 0,
 #define SSL3_SESSIONID_BYTES 32
 
 #define SSL_MIN_CHALLENGE_BYTES 16
 #define SSL_MAX_CHALLENGE_BYTES 32
 
 #define SSL3_MASTER_SECRET_LENGTH 48
 
 /* number of wrap mechanisms potentially used to wrap master secrets. */
-#define SSL_NUM_WRAP_MECHS 16
+#define SSL_NUM_WRAP_MECHS 15
+#define SSL_NUM_WRAP_KEYS 6
 
 /* This makes the cert cache entry exactly 4k. */
 #define SSL_MAX_CACHED_CERT_LEN 4060
 
 #ifndef BPB
 #define BPB 8 /* Bits Per Byte */
 #endif
 
@@ -525,20 +526,20 @@ struct sslSessionIDStr {
     int references;
     PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */
 
     /* The rest of the members, except for the members of u.ssl3.locked, may
      * be modified only when the sid is not in any cache.
      */
 
     CERTCertificate *peerCert;
-    SECItemArray peerCertStatus; /* client only */
-    const char *peerID;          /* client only */
-    const char *urlSvrName;      /* client only */
-    sslServerCertType certType;
+    SECItemArray peerCertStatus;        /* client only */
+    const char *peerID;                 /* client only */
+    const char *urlSvrName;             /* client only */
+    const sslNamedGroupDef *namedCurve; /* (server) for certificate lookup */
     CERTCertificate *localCert;
 
     PRIPv6Addr addr;
     PRUint16 port;
 
     SSL3ProtocolVersion version;
 
     PRUint32 creationTime;   /* seconds since Jan 1, 1970 */
@@ -978,31 +979,32 @@ struct ssl3DHParamsStr {
 
 typedef struct SSLWrappedSymWrappingKeyStr {
     SSL3Opaque wrappedSymmetricWrappingkey[512];
     CK_MECHANISM_TYPE symWrapMechanism;
     /* unwrapped symmetric wrapping key uses this mechanism */
     CK_MECHANISM_TYPE asymWrapMechanism;
     /* mechanism used to wrap the SymmetricWrappingKey using
      * server's public and/or private keys. */
-    SSLAuthType authType; /* type of keys used to wrap SymWrapKey*/
-    PRInt32 symWrapMechIndex;
+    PRInt16 wrapMechIndex;
+    PRUint16 wrapKeyIndex;
     PRUint16 wrappedSymKeyLen;
 } SSLWrappedSymWrappingKey;
 
 typedef struct SessionTicketStr {
     PRUint16 ticket_version;
     SSL3ProtocolVersion ssl_version;
     ssl3CipherSuite cipher_suite;
     SSLCompressionMethod compression_method;
     SSLAuthType authType;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
-    sslServerCertType certType;
+    const sslNamedGroupDef *namedCurve; /* For certificate lookup. */
+
     /*
      * msWrapMech contains a meaningful value only if ms_is_wrapped is true.
      */
     PRUint8 ms_is_wrapped;
     CK_MECHANISM_TYPE msWrapMech;
     PRUint16 ms_length;
     SSL3Opaque master_secret[48];
     PRBool extendedMasterSecretUsed;
@@ -1223,17 +1225,16 @@ struct sslSocketStr {
 /* All the global data items declared here should be protected using the
 ** ssl_global_data_lock, which is a reader/writer lock.
 */
 extern NSSRWLock *ssl_global_data_lock;
 extern char ssl_debug;
 extern char ssl_trace;
 extern FILE *ssl_trace_iob;
 extern FILE *ssl_keylog_iob;
-extern CERTDistNames *ssl3_server_ca_list;
 extern PRUint32 ssl_sid_timeout;
 extern PRUint32 ssl3_sid_timeout;
 
 extern const char *const ssl3_cipherName[];
 
 extern sslSessionIDLookupFunc ssl_sid_lookup;
 extern sslSessionIDCacheFunc ssl_sid_cache;
 extern sslSessionIDUncacheFunc ssl_sid_uncache;
@@ -1679,31 +1680,29 @@ extern SECStatus ssl_ParseSignatureSchem
                                            unsigned int *len);
 extern SECStatus ssl_ConsumeSignatureScheme(
     sslSocket *ss, SSL3Opaque **b, PRUint32 *length, SSLSignatureScheme *out);
 extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
                                  SECKEYPrivateKey *key, SECItem *buf);
 extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
                                          SSL3Hashes *hash, SECItem *buf);
 extern SECStatus ssl3_CacheWrappedMasterSecret(
-    sslSocket *ss, sslSessionID *sid,
-    ssl3CipherSpec *spec, SSLAuthType authType);
+    sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec);
 extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
 
 /* Hello Extension related routines. */
 extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
                                      /*in/out*/ NewSessionTicket *session_ticket);
 SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
                                    const NewSessionTicket *ticket_input,
                                    SECItem *ticket_data);
-extern PRBool ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey,
-                                       SECKEYPublicKey *svrPubKey, void *pwArg,
-                                       unsigned char *keyName, PK11SymKey **aesKey,
-                                       PK11SymKey **macKey);
-extern SECStatus ssl3_SessionTicketShutdown(void *appData, void *nssData);
+SECStatus ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair);
+SECStatus ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName,
+                                   PK11SymKey **encKey, PK11SymKey **macKey);
+void ssl_ResetSessionTicketKeys();
 
 /* Tell clients to consider tickets valid for this long. */
 #define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
 #define TLS_EX_SESS_TICKET_VERSION (0x0103)
 
 extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
                                             unsigned int length);
 
@@ -1711,30 +1710,30 @@ extern SECStatus ssl3_ValidateNextProtoN
 extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
 extern void ssl_FreePRSocket(PRFileDesc *fd);
 
 /* Internal config function so SSL3 can initialize the present state of
  * various ciphers */
 extern int ssl3_config_match_init(sslSocket *);
 
 /* calls for accessing wrapping keys across processes. */
-extern PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType,
+extern SECStatus
+ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
                    SSLWrappedSymWrappingKey *wswk);
 
 /* The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the file on disk.
  * If it is uninitialized, this function writes the caller's value into
  * the disk entry, and returns false.
  * Otherwise, it overwrites the caller's wswk with the value obtained from
  * the disk, and returns PR_TRUE.
  * This is all done while holding the locks/semaphores necessary to make
  * the operation atomic.
  */
-extern PRBool
+extern SECStatus
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk);
 
 /* get rid of the symmetric wrapping key references. */
 extern SECStatus SSL3_ShutdownServerCache(void);
 
 extern SECStatus ssl_InitSymWrapKeysLock(void);
 
 extern SECStatus ssl_FreeSymWrapKeysLock(void);
@@ -1789,18 +1788,18 @@ 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);
-void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp,
-                                   int *nnamesp);
+SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp,
+                                       SECItem **namesp, unsigned int *nnamesp);
 SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b,
                                           PRUint32 *length, PLArenaPool *arena,
                                           CERTDistNames *ca_list);
 SECStatus ssl3_CompleteHandleCertificateRequest(
     sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
     unsigned int signatureSchemeCount, CERTDistNames *ca_list);
 SECStatus ssl3_SendServerHello(sslSocket *ss);
 SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
@@ -1810,17 +1809,16 @@ SECStatus ssl3_ComputeHandshakeHashes(ss
 SECStatus ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss,
                                          const sslNamedGroupDef *ecGroup,
                                          sslEphemeralKeyPair **keyPair);
 SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
                                    const sslNamedGroupDef *ecGroup);
 SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
 PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
                                 PK11SlotInfo *masterSecretSlot,
-                                const sslServerCert *serverCert,
                                 CK_MECHANISM_TYPE masterWrapMech,
                                 void *pwArg);
 SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
 const ssl3BulkCipherDef *
 ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
 SECStatus ssl3_SelectServerCert(sslSocket *ss);
 SECStatus ssl_PickSignatureScheme(sslSocket *ss,
--- a/lib/ssl/sslsnce.c
+++ b/lib/ssl/sslsnce.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This file implements the SERVER Session ID cache.
  * NOTE:  The contents of this file are NOT used by the client.
  *
  * 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/. */
 
 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
@@ -28,17 +29,17 @@
  * struct {
  *     cacheDescriptor          desc;
  *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
  *     sidCacheLock             keyCacheLock;
  *     sidCacheLock             certCacheLock;
  *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
  *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
  *     certCacheEntry           certCacheData[numCertCacheEntries];
- *     SSLWrappedSymWrappingKey keyCacheData[ssl_auth_size][SSL_NUM_WRAP_MECHS];
+ *     SSLWrappedSymWrappingKey keyCacheData[SSL_NUM_WRAP_KEYS][SSL_NUM_WRAP_MECHS];
  *     PRUint8                  keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
  *     encKeyCacheEntry         ticketEncKey; // Wrapped
  *     encKeyCacheEntry         ticketMacKey; // Wrapped
  *     PRBool                   ticketKeysValid;
  *     sidCacheLock             srvNameCacheLock;
  *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
  * } cacheMemCacheData;
  */
@@ -49,16 +50,17 @@
 #include "cert.h"
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "pk11func.h"
 #include "base64.h"
 #include "keyhi.h"
 #include "blapit.h"
+#include "nss.h" /* for NSS_RegisterShutdown */
 #include "sechash.h"
 
 #include <stdio.h>
 
 #if defined(XP_UNIX) || defined(XP_BEOS)
 
 #include <syslog.h>
 #include <fcntl.h>
@@ -104,17 +106,17 @@ struct sidCacheEntryStr {
             /*  2 */ PRUint16 compression; /* SSLCompressionMethod */
 
             /* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
 
             /*  4 */ PRUint32 masterWrapMech;
             /*  4 */ PRInt32 certIndex;
             /*  4 */ PRInt32 srvNameIndex;
             /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
-            /*  2 */ PRUint16 certTypeArgs;
+            /*  2 */ PRUint16 namedCurve;
 /*104 */} ssl3;
 
 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */
 struct {
     /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
 } forceSize;
     } u;
 };
@@ -435,27 +437,22 @@ ConvertFromSID(sidCacheEntry *to, sslSes
     to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression;
     to->u.ssl3.keys = from->u.ssl3.keys;
     to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
     to->sessionIDLength = from->u.ssl3.sessionIDLength;
     to->u.ssl3.certIndex = -1;
     to->u.ssl3.srvNameIndex = -1;
     PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
                 to->sessionIDLength);
-    to->u.ssl3.certTypeArgs = 0U;
-    switch (from->authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            PORT_Assert(from->certType.namedCurve);
-            to->u.ssl3.certTypeArgs =
-                (PRUint16)from->certType.namedCurve->name;
-            break;
-        default:
-            break;
+    to->u.ssl3.namedCurve = 0U;
+    if (from->authType == ssl_auth_ecdsa ||
+        from->authType == ssl_auth_ecdh_rsa ||
+        from->authType == ssl_auth_ecdh_ecdsa) {
+        PORT_Assert(from->namedCurve);
+        to->u.ssl3.namedCurve = (PRUint16)from->namedCurve->name;
     }
 
     SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
                 "cipherSuite=%d",
                 myPid, to->creationTime, to->addr.pr_s6_addr32[0],
                 to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
                 to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
 }
@@ -521,26 +518,21 @@ ConvertToSID(sidCacheEntry *from,
         derCert.len = pcce->certLength;
         derCert.data = pcce->cert;
 
         to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
                                                PR_FALSE, PR_TRUE);
         if (to->peerCert == NULL)
             goto loser;
     }
-    to->certType.authType = from->authType;
-    switch (from->authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            to->certType.namedCurve =
-                ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.certTypeArgs);
-            break;
-        default:
-            break;
+    if (from->authType == ssl_auth_ecdsa ||
+        from->authType == ssl_auth_ecdh_rsa ||
+        from->authType == ssl_auth_ecdh_ecdsa) {
+        to->namedCurve =
+            ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.namedCurve);
     }
 
     to->version = from->version;
     to->creationTime = from->creationTime;
     to->lastAccessTime = from->lastAccessTime;
     to->expirationTime = from->expirationTime;
     to->cached = in_server_cache;
     to->addr = from->addr;
@@ -978,17 +970,17 @@ InitCache(cacheDesc *cache, int maxCache
     }
     ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
     cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
     cache->certCacheSize =
         (char *)cache->keyCacheData - (char *)cache->certCacheData;
 
-    cache->numKeyCacheEntries = ssl_auth_size * SSL_NUM_WRAP_MECHS;
+    cache->numKeyCacheEntries = SSL_NUM_WRAP_KEYS * SSL_NUM_WRAP_MECHS;
     ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
 
     cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
 
     cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
     ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
                       SESS_TICKET_KEY_VAR_NAME_LEN);
@@ -1603,97 +1595,312 @@ StopLockPoller(cacheDesc *cache)
     return SECSuccess;
 }
 #endif
 
 /************************************************************************
  *  Code dealing with shared wrapped symmetric wrapping keys below      *
  ************************************************************************/
 
-/* If now is zero, it implies that the lock is not held, and must be
-** aquired here.
-*/
+/* The asymmetric key we use for wrapping the symmetric ticket keys. This is a
+ * global structure that can be initialized without a socket. Access is
+ * synchronized on the reader-writer lock. This is setup either by calling
+ * SSL_SetSessionTicketKeyPair() or by configuring a certificate of the
+ * ssl_auth_rsa_decrypt type. */
+static struct {
+    PRCallOnceType setup;
+    PRRWLock *lock;
+    SECKEYPublicKey *pubKey;
+    SECKEYPrivateKey *privKey;
+    PRBool configured;
+} ssl_session_ticket_key_pair;
+
+/* The symmetric ticket keys. This requires a socket to construct and requires
+ * that the global structure be initialized before use. */
+static struct {
+    PRCallOnceType setup;
+    unsigned char keyName[SESS_TICKET_KEY_NAME_LEN];
+    PK11SymKey *encKey;
+    PK11SymKey *macKey;
+} ssl_session_ticket_keys;
+
+static void
+ssl_CleanupSessionTicketKeyPair()
+{
+    if (ssl_session_ticket_key_pair.pubKey) {
+        PORT_Assert(ssl_session_ticket_key_pair.privKey);
+        SECKEY_DestroyPublicKey(ssl_session_ticket_key_pair.pubKey);
+        SECKEY_DestroyPrivateKey(ssl_session_ticket_key_pair.privKey);
+    }
+}
+
+void
+ssl_ResetSessionTicketKeys()
+{
+    if (ssl_session_ticket_keys.encKey) {
+        PORT_Assert(ssl_session_ticket_keys.macKey);
+        PK11_FreeSymKey(ssl_session_ticket_keys.encKey);
+        PK11_FreeSymKey(ssl_session_ticket_keys.macKey);
+    }
+    PORT_Memset(&ssl_session_ticket_keys, 0,
+                sizeof(ssl_session_ticket_keys));
+}
+
+static SECStatus
+ssl_SessionTicketShutdown(void *appData, void *nssData)
+{
+    ssl_CleanupSessionTicketKeyPair();
+    PR_DestroyRWLock(ssl_session_ticket_key_pair.lock);
+    PORT_Memset(&ssl_session_ticket_key_pair, 0,
+                sizeof(ssl_session_ticket_key_pair));
+
+    ssl_ResetSessionTicketKeys();
+    return SECSuccess;
+}
+
+static PRStatus
+ssl_SessionTicketSetup(void)
+{
+    SECStatus rv = NSS_RegisterShutdown(ssl_SessionTicketShutdown, NULL);
+    if (rv != SECSuccess) {
+        return PR_FAILURE;
+    }
+    ssl_session_ticket_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL);
+    if (!ssl_session_ticket_key_pair.lock) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+/* Configure a session ticket key pair.  |explicitConfig| is set to true for
+ * calls to SSL_SetSessionTicketKeyPair(), false for implicit configuration.
+ * This assumes that the setup has been run. */
+static SECStatus
+ssl_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey,
+                            SECKEYPrivateKey *privKey,
+                            PRBool explicitConfig)
+{
+    SECKEYPublicKey *pubKeyCopy;
+    SECKEYPrivateKey *privKeyCopy;
+
+    PORT_Assert(ssl_session_ticket_key_pair.lock);
+
+    pubKeyCopy = SECKEY_CopyPublicKey(pubKey);
+    if (!pubKeyCopy) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+
+    privKeyCopy = SECKEY_CopyPrivateKey(privKey);
+    if (!privKeyCopy) {
+        SECKEY_DestroyPublicKey(pubKeyCopy);
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+
+    PR_RWLock_Wlock(ssl_session_ticket_key_pair.lock);
+    ssl_CleanupSessionTicketKeyPair();
+    ssl_session_ticket_key_pair.pubKey = pubKeyCopy;
+    ssl_session_ticket_key_pair.privKey = privKeyCopy;
+    ssl_session_ticket_key_pair.configured = explicitConfig;
+    PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+    return SECSuccess;
+}
+
+SECStatus
+SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey,
+                            SECKEYPrivateKey *privKey)
+{
+    if (SECKEY_GetPublicKeyType(pubKey) != rsaKey ||
+        SECKEY_GetPrivateKeyType(privKey) != rsaKey) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+                                  &ssl_SessionTicketSetup)) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    return ssl_SetSessionTicketKeyPair(pubKey, privKey, PR_TRUE);
+}
+
+/* When configuring a server cert, we should save the RSA key in case it is
+ * needed for ticket encryption. This saves the latest copy, unless there has
+ * been an explicit call to SSL_SetSessionTicketKeyPair(). */
+SECStatus
+ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair)
+{
+    PRBool configured;
+
+    if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+                                  &ssl_SessionTicketSetup)) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock);
+    configured = ssl_session_ticket_key_pair.configured;
+    PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+    if (configured) {
+        return SECSuccess;
+    }
+    return ssl_SetSessionTicketKeyPair(keyPair->pubKey,
+                                       keyPair->privKey, PR_FALSE);
+}
+
+static SECStatus
+ssl_GetSessionTicketKeyPair(SECKEYPublicKey **pubKey,
+                            SECKEYPrivateKey **privKey)
+{
+    if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup,
+                                  &ssl_SessionTicketSetup)) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock);
+    *pubKey = ssl_session_ticket_key_pair.pubKey;
+    *privKey = ssl_session_ticket_key_pair.privKey;
+    PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock);
+    if (!*pubKey) {
+        PORT_Assert(!*privKey);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    PORT_Assert(*privKey);
+    return SECSuccess;
+}
+
 static PRBool
-getSvrWrappingKey(PRInt32 symWrapMechIndex,
-                  SSLAuthType authType,
+ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName,
+                              PK11SymKey **aesKey, PK11SymKey **macKey);
+
+static PRStatus
+ssl_GenerateSessionTicketKeysOnce(void *arg)
+{
+    SECStatus rv;
+
+    /* Get a copy of the session keys from shared memory. */
+    PORT_Memcpy(ssl_session_ticket_keys.keyName,
+                SESS_TICKET_KEY_NAME_PREFIX,
+                sizeof(SESS_TICKET_KEY_NAME_PREFIX));
+    /* This function calls ssl_GetSessionTicketKeyPair(), which initializes the
+     * key pair stuff.  That allows this to use the same shutdown function. */
+    rv = ssl_GenerateSessionTicketKeys(arg, ssl_session_ticket_keys.keyName,
+                                       &ssl_session_ticket_keys.encKey,
+                                       &ssl_session_ticket_keys.macKey);
+    if (rv != SECSuccess) {
+        return PR_FAILURE;
+    }
+
+    return PR_SUCCESS;
+}
+
+SECStatus
+ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName,
+                         PK11SymKey **encKey, PK11SymKey **macKey)
+{
+    if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_session_ticket_keys.setup,
+                                         &ssl_GenerateSessionTicketKeysOnce,
+                                         ss->pkcs11PinArg)) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    if (!ssl_session_ticket_keys.encKey || !ssl_session_ticket_keys.macKey) {
+        return SECFailure;
+    }
+
+    PORT_Memcpy(keyName, ssl_session_ticket_keys.keyName,
+                sizeof(ssl_session_ticket_keys.keyName));
+    *encKey = ssl_session_ticket_keys.encKey;
+    *macKey = ssl_session_ticket_keys.macKey;
+    return SECSuccess;
+}
+
+/* If lockTime is zero, it implies that the lock is not held, and must be
+ * aquired here.
+ */
+static SECStatus
+getSvrWrappingKey(unsigned int symWrapMechIndex,
+                  unsigned int wrapKeyIndex,
                   SSLWrappedSymWrappingKey *wswk,
                   cacheDesc *cache,
                   PRUint32 lockTime)
 {
-    PRUint32 ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+    PRUint32 ndx = (wrapKeyIndex * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
     SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx;
     PRUint32 now = 0;
-    PRBool rv = PR_FALSE;
+    PRBool rv = SECFailure;
 
     if (!cache->cacheMem) { /* cache is uninitialized */
         PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
-        return rv;
+        return SECFailure;
     }
     if (!lockTime) {
-        lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
-        if (!lockTime) {
-            return rv;
+        now = LockSidCacheLock(cache->keyCacheLock, 0);
+        if (!now) {
+            return SECFailure;
         }
     }
-    if (pwswk->authType == authType &&
-        pwswk->symWrapMechIndex == symWrapMechIndex &&
+    if (pwswk->wrapKeyIndex == wrapKeyIndex &&
+        pwswk->wrapMechIndex == symWrapMechIndex &&
         pwswk->wrappedSymKeyLen != 0) {
         *wswk = *pwswk;
-        rv = PR_TRUE;
+        rv = SECSuccess;
     }
     if (now) {
         UnlockSidCacheLock(cache->keyCacheLock);
     }
     return rv;
 }
 
-PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
-                   SSLAuthType authType,
+SECStatus
+ssl_GetWrappingKey(unsigned int wrapMechIndex,
+                   unsigned int wrapKeyIndex,
                    SSLWrappedSymWrappingKey *wswk)
 {
-    PRBool rv;
-
-    PORT_Assert((unsigned)authType < ssl_auth_size);
-    PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
-    if ((unsigned)authType < ssl_auth_size &&
-        (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
-        rv = getSvrWrappingKey(symWrapMechIndex, authType, wswk,
-                               &globalCache, 0);
-    } else {
-        rv = PR_FALSE;
+    PORT_Assert(wrapMechIndex < SSL_NUM_WRAP_MECHS);
+    PORT_Assert(wrapKeyIndex < SSL_NUM_WRAP_KEYS);
+    if (wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
+        wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
     }
 
-    return rv;
+    return getSvrWrappingKey(wrapMechIndex, wrapKeyIndex, wswk,
+                             &globalCache, 0);
 }
 
 /* Wrap and cache a session ticket key. */
-static PRBool
+static SECStatus
 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
               const char *keyName, encKeyCacheEntry *cacheEntry)
 {
     SECItem wrappedKey = { siBuffer, NULL, 0 };
 
     wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
     PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
     if (wrappedKey.len > sizeof(cacheEntry->bytes))
         return PR_FALSE;
     wrappedKey.data = cacheEntry->bytes;
 
     if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) !=
         SECSuccess) {
         SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
                  SSL_GETPID(), "unknown", keyName));
-        return PR_FALSE;
+        return SECFailure;
     }
     cacheEntry->length = wrappedKey.len;
-    return PR_TRUE;
+    return SECSuccess;
 }
 
-static PRBool
+static SECStatus
 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
                    PK11SymKey **macKey)
 {
     PK11SlotInfo *slot;
     CK_MECHANISM_TYPE mechanismArray[2];
     PK11SymKey *aesKeyTmp = NULL;
     PK11SymKey *macKeyTmp = NULL;
     cacheDesc *cache = &globalCache;
@@ -1707,17 +1914,17 @@ GenerateTicketKeys(void *pwArg, unsigned
         ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
     }
 
     if (PK11_GenerateRandom(ticketKeyNameSuffix,
                             SESS_TICKET_KEY_VAR_NAME_LEN) !=
         SECSuccess) {
         SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
                  SSL_GETPID(), "unknown"));
-        goto loser;
+        return SECFailure;
     }
 
     mechanismArray[0] = CKM_AES_CBC;
     mechanismArray[1] = CKM_SHA256_HMAC;
 
     slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
     if (slot) {
         aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
@@ -1730,59 +1937,63 @@ GenerateTicketKeys(void *pwArg, unsigned
     if (aesKeyTmp == NULL || macKeyTmp == NULL) {
         SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
                  SSL_GETPID(), "unknown"));
         goto loser;
     }
     PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
     *aesKey = aesKeyTmp;
     *macKey = macKeyTmp;
-    return PR_TRUE;
+    return SECSuccess;
 
 loser:
     if (aesKeyTmp)
         PK11_FreeSymKey(aesKeyTmp);
     if (macKeyTmp)
         PK11_FreeSymKey(macKeyTmp);
-    return PR_FALSE;
+    return SECFailure;
 }
 
-static PRBool
+static SECStatus
 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
                           unsigned char *keyName, PK11SymKey **aesKey,
                           PK11SymKey **macKey)
 {
     PK11SymKey *aesKeyTmp = NULL;
     PK11SymKey *macKeyTmp = NULL;
     cacheDesc *cache = &globalCache;
+    SECStatus rv;
 
-    if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
-        goto loser;
+    rv = GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
     if (cache->cacheMem) {
         /* Export the keys to the shared cache in wrapped form. */
-        if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
+        rv = WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey);
+        if (rv != SECSuccess) {
             goto loser;
-        if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
+        }
+        rv = WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey);
+        if (rv != SECSuccess) {
             goto loser;
+        }
     }
     *aesKey = aesKeyTmp;
     *macKey = macKeyTmp;
-    return PR_TRUE;
+    return SECSuccess;
 
 loser:
-    if (aesKeyTmp)
-        PK11_FreeSymKey(aesKeyTmp);
-    if (macKeyTmp)
-        PK11_FreeSymKey(macKeyTmp);
-    return PR_FALSE;
+    PK11_FreeSymKey(aesKeyTmp);
+    PK11_FreeSymKey(macKeyTmp);
+    return SECFailure;
 }
 
-static PRBool
+static SECStatus
 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
                        PK11SymKey **aesKey, PK11SymKey **macKey)
 {
     SECItem wrappedKey = { siBuffer, NULL, 0 };
     PK11SymKey *aesKeyTmp = NULL;
     PK11SymKey *macKeyTmp = NULL;
     cacheDesc *cache = &globalCache;
 
@@ -1805,115 +2016,113 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey 
     }
     SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
              SSL_GETPID(), "unknown"));
 
     PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
                 SESS_TICKET_KEY_VAR_NAME_LEN);
     *aesKey = aesKeyTmp;
     *macKey = macKeyTmp;
-    return PR_TRUE;
+    return SECSuccess;
 
 loser:
     if (aesKeyTmp)
         PK11_FreeSymKey(aesKeyTmp);
     if (macKeyTmp)
         PK11_FreeSymKey(macKeyTmp);
-    return PR_FALSE;
+    return SECFailure;
 }
 
-PRBool
-ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey,
-                         SECKEYPublicKey *svrPubKey, void *pwArg,
-                         unsigned char *keyName, PK11SymKey **aesKey,
-                         PK11SymKey **macKey)
+static SECStatus
+ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName,
+                              PK11SymKey **encKey, PK11SymKey **macKey)
 {
-    PRUint32 now = 0;
-    PRBool rv = PR_FALSE;
-    PRBool keysGenerated = PR_FALSE;
+    SECKEYPrivateKey *svrPrivKey;
+    SECKEYPublicKey *svrPubKey;
+    PRUint32 now;
+    SECStatus rv;
     cacheDesc *cache = &globalCache;
 
     if (!cache->cacheMem) {
         /* cache is uninitialized. Generate keys and return them
          * without caching. */
-        return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
+        return GenerateTicketKeys(pwArg, keyName, encKey, macKey);
+    }
+
+    rv = ssl_GetSessionTicketKeyPair(&svrPubKey, &svrPrivKey);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    now = LockSidCacheLock(cache->keyCacheLock, now);
+    now = LockSidCacheLock(cache->keyCacheLock, 0);
     if (!now)
-        return rv;
+        return SECFailure;
 
-    if (!*(cache->ticketKeysValid)) {
+    if (*(cache->ticketKeysValid)) {
+        rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, encKey, macKey);
+    } else {
         /* Keys do not exist, create them. */
-        if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
-                                       aesKey, macKey))
-            goto loser;
-        keysGenerated = PR_TRUE;
-        *(cache->ticketKeysValid) = 1;
+        rv = GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
+                                       encKey, macKey);
+        if (rv == SECSuccess) {
+            *(cache->ticketKeysValid) = 1;
+        }
     }
-
-    rv = PR_TRUE;
-
-loser:
     UnlockSidCacheLock(cache->keyCacheLock);
-    if (rv && !keysGenerated)
-        rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
     return rv;
 }
 
 /* The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the shared memory.
  * If it is uninitialized, this function writes the caller's value into
  * the disk entry, and returns false.
  * Otherwise, it overwrites the caller's wswk with the value obtained from
  * the disk, and returns PR_TRUE.
  * This is all done while holding the locks/mutexes necessary to make
  * the operation atomic.
  */
-PRBool
+SECStatus
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 {
     cacheDesc *cache = &globalCache;
-    PRBool rv = PR_FALSE;
-    SSLAuthType authType = wswk->authType;
-    /* type of keys used to wrap SymWrapKey*/
-    PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
+    PRBool rv = SECFailure;
     PRUint32 ndx;
-    PRUint32 now = 0;
+    PRUint32 now;
     SSLWrappedSymWrappingKey myWswk;
 
     if (!cache->cacheMem) { /* cache is uninitialized */
         PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
-        return 0;
+        return SECFailure;
     }
 
-    PORT_Assert((unsigned)authType < ssl_auth_size);
-    if ((unsigned)authType >= ssl_auth_size)
-        return 0;
+    PORT_Assert(wswk->wrapMechIndex < SSL_NUM_WRAP_MECHS);
+    PORT_Assert(wswk->wrapKeyIndex < SSL_NUM_WRAP_KEYS);
+    if (wswk->wrapMechIndex >= SSL_NUM_WRAP_MECHS ||
+        wswk->wrapKeyIndex >= SSL_NUM_WRAP_KEYS) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
 
-    PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
-    if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
-        return 0;
-
-    ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+    ndx = (wswk->wrapKeyIndex * SSL_NUM_WRAP_MECHS) + wswk->wrapMechIndex;
     PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
 
-    now = LockSidCacheLock(cache->keyCacheLock, now);
-    if (now) {
-        rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->authType,
-                               &myWswk, cache, now);
-        if (rv) {
-            /* we found it on disk, copy it out to the caller. */
-            PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
-        } else {
-            /* Wasn't on disk, and we're still holding the lock, so write it. */
-            cache->keyCacheData[ndx] = *wswk;
-        }
-        UnlockSidCacheLock(cache->keyCacheLock);
+    now = LockSidCacheLock(cache->keyCacheLock, 0);
+    if (!now) {
+        return SECFailure;
     }
+    rv = getSvrWrappingKey(wswk->wrapMechIndex, wswk->wrapKeyIndex,
+                           &myWswk, cache, now);
+    if (rv == SECSuccess) {
+        /* we found it on disk, copy it out to the caller. */
+        PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
+    } else {
+        /* Wasn't on disk, and we're still holding the lock, so write it. */
+        cache->keyCacheData[ndx] = *wswk;
+    }
+    UnlockSidCacheLock(cache->keyCacheLock);
     return rv;
 }
 
 #else /* MAC version or other platform */
 
 #include "seccomon.h"
 #include "cert.h"
 #include "ssl.h"
@@ -1941,41 +2150,39 @@ SSL_ConfigMPServerSIDCache(int maxCacheE
 
 SECStatus
 SSL_InheritMPServerSIDCache(const char *envString)
 {
     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
     return SECFailure;
 }
 
-PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
-                   SSLAuthType authType,
+SECStatus
+ssl_GetWrappingKey(unsigned int wrapMechIndex,
+                   unsigned int wrapKeyIndex,
                    SSLWrappedSymWrappingKey *wswk)
 {
-    PRBool rv = PR_FALSE;
     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
-    return rv;
+    return SECFailure;
 }
 
 /* This is a kind of test-and-set.  The caller passes in the new value it wants
  * to set.  This code tests the wrapped sym key entry in the shared memory.
  * If it is uninitialized, this function writes the caller's value into
  * the disk entry, and returns false.
  * Otherwise, it overwrites the caller's wswk with the value obtained from
  * the disk, and returns PR_TRUE.
  * This is all done while holding the locks/mutexes necessary to make
  * the operation atomic.
  */
-PRBool
+SECStatus
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 {
-    PRBool rv = PR_FALSE;
     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
-    return rv;
+    return SECFailure;
 }
 
 PRUint32
 SSL_GetMaxServerCacheLocks(void)
 {
     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
     return -1;
 }
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -623,23 +623,19 @@ tls13_RecoverWrappedSharedSecret(sslSock
         PORT_Assert(0); /* I think this can't happen. */
         return SECFailure;
     }
 
     /* Now find the hash used as the PRF for the previous handshake. */
     hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite);
 
     /* If we are the server, we compute the wrapping key, but if we
-     * are the client, it's coordinates are stored with the ticket. */
+     * are the client, its coordinates are stored with the ticket. */
     if (ss->sec.isServer) {
-        const sslServerCert *serverCert;
-
-        serverCert = ssl_FindServerCert(ss, &sid->certType);
-        PORT_Assert(serverCert);
-        wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert,
+        wrapKey = ssl3_GetWrappingKey(ss, NULL,
                                       sid->u.ssl3.masterWrapMech,
                                       ss->pkcs11PinArg);
     } else {
         PK11SlotInfo *slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
                                                sid->u.ssl3.masterSlotID);
         if (!slot)
             return SECFailure;
 
@@ -932,17 +928,17 @@ tls13_CanResume(sslSocket *ss, const ssl
     if (tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite) != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
         return PR_FALSE;
     }
 
     /* Server sids don't remember the server cert we previously sent, but they
      * do remember the type of certificate we originally used, so we can locate
      * it again, provided that the current ssl socket has had its server certs
      * configured the same as the previous one. */
-    sc = ssl_FindServerCert(ss, &sid->certType);
+    sc = ssl_FindServerCert(ss, sid->authType, sid->namedCurve);
     if (!sc || !sc->serverCert) {
         return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 
 static PRBool
@@ -1156,16 +1152,40 @@ tls13_NegotiateKeyExchange(sslSocket *ss
     }
 
     PORT_Assert(preferredGroup == entry->group);
     *clientShare = entry;
 
     return SECSuccess;
 }
 
+SSLAuthType
+ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
+{
+    switch (scheme) {
+        case ssl_sig_rsa_pkcs1_sha1:
+        case ssl_sig_rsa_pkcs1_sha256:
+        case ssl_sig_rsa_pkcs1_sha384:
+        case ssl_sig_rsa_pkcs1_sha512:
+        /* We report PSS signatures as being just RSA signatures. */
+        case ssl_sig_rsa_pss_sha256:
+        case ssl_sig_rsa_pss_sha384:
+        case ssl_sig_rsa_pss_sha512:
+            return ssl_auth_rsa_sign;
+        case ssl_sig_ecdsa_secp256r1_sha256:
+        case ssl_sig_ecdsa_secp384r1_sha384:
+        case ssl_sig_ecdsa_secp521r1_sha512:
+        case ssl_sig_ecdsa_sha1:
+            return ssl_auth_ecdsa;
+        default:
+            PORT_Assert(0);
+    }
+    return ssl_auth_null;
+}
+
 SECStatus
 tls13_SelectServerCert(sslSocket *ss)
 {
     PRCList *cursor;
     SECStatus rv;
 
     if (!ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) {
         FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
@@ -1179,32 +1199,31 @@ tls13_SelectServerCert(sslSocket *ss)
      *
      * We might want to do some sort of ranking here later.  For now, it's all
      * based on what order they are configured in. */
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
 
-        if (cert->certType.authType == ssl_auth_rsa_pss ||
-            cert->certType.authType == ssl_auth_rsa_decrypt) {
+        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,
                                      PR_FALSE);
         if (rv == SECSuccess) {
             /* Found one. */
             ss->sec.serverCert = cert;
-            ss->sec.authType = cert->certType.authType;
-            ss->ssl3.hs.kea_def_mutable.authKeyType = cert->certType.authType;
+            ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
+                ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
             ss->sec.authKeyBits = cert->serverKeyBits;
             return SECSuccess;
         }
     }
 
     FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM,
                 handshake_failure);
     return SECFailure;
@@ -1225,18 +1244,16 @@ tls13_NegotiateAuthentication(sslSocket 
 
     SSL_TRC(3, ("%d: TLS13[%d]: selected certificate authentication",
                 SSL_GETPID(), ss->fd));
     /* We've now established that we need to sign.... */
     rv = tls13_SelectServerCert(ss);
     if (rv != SECSuccess) {
         return SECFailure;
     }
-    ss->ssl3.hs.kea_def_mutable.authKeyType =
-        ss->sec.serverCert->certType.authType;
     return SECSuccess;
 }
 
 /* Called from ssl3_HandleClientHello after we have parsed the
  * ClientHello and are sure that we are going to do TLS 1.3
  * or fail. */
 SECStatus
 tls13_HandleClientHelloPart2(sslSocket *ss,
@@ -1338,30 +1355,33 @@ tls13_HandleClientHelloPart2(sslSocket *
         /* Check that the negotiated SNI and the cached SNI match. */
         if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
                                 &ss->ssl3.hs.srvVirtName) != SECEqual) {
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
                         handshake_failure);
             goto loser;
         }
 
+        ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
+                                                sid->namedCurve);
+        PORT_Assert(ss->sec.serverCert);
+
         rv = tls13_RecoverWrappedSharedSecret(ss, sid);
         if (rv != SECSuccess) {
             SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             goto loser;
         }
         tls13_RestoreCipherInfo(ss, sid);
 
-        ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType);
-        PORT_Assert(ss->sec.serverCert);
         ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
         if (sid->peerCert != NULL) {
             ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
         }
+
         ssl3_RegisterExtensionSender(
             ss, &ss->xtnData,
             ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
 
         tls13_NegotiateZeroRtt(ss, sid);
     } else {
         if (sid) { /* we had a sid, but it's no longer valid, free it */
             SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
@@ -1612,35 +1632,38 @@ 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;
-    int calen;
+    unsigned int calen;
     SECItem *names;
-    int nnames;
+    unsigned int nnames;
     SECItem *name;
     int i;
     PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2];
     unsigned int sigSchemesLength = 0;
     int length;
 
     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;
     }
 
-    ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
+    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);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
@@ -3286,26 +3309,17 @@ tls13_HandleCertificateVerify(sslSocket 
     rv = ssl3_VerifySignedHashes(ss, sigScheme, &tbsHash, &signed_hash);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
         return SECFailure;
     }
 
     /* Set the auth type. */
     if (!ss->sec.isServer) {
-        switch (ssl_SignatureSchemeToKeyType(sigScheme)) {
-            case rsaKey:
-                ss->sec.authType = ssl_auth_rsa_sign;
-                break;
-            case ecKey:
-                ss->sec.authType = ssl_auth_ecdsa;
-                break;
-            default:
-                PORT_Assert(PR_FALSE);
-        }
+        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;
 
         PORT_Assert(!ss->sec.isServer);
         rv = ssl3_CompleteHandleCertificateRequest(ss, req->signatureSchemes,