Backed out changeset 72ae99c547be, part 3/3, bug 1237514, for causing test failures in Firefox tests
authorKai Engert <kaie@kuix.de>
Wed, 06 Apr 2016 18:07:39 +0200
changeset 12057 611ef59ebea66112f9ab98b0ef97390d849ec161
parent 12056 dac2c3e36c7811706cc1399d4ad19f2ffe17c0a0
child 12058 cb003099f3f0d1bd161720d5e7b7deedb611881d
push id1119
push userkaie@kuix.de
push dateWed, 06 Apr 2016 16:07:58 +0000
bugs1237514
backs out72ae99c547be9fe56d4448c7447be6316a670bfd
Backed out changeset 72ae99c547be, part 3/3, bug 1237514, for causing test failures in Firefox tests
external_tests/ssl_gtest/libssl_internals.c
external_tests/ssl_gtest/ssl_loopback_unittest.cc
external_tests/ssl_gtest/tls_agent.cc
external_tests/ssl_gtest/tls_agent.h
external_tests/ssl_gtest/tls_connect.cc
external_tests/ssl_gtest/tls_connect.h
lib/ssl/SSLerrs.h
lib/ssl/manifest.mn
lib/ssl/ssl.def
lib/ssl/ssl.h
lib/ssl/ssl3con.c
lib/ssl/ssl3ecc.c
lib/ssl/ssl3ext.c
lib/ssl/sslcert.c
lib/ssl/sslcert.h
lib/ssl/sslcon.c
lib/ssl/sslimpl.h
lib/ssl/sslinfo.c
lib/ssl/sslsecur.c
lib/ssl/sslsnce.c
lib/ssl/sslsock.c
lib/ssl/sslt.h
lib/ssl/tls13con.c
--- a/external_tests/ssl_gtest/libssl_internals.c
+++ b/external_tests/ssl_gtest/libssl_internals.c
@@ -24,22 +24,21 @@ SSLInt_IncrementClientHandshakeVersion(P
 
     return SECSuccess;
 }
 
 PRUint32
 SSLInt_DetermineKEABits(PRUint16 serverKeyBits, SSLAuthType authAlgorithm) {
     // For ECDSA authentication we expect a curve for key exchange with the
     // same strength as the one used for the certificate's signature.
-    if (authAlgorithm == ssl_auth_ecdsa || authAlgorithm == ssl_auth_ecdh) {
+    if (authAlgorithm == ssl_auth_ecdsa) {
         return serverKeyBits;
     }
 
-    PORT_Assert(authAlgorithm == ssl_auth_rsa_decrypt ||
-                authAlgorithm == ssl_auth_rsa_sign);
+    PORT_Assert(authAlgorithm == ssl_auth_rsa);
     PRUint32 minKeaBits;
 #ifdef NSS_ECC_MORE_THAN_SUITE_B
     // P-192 is the smallest curve we want to use.
     minKeaBits = 192U;
 #else
     // P-256 is the smallest supported curve.
     minKeaBits = 256U;
 #endif
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -103,49 +103,54 @@ class TlsServerKeyExchangeEcdhe {
     }
 
     return parser.ReadVariable(&public_key_, 1);
   }
 
   DataBuffer public_key_;
 };
 
-class TlsChaCha20Poly1305Test : public TlsConnectTls12 {};
+class TlsChaCha20Poly1305Test : public TlsConnectTls12 {
+ public:
+  void ConnectSendReceive(PRUint32 cipher_suite)
+  {
+    // Disable all ciphers.
+    client_->DisableCiphersByKeyExchange(ssl_kea_rsa);
+    client_->DisableCiphersByKeyExchange(ssl_kea_dh);
+    client_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
+
+    // Re-enable ChaCha20/Poly1305.
+    SECStatus rv = SSL_CipherPrefSet(client_->ssl_fd(), cipher_suite, PR_TRUE);
+    EXPECT_EQ(SECSuccess, rv);
+
+    Connect();
+    SendReceive();
+
+    // Check that we used the right cipher suite.
+    int16_t actual, expected = static_cast<int16_t>(cipher_suite);
+    EXPECT_TRUE(client_->cipher_suite(&actual) && actual == expected);
+    EXPECT_TRUE(server_->cipher_suite(&actual) && actual == expected);
+  }
+};
 
 TEST_P(TlsConnectGeneric, SetupOnly) {}
 
 TEST_P(TlsConnectGeneric, Connect) {
   SetExpectedVersion(std::get<1>(GetParam()));
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 }
 
 TEST_P(TlsConnectGeneric, ConnectEcdsa) {
   SetExpectedVersion(std::get<1>(GetParam()));
   ResetEcdsa();
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
 }
 
-TEST_P(TlsConnectGenericPre13, ConnectEcdh) {
-  SetExpectedVersion(std::get<1>(GetParam()));
-  // ECDH_ cipher suites can use an ECDSA cert (NSS doesn't care that we
-  // shouldn't, which this shamelessly exploits).
-  ResetEcdsa();
-  DisableDheAndEcdheCiphers();
-  EnableSomeEcdhCiphers();
-
-  Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_ecdh);
-}
-
-TEST_P(TlsConnectStreamPre13, ConnectRC4) {
-  ConnectWithCipherSuite(TLS_RSA_WITH_RC4_128_SHA);
-}
-
 TEST_P(TlsConnectGenericPre13, ConnectFalseStart) {
   client_->EnableFalseStart();
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectResumed) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
@@ -301,33 +306,33 @@ TEST_P(TlsConnectGeneric, ConnectResumeC
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsConnectGeneric, ClientAuth) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 }
 
 // In TLS 1.3, the client sends its cert rejection on the
 // second flight, and since it has already received the
 // server's Finished, it transitions to complete and
 // then gets an alert from the server. The test harness
 // doesn't handle this right yet.
 TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) {
   server_->RequestClientAuth(true);
   ConnectExpectFail();
 }
 
 TEST_P(TlsConnectGeneric, ClientAuthRequestedRejected) {
   server_->RequestClientAuth(false);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 }
 
 
 TEST_P(TlsConnectGeneric, ClientAuthEcdsa) {
   ResetEcdsa();
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
@@ -386,23 +391,23 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
 // This should also work in TLS 1.0 and 1.1 where the algorithms aren't used.
 TEST_P(TlsConnectGenericPre13, SignatureAlgorithmNoOverlapStaticRsa) {
   client_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->SetSignatureAlgorithms(SignatureRsaSha256,
                                   PR_ARRAY_SIZE(SignatureRsaSha256));
   DisableDheAndEcdheCiphers();
   Connect();
-  CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt);
+  CheckKeys(ssl_kea_rsa, ssl_auth_rsa);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectStaticRSA) {
   DisableDheAndEcdheCiphers();
   Connect();
-  CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt);
+  CheckKeys(ssl_kea_rsa, ssl_auth_rsa);
 }
 
 // Signature algorithms governs both verification and generation of signatures.
 // With ECDSA, we need to at least have a common signature algorithm configured.
 TEST_P(TlsConnectTls12, SignatureAlgorithmNoOverlapEcdsa) {
   ResetEcdsa();
   client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha384));
@@ -527,17 +532,17 @@ TEST_P(TlsConnectStreamPre13, ConnectAnd
   Handshake();
   CheckConnected();
 }
 
 // TODO implement DHE for 1.3
 TEST_P(TlsConnectGenericPre13, ConnectDhe) {
   DisableEcdheCiphers();
   Connect();
-  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_dh, ssl_auth_rsa);
 }
 
 // Test that a totally bogus EPMS is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
   DisableDheAndEcdheCiphers();
   TlsInspectorReplaceHandshakeMessage* i1 =
       new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
@@ -573,37 +578,37 @@ TEST_P(TlsConnectGenericPre13, ConnectSt
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectEcdhe) {
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 }
 
 // Prior to TLS 1.3, we were not fully ephemeral; though 1.3 fixes that
 TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   ResetRsa();
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are the same.
   EXPECT_EQ(dhe1.public_key_.len(), dhe2.public_key_.len());
   EXPECT_TRUE(!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                       dhe1.public_key_.len()));
@@ -614,57 +619,57 @@ TEST_P(TlsConnectGenericPre13, ConnectEc
   server_->EnsureTlsSetup();
   SECStatus rv =
       SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   ResetRsa();
   server_->EnsureTlsSetup();
   rv = SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
-  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are different.
   EXPECT_FALSE((dhe1.public_key_.len() == dhe2.public_key_.len()) &&
                (!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                         dhe1.public_key_.len())));
 }
 
 TEST_P(TlsConnectGeneric, ConnectSendReceive) {
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305DheRsa) {
-  ConnectWithCipherSuite(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+  ConnectSendReceive(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
 }
 
 TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheRsa) {
-  ConnectWithCipherSuite(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+  ConnectSendReceive(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
 }
 
 TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheEcdsa) {
   ResetEcdsa();
-  ConnectWithCipherSuite(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
+  ConnectSendReceive(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
 }
 
 // The next two tests takes advantage of the fact that we
 // automatically read the first 1024 bytes, so if
 // we provide 1200 bytes, they overrun the read buffer
 // provided by the calling test.
 
 // DTLS should return an error.
--- a/external_tests/ssl_gtest/tls_agent.cc
+++ b/external_tests/ssl_gtest/tls_agent.cc
@@ -101,19 +101,17 @@ bool TlsAgent::EnsureTlsSetup() {
     if (!pub) return false;  // Leak cert.
     server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub);
     SECKEY_DestroyPublicKey(pub);
 
     SECKEYPrivateKey* priv = PK11_FindKeyByAnyCert(cert, nullptr);
     EXPECT_NE(nullptr, priv);
     if (!priv) return false;  // Leak cert.
 
-    SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, kt_null);
-    EXPECT_EQ(SECFailure, rv);
-    rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kea_);
+    SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kea_);
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;  // Leak cert and key.
 
     SECKEY_DestroyPrivateKey(priv);
     CERT_DestroyCertificate(cert);
 
     rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook, this);
     EXPECT_EQ(SECSuccess, rv);  // don't abort, just fail
@@ -210,33 +208,16 @@ void TlsAgent::DisableCiphersByKeyExchan
 
     if (csinfo.keaType == kea) {
       rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_FALSE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
-void TlsAgent::EnableCiphersByAuthType(SSLAuthType authType) {
-  EXPECT_TRUE(EnsureTlsSetup());
-
-  for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
-    SSLCipherSuiteInfo csinfo;
-
-    SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],
-                                          &csinfo, sizeof(csinfo));
-    ASSERT_EQ(SECSuccess, rv);
-
-    bool enable = csinfo.authType == authType;
-    rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], enable);
-    EXPECT_EQ(SECSuccess, rv);
-  }
-}
-
-
 void TlsAgent::SetSessionTicketsEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
                                en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
@@ -316,17 +297,17 @@ void TlsAgent::SetSignatureAlgorithms(co
   EXPECT_EQ(i, configuredCount) << "algorithms in use were all set";
 }
 
 void TlsAgent::CheckKEAType(SSLKEAType type) const {
   EXPECT_EQ(STATE_CONNECTED, state_);
   EXPECT_EQ(type, csinfo_.keaType);
 
   PRUint32 ecKEAKeyBits = SSLInt_DetermineKEABits(server_key_bits_,
-                                                  csinfo_.authType);
+                                                  csinfo_.authAlgorithm);
 
   switch (type) {
       case ssl_kea_ecdh:
           EXPECT_EQ(ecKEAKeyBits, info_.keaKeyBits);
           break;
       case ssl_kea_dh:
           EXPECT_EQ(2048U, info_.keaKeyBits);
           break;
@@ -335,43 +316,24 @@ void TlsAgent::CheckKEAType(SSLKEAType t
           break;
       default:
           break;
   }
 }
 
 void TlsAgent::CheckAuthType(SSLAuthType type) const {
   EXPECT_EQ(STATE_CONNECTED, state_);
-  EXPECT_EQ(type, csinfo_.authType);
+  EXPECT_EQ(type, csinfo_.authAlgorithm);
   EXPECT_EQ(server_key_bits_, info_.authKeyBits);
-
-  // Do some extra checks based on type.
   switch (type) {
       case ssl_auth_ecdsa:
           // extra check for P-256
           EXPECT_EQ(256U, info_.authKeyBits);
           break;
-    default:
-      break;
-  }
-
-  // Check authAlgorithm, which is the old value for authType.  This is a second switch
-  // statement because default label is different.
-  switch (type) {
-      case ssl_auth_rsa_sign:
-          EXPECT_EQ(ssl_auth_rsa_decrypt, csinfo_.authAlgorithm)
-                  << "authAlgorithm for RSA is always decrypt";
-          break;
-      case ssl_auth_ecdh:
-          EXPECT_TRUE(csinfo_.authAlgorithm != ssl_auth_ecdh)
-                  << "ECDH suites were originally wonky";
-          break;
       default:
-          EXPECT_EQ(type, csinfo_.authAlgorithm)
-                  << "authAlgorithm is (usually) the same as authType";
           break;
   }
 }
 
 void TlsAgent::EnableFalseStart() {
   EXPECT_TRUE(EnsureTlsSetup());
 
   falsestart_enabled_ = true;
--- a/external_tests/ssl_gtest/tls_agent.h
+++ b/external_tests/ssl_gtest/tls_agent.h
@@ -69,17 +69,16 @@ class TlsAgent : public PollTarget {
   void CheckAuthType(SSLAuthType type) const;
 
   void Handshake();
   // Marks the internal state as CONNECTING in anticipation of renegotiation.
   void PrepareForRenegotiate();
   // Prepares for renegotiation, then actually triggers it.
   void StartRenegotiate();
   void DisableCiphersByKeyExchange(SSLKEAType kea);
-  void EnableCiphersByAuthType(SSLAuthType authType);
   bool EnsureTlsSetup();
 
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
   bool GetClientAuthCredentials(CERTCertificate** cert,
                                 SECKEYPrivateKey** priv) const;
 
   void ConfigureSessionCache(SessionResumptionMode mode);
@@ -134,17 +133,17 @@ class TlsAgent : public PollTarget {
   uint16_t server_key_bits() const { return server_key_bits_; }
   uint16_t min_version() const { return vrange_.min; }
   uint16_t max_version() const { return vrange_.max; }
   uint16_t version() const {
     EXPECT_EQ(STATE_CONNECTED, state_);
     return info_.protocolVersion;
   }
 
-  bool cipher_suite(uint16_t* cipher_suite) const {
+  bool cipher_suite(int16_t* cipher_suite) const {
     if (state_ != STATE_CONNECTED) return false;
 
     *cipher_suite = info_.cipherSuite;
     return true;
   }
 
   std::string cipher_suite_name() const {
     if (state_ != STATE_CONNECTED) return "UNKNOWN";
--- a/external_tests/ssl_gtest/tls_connect.cc
+++ b/external_tests/ssl_gtest/tls_connect.cc
@@ -214,50 +214,27 @@ void TlsConnectTestBase::EnableExtendedM
 
 void TlsConnectTestBase::Connect() {
   server_->StartConnect();
   client_->StartConnect();
   Handshake();
   CheckConnected();
 }
 
-void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite)
-{
-  // Disable all ciphers.
-  client_->DisableCiphersByKeyExchange(ssl_kea_rsa);
-  client_->DisableCiphersByKeyExchange(ssl_kea_dh);
-  client_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
-
-  // Re-enable this specific cipher suite
-  SECStatus rv = SSL_CipherPrefSet(client_->ssl_fd(), cipher_suite, PR_TRUE);
-  EXPECT_EQ(SECSuccess, rv);
-
-  Connect();
-  SendReceive();
-
-  // Check that we used the right cipher suite.
-  uint16_t actual;
-  EXPECT_TRUE(client_->cipher_suite(&actual));
-  EXPECT_EQ(cipher_suite, actual);
-  EXPECT_TRUE(server_->cipher_suite(&actual));
-  EXPECT_EQ(cipher_suite, actual);
-}
-
-
 void TlsConnectTestBase::CheckConnected() {
   // Check the version is as expected
   EXPECT_EQ(client_->version(), server_->version());
   EXPECT_EQ(std::min(client_->max_version(),
                      server_->max_version()),
             client_->version());
 
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
 
-  uint16_t cipher_suite1, cipher_suite2;
+  int16_t cipher_suite1, cipher_suite2;
   bool ret = client_->cipher_suite(&cipher_suite1);
   EXPECT_TRUE(ret);
   ret = server_->cipher_suite(&cipher_suite2);
   EXPECT_TRUE(ret);
   EXPECT_EQ(cipher_suite1, cipher_suite2);
 
   std::cerr << "Connected with version " << client_->version()
             << " cipher suite " << client_->cipher_suite_name()
@@ -309,21 +286,16 @@ void TlsConnectTestBase::DisableEcdheCip
   server_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
 }
 
 void TlsConnectTestBase::DisableDheAndEcdheCiphers() {
   DisableDheCiphers();
   DisableEcdheCiphers();
 }
 
-void TlsConnectTestBase::EnableSomeEcdhCiphers() {
-  client_->EnableCiphersByAuthType(ssl_auth_ecdh);
-  server_->EnableCiphersByAuthType(ssl_auth_ecdh);
-}
-
 void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
                                                SessionResumptionMode server) {
   client_->ConfigureSessionCache(client);
   server_->ConfigureSessionCache(server);
 }
 
 void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
   EXPECT_NE(RESUME_BOTH, expected);
--- a/external_tests/ssl_gtest/tls_connect.h
+++ b/external_tests/ssl_gtest/tls_connect.h
@@ -61,26 +61,24 @@ class TlsConnectTestBase : public ::test
   // Run the handshake.
   void Handshake();
   // Connect and check that it works.
   void Connect();
   // Check that the connection was successfully established.
   void CheckConnected();
   // Connect and expect it to fail.
   void ConnectExpectFail();
-  void ConnectWithCipherSuite(uint16_t cipher_suite);
-  void CheckKeys(SSLKEAType akeyType, SSLAuthType authType) const;
+  void CheckKeys(SSLKEAType keyType, SSLAuthType authType) const;
 
   void SetExpectedVersion(uint16_t version);
   // Expect resumption of a particular type.
   void ExpectResumption(SessionResumptionMode expected);
   void DisableDheAndEcdheCiphers();
   void DisableDheCiphers();
   void DisableEcdheCiphers();
-  void EnableSomeEcdhCiphers();
   void EnableExtendedMasterSecret();
   void ConfigureSessionCache(SessionResumptionMode client,
                              SessionResumptionMode server);
   void EnableAlpn();
   void EnableSrtp();
   void CheckSrtp() const;
   void SendReceive();
   void Receive(size_t amount);
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -285,17 +285,17 @@ ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP, (S
 
 ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED, (SSL_ERROR_BASE + 86),
     "Cannot perform the operation until the handshake is complete.")
 
 ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE, (SSL_ERROR_BASE + 87),
     "Received incorrect handshakes hash values from peer.")
 
 ER3(SSL_ERROR_CERT_KEA_MISMATCH, (SSL_ERROR_BASE + 88),
-    "The certificate provided cannot be used with the selected authentication type.")
+    "The certificate provided cannot be used with the selected key exchange algorithm.")
 
 ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA, (SSL_ERROR_BASE + 89),
     "No certificate authority is trusted for SSL client authentication.")
 
 ER3(SSL_ERROR_SESSION_NOT_FOUND, (SSL_ERROR_BASE + 90),
     "Client's SSL session ID not found in server's session cache.")
 
 ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT, (SSL_ERROR_BASE + 91),
--- a/lib/ssl/manifest.mn
+++ b/lib/ssl/manifest.mn
@@ -40,16 +40,15 @@ CSRCS = \
 	ssltrace.c \
 	sslver.c \
 	authcert.c \
 	cmpcert.c \
 	sslinfo.c \
 	ssl3ecc.c \
         tls13con.c \
         tls13hkdf.c \
-        sslcert.c \
 	$(NULL)
 
 LIBRARY_NAME = ssl
 LIBRARY_VERSION = 3
 
 # This part of the code, including all sub-dirs, can be optimized for size
 export ALLOW_OPT_CODE_SIZE = 1
--- a/lib/ssl/ssl.def
+++ b/lib/ssl/ssl.def
@@ -191,13 +191,12 @@ SSL_SignatureMaxCount;
 ;+    global:
 SSL_PeerSignedCertTimestamps;
 SSL_SetSignedCertTimestamps;
 ;+    local:
 ;+*;
 ;+};
 ;+NSS_3.23 {    # NSS 3.23 release
 ;+    global:
-SSL_ConfigServerCert;
 SSL_SetDowngradeCheckVersion;
 ;+    local:
 ;+*;
 ;+};
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -591,32 +591,28 @@ SSL_IMPORT const SECItemArray *SSL_PeerS
  */
 SSL_IMPORT const SECItem *SSL_PeerSignedCertTimestamps(PRFileDesc *fd);
 
 /* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses
  * in the fd's data, which may be sent as part of a server side cert_status
  * handshake message. Parameter |responses| is for the server certificate of
  * the key exchange type |kea|.
  * The function will duplicate the responses array.
- *
- * Deprecated: see SSL_ConfigSecureServer for details.
  */
 SSL_IMPORT SECStatus
 SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
                             SSLKEAType kea);
 
 /*
  * SSL_SetSignedCertTimestamps stores serialized signed_certificate_timestamp
  * extension data in the fd. The signed_certificate_timestamp data is sent
  * during the handshake (if requested by the client). Parameter |scts|
  * is for the server certificate of the key exchange type |kea|.
  * The function will duplicate the provided data item. To clear previously
  * set data for a given key exchange type |kea|, pass NULL to |scts|.
- *
- * Deprecated: see SSL_ConfigSecureServer for details.
  */
 SSL_IMPORT SECStatus
 SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts,
                             SSLKEAType kea);
 
 /*
 ** Authenticate certificate hook. Called when a certificate comes in
 ** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
@@ -763,82 +759,24 @@ SSL_IMPORT SECStatus SSL_SetPKCS11PinArg
 typedef SECStatus(PR_CALLBACK *SSLBadCertHandler)(void *arg, PRFileDesc *fd);
 SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
                                      void *arg);
 
 /*
 ** Configure SSL socket for running a secure server. Needs the
 ** certificate for the server and the servers private key. The arguments
 ** are copied.
-**
-** This method should be used in preference to SSL_ConfigSecureServer,
-** SSL_ConfigSecureServerWithCertChain, SSL_SetStapledOCSPResponses, and
-** SSL_SetSignedCertTimestamps.
-**
-** The authentication method is determined from the certificate and private key
-** based on how libssl authenticates peers. Primarily, this uses the value of
-** the SSLAuthType enum and is derived from the type of public key in the
-** certificate.  For example, different RSA certificates might be saved for
-** signing (ssl_auth_rsa_sign) and key encipherment
-** (ssl_auth_rsa_decrypt). Unique to RSA, the same certificate can be used for
-** both usages. Additional information about the authentication method is also
-** used: EC keys with different curves are separately stored.
-**
-** Only one certificate is stored for each authentication method.
-**
-** The optional |data| argument contains additional information about the
-** certificate:
-**
-** - |authType| (with a value other than ssl_auth_null) limits the
-**   authentication method; this is primarily useful in limiting the use of an
-**   RSA certificate to one particular key usage (either signing or key
-**   encipherment) when its key usages indicate support for both.
-**
-** - |certChain| provides an explicit certificate chain, rather than relying on
-**   NSS functions for finding a certificate chain.
-**
-** - |stapledOCSPResponses| provides a response for OCSP stapling.
-**
-** - |signedCertTimestamps| provides a value for the
-**   signed_certificate_timestamp extension used in certificate transparency.
-**
-** The |data_len| argument provides the length of the data.  This should be set
-** to |sizeof(data)|.
-**
-** This function allows an application to provide certificates with narrow key
-** usages attached to them.  For instance, RSA keys can be provided that are
-** limited to signing or decryption only.  Multiple EC certificates with keys on
-** different named curves can be provided.
-**
-** Unlike SSL_ConfigSecureServer(WithCertChain), this function does not accept
-** NULL for the |cert| and |key| arguments.  It will replace certificates that
-** have the same type, but it cannot be used to remove certificates that have
-** already been configured.
-*/
-SSL_IMPORT SECStatus SSL_ConfigServerCert(
-    PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key,
-    const SSLExtraServerCertData *data, unsigned int data_len);
-
-/*
-** Deprecated variant of SSL_ConfigServerCert.
-**
-** This uses values from the SSLKEAType to identify the type of |key| that the
-** |cert| contains.  This is incorrect, since key exchange and authentication
-** are separated in some cipher suites (in particular, ECDHE_RSA_* suites).
-**
-** Providing a |kea| parameter of ssl_kea_ecdh (or kt_ecdh) is interpreted as
-** providing both ECDH and ECDSA certificates.
 */
 SSL_IMPORT SECStatus SSL_ConfigSecureServer(
     PRFileDesc *fd, CERTCertificate *cert,
     SECKEYPrivateKey *key, SSLKEAType kea);
 
 /*
-** Deprecated variant of SSL_ConfigSecureServerCert.  The |data| argument to
-** SSL_ConfigSecureServerCert can be used to pass a certificate chain.
+** Allows SSL socket configuration with caller-supplied certificate chain.
+** If certChainOpt is NULL, tries to find one.
 */
 SSL_IMPORT SECStatus
 SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
                                     const CERTCertificateList *certChainOpt,
                                     SECKEYPrivateKey *key, SSLKEAType kea);
 
 /*
 ** Configure a secure server's session-id cache. Define the maximum number
@@ -1060,18 +998,17 @@ SSL_IMPORT SECStatus SSL_GetSRTPCipher(P
  * Look to see if any of the signers in the cert chain for "cert" are found
  * in the list of caNames.
  * Returns SECSuccess if so, SECFailure if not.
  * Used by NSS_GetClientAuthData.  May be used by other callback functions.
  */
 SSL_IMPORT SECStatus NSS_CmpCertChainWCANames(CERTCertificate *cert,
                                               CERTDistNames *caNames);
 
-/* Deprecated.  This reports a misleading value for certificates that might
- * be used for signing rather than key exchange.
+/*
  * Returns key exchange type of the keys in an SSL server certificate.
  */
 SSL_IMPORT SSLKEAType NSS_FindCertKEAType(CERTCertificate *cert);
 
 /* Set cipher policies to a predefined Domestic (U.S.A.) policy.
  * This essentially allows all supported ciphers.
  */
 SSL_IMPORT SECStatus NSS_SetDomesticPolicy(void);
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -304,40 +304,39 @@ static const ssl3BulkCipherDef bulk_ciph
     {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0, SEC_OID_SEED_CBC},
     {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8, SEC_OID_AES_128_GCM},
     {cipher_chacha20,     calg_chacha20,    32,32, type_aead,  12, 0,16, 0, SEC_OID_CHACHA20_POLY1305},
     {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0, 0},
 };
 
 static const ssl3KEADef kea_defs[] =
 { /* indexed by SSL3KeyExchangeAlgorithm */
-    /* kea            exchKeyType signKeyType authKeyType, is_limited limit tls_keygen ephemeral  oid */
-    {kea_null,           ssl_kea_null, ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_FALSE, 0},
-    {kea_rsa,            ssl_kea_rsa,  ssl_sign_null, ssl_auth_rsa_decrypt,  PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA},
-    /* note: export suites abuse RSA, but these will be removed soon */
-    {kea_rsa_export,     ssl_kea_rsa,  ssl_sign_rsa, ssl_auth_rsa_sign, PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT},
-    {kea_rsa_export_1024,ssl_kea_rsa,  ssl_sign_rsa, ssl_auth_rsa_sign, PR_TRUE, 1024, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT},
-    {kea_dh_dss,         ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,  PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS},
-    {kea_dh_dss_export,  ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS_EXPORT},
-    {kea_dh_rsa,         ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA},
-    {kea_dh_rsa_export,  ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA_EXPORT},
-    {kea_dhe_dss,        ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS},
-    {kea_dhe_dss_export, ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS_EXPORT},
-    {kea_dhe_rsa,        ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA},
-    {kea_dhe_rsa_export, ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA_EXPORT},
-    {kea_dh_anon,        ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON},
-    {kea_dh_anon_export, ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON_EXPORT},
-    {kea_rsa_fips,       ssl_kea_rsa,  ssl_sign_rsa, ssl_auth_rsa_decrypt,   PR_FALSE,   0, PR_TRUE,  PR_FALSE, SEC_OID_TLS_RSA},
+    /* kea            exchKeyType signKeyType is_limited limit tls_keygen ephemeral  oid */
+    {kea_null,           kt_null, ssl_sign_null,  PR_FALSE,   0, PR_FALSE, PR_FALSE, 0},
+    {kea_rsa,            kt_rsa,  ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA},
+    {kea_rsa_export,     kt_rsa,  ssl_sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT},
+    {kea_rsa_export_1024,kt_rsa,  ssl_sign_rsa,   PR_TRUE, 1024, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA_EXPORT},
+    {kea_dh_dss,         kt_dh,   ssl_sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS},
+    {kea_dh_dss_export,  kt_dh,   ssl_sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_DSS_EXPORT},
+    {kea_dh_rsa,         kt_dh,   ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA},
+    {kea_dh_rsa_export,  kt_dh,   ssl_sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA_EXPORT},
+    {kea_dhe_dss,        kt_dh,   ssl_sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS},
+    {kea_dhe_dss_export, kt_dh,   ssl_sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS_EXPORT},
+    {kea_dhe_rsa,        kt_dh,   ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA},
+    {kea_dhe_rsa_export, kt_dh,   ssl_sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA_EXPORT},
+    {kea_dh_anon,        kt_dh,   ssl_sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON},
+    {kea_dh_anon_export, kt_dh,   ssl_sign_null,  PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON_EXPORT},
+    {kea_rsa_fips,       kt_rsa,  ssl_sign_rsa,   PR_FALSE,   0, PR_TRUE,  PR_FALSE, SEC_OID_TLS_RSA},
 #ifndef NSS_DISABLE_ECC
-    {kea_ecdh_ecdsa,     ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA},
-    {kea_ecdhe_ecdsa,    ssl_kea_ecdh, ssl_sign_ecdsa, ssl_auth_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_ECDSA},
-    {kea_ecdh_rsa,       ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_RSA},
-    {kea_ecdhe_rsa,      ssl_kea_ecdh, ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_RSA},
-    {kea_ecdh_anon,      ssl_kea_ecdh, ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDH_ANON},
-    {kea_ecdhe_psk,      ssl_kea_ecdh_psk, ssl_sign_null, ssl_auth_psk, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_PSK}
+    {kea_ecdh_ecdsa,     kt_ecdh, ssl_sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA},
+    {kea_ecdhe_ecdsa,    kt_ecdh, ssl_sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_ECDSA},
+    {kea_ecdh_rsa,       kt_ecdh, ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_RSA},
+    {kea_ecdhe_rsa,      kt_ecdh, ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_RSA},
+    {kea_ecdh_anon,      kt_ecdh, ssl_sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDH_ANON},
+    {kea_ecdhe_psk,      kt_ecdh, ssl_sign_psk,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_PSK}
 #endif /* NSS_DISABLE_ECC */
 };
 
 /* must use ssl_LookupCipherSuiteDef to access */
 static const ssl3CipherSuiteDef cipher_suite_defs[] =
 {
 /*  cipher_suite                    bulk_cipher_alg mac_alg key_exchange_alg */
 
@@ -475,38 +474,23 @@ static const ssl3CipherSuiteDef cipher_s
     {TLS_ECDH_anon_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdh_anon},
     {TLS_ECDH_anon_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdh_anon},
 #endif
     {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_psk},
 #endif /* NSS_DISABLE_ECC */
 };
 /* clang-format on */
 
-static const CK_MECHANISM_TYPE auth_alg_defs[] = {
-    0x80000000L, /* ssl_auth_null */
-    CKM_RSA_PKCS, /* ssl_auth_rsa_decrypt */
-    CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */
-    0x80000000L, /* ssl_auth_kea (unused) */
-    CKM_ECDSA, /* ssl_auth_ecdsa */
-    CKM_ECDH1_DERIVE, /* ssl_auth_ecdh */
-    CKM_RSA_PKCS, /* ssl_auth_rsa_sign */
-    CKM_RSA_PKCS_PSS, /* ssl_auth_rsa_pss */
-    CKM_NSS_HKDF_SHA256 /* ssl_auth_psk (just check for HKDF) */
+static const CK_MECHANISM_TYPE kea_alg_defs[] = {
+    0x80000000L,
+    CKM_RSA_PKCS,
+    CKM_DH_PKCS_DERIVE,
+    CKM_KEA_KEY_DERIVE,
+    CKM_ECDH1_DERIVE
 };
-PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size);
-
-static const CK_MECHANISM_TYPE kea_alg_defs[] = {
-    0x80000000L, /* ssl_kea_null */
-    CKM_RSA_PKCS, /* ssl_kea_rsa */
-    CKM_DH_PKCS_DERIVE, /* ssl_kea_dh */
-    0x80000000L, /* ssl_kea_fortezza (unused) */
-    CKM_ECDH1_DERIVE, /* ssl_kea_ecdh */
-    CKM_ECDH1_DERIVE /* ssl_kea_ecdh_psk */
-};
-PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size);
 
 typedef struct SSLCipher2MechStr {
     SSLCipherAlgorithm calg;
     CK_MECHANISM_TYPE cmech;
 } SSLCipher2Mech;
 
 /* indexed by type SSLCipherAlgorithm */
 static const SSLCipher2Mech alg2Mech[] = {
@@ -817,55 +801,34 @@ ssl_LookupCipherSuiteCfg(ssl3CipherSuite
         if (suites[i].cipher_suite == suite)
             return &suites[i];
     }
     /* return NULL and let the caller handle it.  */
     PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
     return NULL;
 }
 
-static PRBool
-ssl3_HasCert(sslSocket *ss, SSLAuthType authType)
-{
-    PRCList *cursor;
-    if (authType == ssl_auth_null) {
-        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 &&
-            cert->serverKeyPair &&
-            cert->serverKeyPair->privKey &&
-            cert->serverCertChain) {
-            return PR_TRUE;
-        }
-    }
-    return PR_FALSE;
-}
-
 /* Initialize the suite->isPresent value for config_match
  * Returns count of enabled ciphers supported by extant tokens,
  * regardless of policy or user preference.
  * If this returns zero, the user cannot do SSL v3.
  */
 int
 ssl3_config_match_init(sslSocket *ss)
 {
     ssl3CipherSuiteCfg *suite;
     const ssl3CipherSuiteDef *cipher_def;
     SSLCipherAlgorithm cipher_alg;
     CK_MECHANISM_TYPE cipher_mech;
-    SSLAuthType authType;
-    SSLKEAType keaType;
+    SSL3KEAType exchKeyType;
     int i;
     int numPresent = 0;
     int numEnabled = 0;
     PRBool isServer;
+    sslServerCerts *svrAuth;
 
     PORT_Assert(ss);
     if (!ss) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return 0;
     }
     if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
         return 0;
@@ -881,44 +844,60 @@ ssl3_config_match_init(sslSocket *ss)
              */
             cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
             if (!cipher_def) {
                 suite->isPresent = PR_FALSE;
                 continue;
             }
             cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg;
             cipher_mech = ssl3_Alg2Mech(cipher_alg);
+            exchKeyType =
+                kea_defs[cipher_def->key_exchange_alg].exchKeyType;
+#ifdef NSS_DISABLE_ECC
+            svrAuth = ss->serverCerts + exchKeyType;
+#else
+            /* XXX SSLKEAType isn't really a good choice for
+             * indexing certificates. It doesn't work for
+             * (EC)DHE-* ciphers. Here we use a hack to ensure
+             * that the server uses an RSA cert for (EC)DHE-RSA.
+             */
+            switch (cipher_def->key_exchange_alg) {
+                case kea_dhe_dss:
+                    svrAuth = ss->serverCerts + ssl_kea_dh;
+                    break;
+                case kea_ecdhe_rsa:
+                case kea_dhe_rsa:
+                    svrAuth = ss->serverCerts + kt_rsa;
+                    break;
+                case kea_ecdh_ecdsa:
+                case kea_ecdh_rsa:
+                /*
+                 * XXX We ought to have different indices for
+                 * ECDSA- and RSA-signed EC certificates so
+                 * we could support both key exchange mechanisms
+                 * simultaneously. For now, both of them use
+                 * whatever is in the certificate slot for kt_ecdh
+                 */
+                case kea_dhe_dss_export:
+                case kea_dhe_rsa_export:
+                default:
+                    svrAuth = ss->serverCerts + exchKeyType;
+                    break;
+            }
+#endif /* NSS_DISABLE_ECC */
 
             /* Mark the suites that are backed by real tokens, certs and keys */
-            suite->isPresent = PR_TRUE;
-
-            authType = kea_defs[cipher_def->key_exchange_alg].authKeyType;
-            if (authType != ssl_auth_null) {
-                if (isServer && !ssl3_HasCert(ss, authType)) {
-                    suite->isPresent = PR_FALSE;
-                }
-                if (!PK11_TokenExists(auth_alg_defs[authType])) {
-                    suite->isPresent = PR_FALSE;
-                }
-            }
-
-            keaType = kea_defs[cipher_def->key_exchange_alg].exchKeyType;
-            if (keaType != ssl_kea_null &&
-                !PK11_TokenExists(kea_alg_defs[keaType])) {
-                suite->isPresent = PR_FALSE;
-            }
-
-            if (cipher_alg != calg_null &&
-                !PK11_TokenExists(cipher_mech)) {
-                suite->isPresent = PR_FALSE;
-            }
-
-            if (suite->isPresent) {
+            suite->isPresent = (PRBool)(((exchKeyType == kt_null) ||
+                                         ((!isServer ||
+                                           (svrAuth->serverKeyPair && svrAuth->SERVERKEY &&
+                                            svrAuth->serverCertChain)) &&
+                                          PK11_TokenExists(kea_alg_defs[exchKeyType]))) &&
+                                        ((cipher_alg == calg_null) || PK11_TokenExists(cipher_mech)));
+            if (suite->isPresent)
                 ++numPresent;
-            }
         }
     }
     PORT_Assert(numPresent > 0 || numEnabled == 0);
     if (numPresent <= 0) {
         PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED);
     }
     return numPresent;
 }
@@ -952,18 +931,18 @@ config_match(ssl3CipherSuiteCfg *suite, 
     if (!suite->enabled)
         return PR_FALSE;
 
     if ((suite->policy == SSL_NOT_ALLOWED) ||
         (suite->policy > policy))
         return PR_FALSE;
 
     /* We only allow PSK for TLS 1.3 and only if there is resumption. */
-    if (kea_defs[cipher_def->key_exchange_alg].authKeyType ==
-        ssl_auth_psk) {
+    if (kea_defs[cipher_def->key_exchange_alg].signKeyType ==
+        ssl_sign_psk) {
         return tls13_AllowPskCipher(ss, cipher_def);
     }
 
     return (PRBool)(suite->isPresent &&
                     ssl3_CipherSuiteAllowedForVersionRange(
                         suite->cipher_suite, vrange));
 }
 
@@ -3923,18 +3902,18 @@ ssl3_ComputeMasterSecretInt(sslSocket *s
                             (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
     PRBool isTLS12 =
         (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
     /*
      * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
      * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
      * data into a 48-byte value, and does not expect to return the version.
      */
-    PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
-                           (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh));
+    PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
+                           (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
     CK_MECHANISM_TYPE master_derive;
     CK_MECHANISM_TYPE key_derive;
     SECItem params;
     CK_FLAGS keyFlags;
     CK_VERSION pms_version;
     CK_VERSION *pms_version_ptr = NULL;
     /* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */
     CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
@@ -4000,19 +3979,19 @@ tls_ComputeExtendedMasterSecretInt(sslSo
     ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
     CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params;
     SSL3Hashes hashes;
     /*
      * Determine whether to use the DH/ECDH or RSA derivation modes.
      */
     /*
      * TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
-     * mode. Bug 1198298 */
-    PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
-                           (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh));
+     *  mode. Bug 1198298 */
+    PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
+                           (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
     CK_MECHANISM_TYPE master_derive;
     CK_MECHANISM_TYPE key_derive;
     SECItem params;
     const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY;
     CK_VERSION pms_version;
     CK_VERSION *pms_version_ptr = NULL;
     SECStatus rv;
 
@@ -5913,54 +5892,52 @@ ssl_FindIndexByWrapMechanism(CK_MECHANIS
     return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1
                                               : (pMech - wrapMechanismList);
 }
 
 static PK11SymKey *
 ssl_UnwrapSymWrappingKey(
     SSLWrappedSymWrappingKey *pWswk,
     SECKEYPrivateKey *svrPrivKey,
-    SSLAuthType authType,
+    SSL3KEAType exchKeyType,
     CK_MECHANISM_TYPE masterWrapMech,
     void *pwArg)
 {
     PK11SymKey *unwrappedWrappingKey = NULL;
     SECItem wrappedKey;
 #ifndef NSS_DISABLE_ECC
     PK11SymKey *Ks;
     SECKEYPublicKey pubWrapKey;
     ECCWrappedKeyInfo *ecWrapped;
 #endif /* NSS_DISABLE_ECC */
 
     /* found the wrapping key on disk. */
     PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
-    PORT_Assert(pWswk->authType == authType);
+    PORT_Assert(pWswk->exchKeyType == exchKeyType);
     if (pWswk->symWrapMechanism != masterWrapMech ||
-        pWswk->authType != authType) {
+        pWswk->exchKeyType != exchKeyType) {
         goto loser;
     }
     wrappedKey.type = siBuffer;
     wrappedKey.data = pWswk->wrappedSymmetricWrappingkey;
     wrappedKey.len = pWswk->wrappedSymKeyLen;
     PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
 
-    switch (authType) {
-
-        case ssl_auth_rsa_decrypt:
-        case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
+    switch (exchKeyType) {
+
+        case kt_rsa:
             unwrappedWrappingKey =
-                    PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
-                                         masterWrapMech, CKA_UNWRAP, 0);
+                PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
+                                     masterWrapMech, CKA_UNWRAP, 0);
             break;
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
+        case kt_ecdh:
             /*
-             * For ssl_auth_ecd*, we first create an EC public key based on
+             * For kt_ecdh, we first create an EC public key based on
              * data stored with the wrappedSymmetricWrappingkey. Next,
              * we do an ECDH computation involving this public key and
              * the SSL server's (long-term) EC private key. The resulting
              * shared secret is treated the same way as Fortezza's Ks, i.e.,
              * it is used to recover the symmetric wrapping key.
              *
              * The data in wrappedSymmetricWrappingkey is laid out as defined
              * in the ECCWrappedKeyInfo structure.
@@ -6009,24 +5986,24 @@ ssl_UnwrapSymWrappingKey(
             /* Assert? */
             SET_ERROR_CODE
             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
+/* 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 KEA type.  These Symkeys
  * correspond to the wrapped SymKeys kept in the server session cache.
  */
 
 typedef struct {
-    PK11SymKey *symWrapKey[ssl_auth_size];
+    PK11SymKey *symWrapKey[kt_kea_size];
 } ssl3SymWrapKey;
 
 static PZLock *symWrapKeysLock = NULL;
 static ssl3SymWrapKey symWrapKeys[SSL_NUM_WRAP_MECHS];
 
 SECStatus
 ssl_FreeSymWrapKeysLock(void)
 {
@@ -6044,17 +6021,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 < kt_kea_size; ++j) {
             PK11SymKey **pSymWrapKey;
             pSymWrapKey = &symWrapKeys[i].symWrapKey[j];
             if (*pSymWrapKey) {
                 PK11_FreeSymKey(*pSymWrapKey);
                 *pSymWrapKey = NULL;
             }
         }
     }
@@ -6070,29 +6047,24 @@ ssl_InitSymWrapKeysLock(void)
     symWrapKeysLock = PZ_NewLock(nssILockOther);
     return symWrapKeysLock ? SECSuccess : SECFailure;
 }
 
 /* Try to get wrapping key for mechanism from in-memory array.
  * If that fails, look for one on disk.
  * If that fails, generate a new one, put the new one on disk,
  * Put the new key in the in-memory array.
- *
- * 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,
+               SSL3KEAType exchKeyType,
                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;
     SECStatus rv;
@@ -6100,35 +6072,28 @@ ssl3_GetWrappingKey(sslSocket *ss,
     SSLWrappedSymWrappingKey wswk;
 #ifndef NSS_DISABLE_ECC
     PK11SymKey *Ks = NULL;
     SECKEYPublicKey *pubWrapKey = NULL;
     SECKEYPrivateKey *privWrapKey = NULL;
     ECCWrappedKeyInfo *ecWrapped;
 #endif /* NSS_DISABLE_ECC */
 
-    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;
-    svrPrivKey = serverCert->serverKeyPair->privKey;
+    svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY;
+    PORT_Assert(svrPrivKey != NULL);
+    if (!svrPrivKey) {
+        return NULL; /* why are we here?!? */
+    }
 
     symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech);
     PORT_Assert(symWrapMechIndex >= 0);
     if (symWrapMechIndex < 0)
         return NULL; /* invalid masterWrapMech. */
 
-    pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType];
+    pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[exchKeyType];
 
     ssl_InitSessionCacheLocks(PR_TRUE);
 
     PZ_Lock(symWrapKeysLock);
 
     unwrappedWrappingKey = *pSymWrapKey;
     if (unwrappedWrappingKey != NULL) {
         if (PK11_VerifyKeyOK(unwrappedWrappingKey)) {
@@ -6137,20 +6102,20 @@ 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)) {
+    if (ssl_GetWrappingKey(symWrapMechIndex, exchKeyType, &wswk)) {
         /* found the wrapped sym wrapping key on disk. */
         unwrappedWrappingKey =
-            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType,
+            ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType,
                                      masterWrapMech, pwArg);
         if (unwrappedWrappingKey) {
             goto install;
         }
     }
 
     if (!masterSecretSlot) /* caller doesn't want to create a new one. */
         goto loser;
@@ -6165,37 +6130,41 @@ ssl3_GetWrappingKey(sslSocket *ss,
         goto loser;
     }
 
     /* Prepare the buffer to receive the wrappedWrappingKey,
      * the symmetric wrapping key wrapped using the server's pub key.
      */
     PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */
 
-    svrPubKey = serverCert->serverKeyPair->pubKey;
+    if (ss->serverCerts[exchKeyType].serverKeyPair) {
+        svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey;
+    }
+    if (svrPubKey == NULL) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        goto loser;
+    }
     wrappedKey.type = siBuffer;
     wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
     wrappedKey.data = wswk.wrappedSymmetricWrappingkey;
 
     PORT_Assert(wrappedKey.len <= sizeof wswk.wrappedSymmetricWrappingkey);
     if (wrappedKey.len > sizeof wswk.wrappedSymmetricWrappingkey)
         goto loser;
 
     /* wrap symmetric wrapping key in server's public key. */
-    switch (authType) {
-        case ssl_auth_rsa_decrypt:
-        case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
+    switch (exchKeyType) {
+        case kt_rsa:
             asymWrapMechanism = CKM_RSA_PKCS;
             rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
                                     unwrappedWrappingKey, &wrappedKey);
             break;
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
+        case kt_ecdh:
             /*
              * We generate an ephemeral EC key pair. Perform an ECDH
              * computation involving this ephemeral EC public key and
              * the SSL server's (long-term) EC private key. The resulting
              * shared secret is treated in the same way as Fortezza's Ks,
              * i.e., it is used to wrap the wrapping key. To facilitate
              * unwrapping in ssl_UnwrapWrappingKey, we also store all
              * relevant info about the ephemeral EC public key in
@@ -6290,33 +6259,33 @@ ssl3_GetWrappingKey(sslSocket *ss,
         goto loser;
     }
 
     PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM);
 
     wswk.symWrapMechanism = masterWrapMech;
     wswk.symWrapMechIndex = symWrapMechIndex;
     wswk.asymWrapMechanism = asymWrapMechanism;
-    wswk.authType = authType;
+    wswk.exchKeyType = exchKeyType;
     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)) {
         /* 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, exchKeyType,
                                      masterWrapMech, pwArg);
     }
 
 install:
     if (unwrappedWrappingKey) {
         *pSymWrapKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
     }
 
@@ -6581,26 +6550,26 @@ ssl3_SendClientKeyExchange(sslSocket *ss
             goto loser;
         }
     }
 
     ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
     ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey);
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
-        case ssl_kea_rsa:
+        case kt_rsa:
             rv = sendRSAClientKeyExchange(ss, serverKey);
             break;
 
-        case ssl_kea_dh:
+        case kt_dh:
             rv = sendDHClientKeyExchange(ss, serverKey);
             break;
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
+        case kt_ecdh:
             rv = ssl3_SendECDHClientKeyExchange(ss, serverKey);
             break;
 #endif /* NSS_DISABLE_ECC */
 
         default:
             /* got an unknown or unsupported Key Exchange Algorithm.  */
             SEND_ALERT
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
@@ -7053,17 +7022,17 @@ ssl3_HandleServerHelloPart2(sslSocket *s
              * used at all (bug 1176526).
              */
             if (sid->u.ssl3.keys.extendedMasterSecretUsed &&
                 !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
                 errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
                 goto alert_loser;
             }
 
-            ss->sec.authType = sid->authType;
+            ss->sec.authAlgorithm = sid->authAlgorithm;
             ss->sec.authKeyBits = sid->authKeyBits;
             ss->sec.keaType = sid->keaType;
             ss->sec.keaKeyBits = sid->keaKeyBits;
 
             /* 3 cases here:
              * a) key is wrapped (implies using PKCS11)
              * b) key is unwrapped, but we're still using PKCS11
              * c) key is unwrapped, and we're bypassing PKCS11.
@@ -7199,18 +7168,18 @@ ssl3_HandleServerHelloPart2(sslSocket *s
         if (rv != SECSuccess)
             goto loser;
         /* Clean up the temporary pointer to the handshake buffer. */
         ss->xtnData.signedCertTimestamps.data = NULL;
         ss->xtnData.signedCertTimestamps.len = 0;
     }
 
     ss->ssl3.hs.isResuming = PR_FALSE;
-    if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_null) {
-        /* All current cipher suites other than those with ssl_auth_null (i.e.,
+    if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_null) {
+        /* All current cipher suites other than those with ssl_sign_null (i.e.,
          * (EC)DH_anon_* suites) require a certificate, so use that signal. */
         ss->ssl3.hs.ws = wait_server_cert;
     } else {
         /* All the remaining cipher suites must be (EC)DH_anon_* and so
          * must be ephemeral. Note, if we ever add PSK this might
          * change. */
         PORT_Assert(ss->ssl3.hs.kea_def->ephemeral);
         ss->ssl3.hs.ws = wait_server_key;
@@ -7254,17 +7223,18 @@ ssl3_HandleServerKeyExchange(sslSocket *
         desc = unexpected_message;
         goto alert_loser;
     }
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
-        case ssl_kea_rsa: {
+
+        case kt_rsa: {
             SECItem modulus = { siBuffer, NULL, 0 };
             SECItem exponent = { siBuffer, NULL, 0 };
 
             rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
             if (rv != SECSuccess) {
                 goto loser; /* malformed. */
             }
             /* This exchange method is only used by export cipher suites.
@@ -7290,17 +7260,18 @@ ssl3_HandleServerKeyExchange(sslSocket *
                 }
             }
             rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
             if (rv != SECSuccess) {
                 goto loser; /* malformed. */
             }
             if (length != 0) {
                 if (isTLS)
-                    desc = decode_error;
+                    desc =
+                        decode_error;
                 goto alert_loser; /* malformed. */
             }
 
             /* failures after this point are not malformed handshakes. */
             /* TLS: send decrypt_error if signature failed. */
             desc = isTLS ? decrypt_error : handshake_failure;
 
             /*
@@ -7346,17 +7317,17 @@ ssl3_HandleServerKeyExchange(sslSocket *
                 SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent)) {
                 goto no_memory;
             }
             ss->sec.peerKey = peerKey;
             ss->ssl3.hs.ws = wait_cert_request;
             return SECSuccess;
         }
 
-        case ssl_kea_dh: {
+        case kt_dh: {
             SECItem dh_p = { siBuffer, NULL, 0 };
             SECItem dh_g = { siBuffer, NULL, 0 };
             SECItem dh_Ys = { siBuffer, NULL, 0 };
             unsigned dh_p_bits;
             unsigned dh_g_bits;
             unsigned dh_Ys_bits;
             PRInt32 minDH;
 
@@ -7402,17 +7373,18 @@ ssl3_HandleServerKeyExchange(sslSocket *
                 }
             }
             rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
             if (rv != SECSuccess) {
                 goto loser; /* malformed. */
             }
             if (length != 0) {
                 if (isTLS)
-                    desc = decode_error;
+                    desc =
+                        decode_error;
                 goto alert_loser; /* malformed. */
             }
 
             PRINT_BUF(60, (NULL, "Server DH p", dh_p.data, dh_p.len));
             PRINT_BUF(60, (NULL, "Server DH g", dh_g.data, dh_g.len));
             PRINT_BUF(60, (NULL, "Server DH Ys", dh_Ys.data, dh_Ys.len));
 
             /* failures after this point are not malformed handshakes. */
@@ -7465,17 +7437,17 @@ ssl3_HandleServerKeyExchange(sslSocket *
                 goto no_memory;
             }
             ss->sec.peerKey = peerKey;
             ss->ssl3.hs.ws = wait_cert_request;
             return SECSuccess;
         }
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
+        case kt_ecdh:
             rv = ssl3_HandleECDHServerKeyExchange(ss, b, length);
             return rv;
 #endif /* NSS_DISABLE_ECC */
 
         default:
             desc = handshake_failure;
             errCode = SEC_ERROR_UNSUPPORTED_KEYALG;
             break; /* goto alert_loser; */
@@ -8239,36 +8211,25 @@ ssl3_SendServerHelloSequence(sslSocket *
         return rv; /* error code is set. */
     }
     /* We have to do this after the call to ssl3_SendServerHello,
      * because kea_def is set up by ssl3_SendServerHello().
      */
     kea_def = ss->ssl3.hs.kea_def;
     ss->ssl3.hs.usedStepDownKey = PR_FALSE;
 
-    if (kea_def->is_limited) {
+    if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) {
         /* see if we can legally use the key in the cert. */
-        unsigned int keyBits;
-        const sslServerCert *cert;
-
-        /* Note that all ciphers that are limited use a SSLAuthType of
-         * ssl_auth_rsa_sign.  This isn't even remotely correct, but these keys
-         * need to do either signing or decryption on demand. */
-        PORT_Assert(kea_def->authKeyType == ssl_auth_rsa_sign);
-
-        cert = ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_sign);
-        if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) {
-            PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
-            return SECFailure;
-        }
-
-        keyBits = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
-        PORT_Assert(keyBits);
-
-        if (keyBits <= kea_def->key_size_limit) {
+        unsigned int keyLen; /* bytes */
+
+        keyLen = PK11_GetPrivateModulusLen(
+            ss->serverCerts[kea_def->exchKeyType].SERVERKEY);
+
+        if (keyLen > 0 &&
+            keyLen * BPB <= kea_def->key_size_limit) {
             /* XXX AND cert is not signing only!! */
             /* just fall through and use it. */
         } else if (ss->stepDownKeyPair != NULL) {
             ss->ssl3.hs.usedStepDownKey = PR_TRUE;
             rv = ssl3_SendServerKeyExchange(ss);
             if (rv != SECSuccess) {
                 return rv; /* err code was set. */
             }
@@ -8300,24 +8261,29 @@ ssl3_SendServerHelloSequence(sslSocket *
                                                   : wait_client_key;
     return SECSuccess;
 }
 
 /* An empty TLS Renegotiation Info (RI) extension */
 static const PRUint8 emptyRIext[5] = { 0xff, 0x01, 0x00, 0x01, 0x00 };
 
 static PRBool
-ssl3_KEASupportsTickets(const ssl3KEADef *kea_def)
-{
-    if (kea_def->signKeyType == ssl_sign_dsa) {
-        /* TODO: Fix session tickets for DSS. The server code rejects the
-         * session ticket received from the client. Bug 1174677 */
-        return PR_FALSE;
-    }
-    return PR_TRUE;
+ssl3_KEAAllowsSessionTicket(SSL3KeyExchangeAlgorithm kea)
+{
+    switch (kea) {
+        case kea_dhe_dss:
+        case kea_dhe_dss_export:
+        case kea_dh_dss_export:
+        case kea_dh_dss:
+            /* TODO: Fix session tickets for DSS. The server code rejects the
+             * session ticket received from the client. Bug 1174677 */
+            return PR_FALSE;
+        default:
+            return PR_TRUE;
+    };
 }
 
 /* Select a cipher suite.
 **
 ** NOTE: This suite selection algorithm should be the same as the one in
 ** ssl3_HandleV2ClientHello().
 **
 ** If TLS 1.0 is enabled, we could handle the case where the client
@@ -8521,55 +8487,16 @@ ssl3_ServerCallSNICallback(sslSocket *ss
     return SECSuccess;
 
 alert_loser:
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
     PORT_SetError(errCode);
     return SECFailure;
 }
 
-SECStatus
-ssl3_SelectServerCert(sslSocket *ss)
-{
-    const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
-    PRCList *cursor;
-
-    /* This picks the first certificate that has:
-     * a) the right authentication method, and
-     * 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) {
-            continue;
-        }
-#ifndef NSS_DISABLE_ECC
-        if ((cert->certType.authType == ssl_auth_ecdh ||
-             cert->certType.authType == ssl_auth_ecdsa) &&
-            !SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                     cert->certType.u.namedCurve)) {
-            continue;
-        }
-#endif
-
-        /* Found one. */
-        ss->sec.serverCert = cert;
-        ss->sec.authType = cert->certType.authType;
-        ss->sec.authKeyBits = cert->serverKeyBits;
-        return SECSuccess;
-    }
-
-    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
-    return SECFailure;
-}
-
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Client Hello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     sslSessionID *sid = NULL;
@@ -9025,18 +8952,18 @@ static SECStatus ssl3_HandleClientHelloP
     rv = ssl3_NegotiateCipherSuite(ss, suites);
     if (rv != SECSuccess) {
         desc = handshake_failure;
         errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
         goto alert_loser;
     }
 
     if (canOfferSessionTicket)
-        canOfferSessionTicket =
-                ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def);
+        canOfferSessionTicket = ssl3_KEAAllowsSessionTicket(
+            ss->ssl3.hs.suite_def->key_exchange_alg);
 
     if (canOfferSessionTicket) {
         ssl3_RegisterServerHelloExtensionSender(ss,
                                                 ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn);
     }
 
     /* Select a compression algorithm. */
     for (i = 0; i < comps->len; i++) {
@@ -9063,32 +8990,23 @@ 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) {
-                /* 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"
              *    extension but the new ClientHello contains the extension, then the
              *    server MUST NOT perform the abbreviated handshake.  Instead, it
              *    SHOULD continue with a full handshake (as described in
              *    Section 5.2) to negotiate a new session.
              *
              * o  If the original session used the "extended_master_secret"
@@ -9129,26 +9047,27 @@ compression_found:
                 if (ss->opt.bypassPKCS11) {
                     /* we cannot restart a non-bypass session in a
                     ** bypass socket.
                     */
                     break;
                 }
 #endif
 
-                wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert,
+                wrapKey = ssl3_GetWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType,
                                               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 */
-                    keyFlags = CKF_SIGN | CKF_VERIFY;
+                    keyFlags =
+                        CKF_SIGN | CKF_VERIFY;
                 }
 
                 wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
                 wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
 
                 /* unwrap the master secret. */
                 pwSpec->master_secret =
                     PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
@@ -9192,28 +9111,28 @@ compression_found:
              *
              * XXX make sure compression still matches
              */
             SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_hits);
             if (ss->statelessResume)
                 SSL_AtomicIncrementLong(&ssl3stats.hch_sid_stateless_resumes);
             ss->ssl3.hs.isResuming = PR_TRUE;
 
-            ss->sec.authType = sid->authType;
+            ss->sec.authAlgorithm = sid->authAlgorithm;
             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
+            ** but they do remember the kea type 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->serverCerts[sid->keaType].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.pwSpec->srvVirtName;
@@ -9292,23 +9211,16 @@ compression_found:
 
     rv = ssl3_ServerCallSNICallback(ss);
     if (rv != SECSuccess) {
         /* The alert has already been sent. */
         errCode = PORT_GetError();
         goto loser;
     }
 
-    rv = ssl3_SelectServerCert(ss);
-    if (rv != SECSuccess) {
-        errCode = PORT_GetError();
-        desc = handshake_failure;
-        goto alert_loser;
-    }
-
     sid = ssl3_NewSessionID(ss, PR_TRUE);
     if (sid == NULL) {
         errCode = PORT_GetError();
         goto loser; /* memory error is set. */
     }
     ss->sec.ci.sid = sid;
 
     sid->u.ssl3.keys.extendedMasterSecretUsed =
@@ -9532,23 +9444,16 @@ suite_found:
         !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
         desc = handshake_failure;
         errCode = SSL_ERROR_UNSAFE_NEGOTIATION;
         goto alert_loser;
     }
 
     ss->ssl3.hs.compression = ssl_compression_null;
 
-    rv = ssl3_SelectServerCert(ss);
-    if (rv != SECSuccess) {
-        errCode = PORT_GetError();
-        desc = handshake_failure;
-        goto alert_loser;
-    }
-
     /* we don't even search for a cache hit here.  It's just a miss. */
     SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_misses);
     sid = ssl3_NewSessionID(ss, PR_TRUE);
     if (sid == NULL) {
         errCode = PORT_GetError();
         goto loser; /* memory error is set. */
     }
     ss->sec.ci.sid = sid;
@@ -9719,17 +9624,17 @@ ssl3_SendDHServerKeyExchange(sslSocket *
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SSL3Hashes hashes;
     SSLSignatureAndHashAlg sigAndHash;
     SECKEYDHParams dhParam;
 
     ssl3KeyPair *keyPair = NULL;
     SECKEYPublicKey *pubKey = NULL;   /* Ephemeral DH key */
     SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
-    SECKEYPrivateKey *certPrivateKey;
+    int certIndex = -1;
 
     if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) {
         /* TODO: Support DH_anon. It might be sufficient to drop the signature.
                  See bug 1170510. */
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
@@ -9772,19 +9677,26 @@ ssl3_SendDHServerKeyExchange(sslSocket *
                                &ss->ssl3.hs.client_random,
                                &ss->ssl3.hs.server_random,
                                &hashes, ss->opt.bypassPKCS11);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
+    /* It has been suggested to test kea_def->signKeyType instead, and to use
+     * ssl_auth_* instead. Investigate what to do. See bug 102794. */
+    if (kea_def->kea == kea_dhe_rsa)
+        certIndex = ssl_kea_rsa;
+    else
+        certIndex = ssl_kea_dh;
+
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
-    certPrivateKey = ss->sec.serverCert->serverKeyPair->privKey;
-    rv = ssl3_SignHashes(&hashes, certPrivateKey, &signed_hash, isTLS);
+    rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY,
+                         &signed_hash, isTLS);
     if (rv != SECSuccess) {
         goto loser; /* ssl3_SignHashes has set err. */
     }
     if (signed_hash.data == NULL) {
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
     length = 2 + pubKey->u.dh.prime.len +
@@ -9922,17 +9834,17 @@ ssl3_SendServerKeyExchange(sslSocket *ss
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) {
         return SECFailure;
     }
 
     switch (kea_def->exchKeyType) {
-        case ssl_kea_rsa:
+        case kt_rsa:
             /* Perform SSL Step-Down here. */
             sdPub = ss->stepDownKeyPair->pubKey;
             PORT_Assert(sdPub != NULL);
             if (!sdPub) {
                 PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
                 return SECFailure;
             }
             rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg,
@@ -9942,29 +9854,29 @@ ssl3_SendServerKeyExchange(sslSocket *ss
                                               &ss->ssl3.hs.server_random,
                                               &hashes, ss->opt.bypassPKCS11);
             if (rv != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
                 return rv;
             }
 
             isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
-            rv = ssl3_SignHashes(&hashes, ss->sec.serverCert->serverKeyPair->privKey,
+            rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].SERVERKEY,
                                  &signed_hash, isTLS);
             if (rv != SECSuccess) {
                 goto loser; /* ssl3_SignHashes has set err. */
             }
             if (signed_hash.data == NULL) {
                 /* how can this happen and rv == SECSuccess ?? */
                 PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
                 goto loser;
             }
             length = 2 + sdPub->u.rsa.modulus.len +
-                    2 + sdPub->u.rsa.publicExponent.len +
-                    2 + signed_hash.len;
+                     2 + sdPub->u.rsa.publicExponent.len +
+                     2 + signed_hash.len;
 
             if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
                 length += 2;
             }
 
             rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
             if (rv != SECSuccess) {
                 goto loser; /* err set by AppendHandshake. */
@@ -9999,23 +9911,23 @@ ssl3_SendServerKeyExchange(sslSocket *ss
             return SECSuccess;
 
         case ssl_kea_dh: {
             rv = ssl3_SendDHServerKeyExchange(ss);
             return rv;
         }
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh: {
+        case kt_ecdh: {
             rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash);
             return rv;
         }
 #endif /* NSS_DISABLE_ECC */
 
-        case ssl_kea_null:
+        case kt_null:
         default:
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             break;
     }
 loser:
     if (signed_hash.data != NULL)
         PORT_Free(signed_hash.data);
     return SECFailure;
@@ -10622,65 +10534,77 @@ ssl3_HandleClientKeyExchange(sslSocket *
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
         return SECFailure;
     }
 
     kea_def = ss->ssl3.hs.kea_def;
 
     if (ss->ssl3.hs.usedStepDownKey) {
         PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */
-                    && kea_def->authKeyType == ssl_auth_rsa_sign
-                    && ss->stepDownKeyPair != NULL);
+                    &&
+                    kea_def->exchKeyType == kt_rsa &&
+                    ss->stepDownKeyPair != NULL);
         if (!kea_def->is_limited ||
-            kea_def->authKeyType != ssl_auth_rsa_sign ||
+            kea_def->exchKeyType != kt_rsa ||
             ss->stepDownKeyPair == NULL) {
             /* shouldn't happen, don't use step down if it does */
             goto skip;
         }
         serverKeyPair = ss->stepDownKeyPair;
         ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB;
     } else
     skip:
-    if (kea_def->ephemeral) {
-        if (kea_def->exchKeyType == ssl_kea_dh && ss->dheKeyPair) {
+    if (kea_def->kea == kea_dhe_dss ||
+        kea_def->kea == kea_dhe_rsa) {
+        if (ss->dheKeyPair) {
             serverKeyPair = ss->dheKeyPair;
             if (serverKeyPair->pubKey) {
                 ss->sec.keaKeyBits =
                     SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
             }
         }
+    } else
 #ifndef NSS_DISABLE_ECC
-        else if (kea_def->exchKeyType == ssl_kea_ecdh &&
-                 ss->ephemeralECDHKeyPair) {
+        /* XXX Using SSLKEAType to index server certifiates
+         * does not work for (EC)DHE ciphers. Until we have
+         * an indexing mechanism general enough for all key
+         * exchange algorithms, we'll need to deal with each
+         * one seprately.
+         */
+        if ((kea_def->kea == kea_ecdhe_rsa) ||
+            (kea_def->kea == kea_ecdhe_ecdsa)) {
+        if (ss->ephemeralECDHKeyPair != NULL) {
             serverKeyPair = ss->ephemeralECDHKeyPair;
             if (serverKeyPair->pubKey) {
                 ss->sec.keaKeyBits =
-                        SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
-            }
-        }
+                    SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
+            }
+        }
+    } else
 #endif
-    } else {
-        serverKeyPair = ss->sec.serverCert->serverKeyPair;
-        ss->sec.keaKeyBits = ss->sec.serverCert->serverKeyBits;
+    {
+        sslServerCerts *sc = ss->serverCerts + kea_def->exchKeyType;
+        serverKeyPair = sc->serverKeyPair;
+        ss->sec.keaKeyBits = sc->serverKeyBits;
     }
 
     if (serverKeyPair) {
         serverKey = serverKeyPair->privKey;
     }
 
     if (serverKey == NULL) {
         SEND_ALERT
         PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG);
         return SECFailure;
     }
 
     ss->sec.keaType = kea_def->exchKeyType;
 
     switch (kea_def->exchKeyType) {
-        case ssl_kea_rsa:
+        case kt_rsa:
             rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey);
             if (rv != SECSuccess) {
                 SEND_ALERT
                 return SECFailure; /* error code set */
             }
             break;
 
         case ssl_kea_dh:
@@ -10695,17 +10619,23 @@ ssl3_HandleClientKeyExchange(sslSocket *
                                                 serverPubKey, serverKey);
             if (rv != SECSuccess) {
                 SSL3_SendAlert(ss, alert_fatal, handshake_failure);
                 return SECFailure; /* error code set */
             }
             break;
 
 #ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
+        case kt_ecdh:
+            /* XXX We really ought to be able to store multiple
+             * EC certs (a requirement if we wish to support both
+             * ECDH-RSA and ECDH-ECDSA key exchanges concurrently).
+             * When we make that change, we'll need an index other
+             * than kt_ecdh to pick the right EC certificate.
+             */
             if (serverKeyPair) {
                 serverPubKey = serverKeyPair->pubKey;
             }
             if (serverPubKey == NULL) {
                 /* XXX Is this the right error code? */
                 PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
                 return SECFailure;
             }
@@ -10882,37 +10812,54 @@ loser:
  */
 SECStatus
 ssl3_SendCertificate(sslSocket *ss)
 {
     SECStatus rv;
     CERTCertificateList *certChain;
     int certChainLen = 0;
     int i;
+    SSL3KEAType certIndex;
 #ifdef NISCC_TEST
     SECItem fakeCert;
     int ndex = -1;
 #endif
     PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
     unsigned int contextLen = 0;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->sec.localCert)
         CERT_DestroyCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
-        /* A server certificate is selected in ssl3_HandleClientHello. */
-        PORT_Assert(ss->sec.serverCert);
-
-        certChain = ss->sec.serverCert->serverCertChain;
-        ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
+        sslServerCerts *sc = NULL;
+
+        /* XXX SSLKEAType isn't really a good choice for
+         * indexing certificates (it breaks when we deal
+         * with (EC)DHE-* cipher suites. This hack ensures
+         * the RSA cert is picked for (EC)DHE-RSA.
+         * Revisit this when we add server side support
+         * for ECDHE-ECDSA or client-side authentication
+         * using EC certificates.
+         */
+        if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+            (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+            certIndex = kt_rsa;
+        } else {
+            certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+        }
+        sc = ss->serverCerts + certIndex;
+        certChain = sc->serverCertChain;
+        ss->sec.authKeyBits = sc->serverKeyBits;
+        ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
+        ss->sec.localCert = CERT_DupCertificate(sc->serverCert);
     } else {
         certChain = ss->ssl3.clientCertChain;
         ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
     }
 
 #ifdef NISCC_TEST
     rv = get_fake_cert(&fakeCert, &ndex);
 #endif
@@ -10989,32 +10936,37 @@ ssl3_SendCertificate(sslSocket *ss)
  * single-stapling, send only a single cert status
  */
 SECStatus
 ssl3_SendCertificateStatus(sslSocket *ss)
 {
     SECStatus rv;
     int len = 0;
     SECItemArray *statusToSend = NULL;
-    const sslServerCert *serverCert;
+    SSL3KEAType certIndex;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->sec.isServer);
 
     if (!ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn))
         return SECSuccess;
 
     /* Use certStatus based on the cert being used. */
-    serverCert = ss->sec.serverCert;
-    if (serverCert->certStatusArray && serverCert->certStatusArray->len) {
-        statusToSend = serverCert->certStatusArray;
+    if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+        (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+        certIndex = kt_rsa;
+    } else {
+        certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+    if (ss->certStatusArray[certIndex] && ss->certStatusArray[certIndex]->len) {
+        statusToSend = ss->certStatusArray[certIndex];
     }
     if (!statusToSend)
         return SECSuccess;
 
     /* Use the array's first item only (single stapling) */
     len = 1 + statusToSend->items[0].len + 3;
 
     rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len);
@@ -11361,17 +11313,17 @@ ssl3_AuthCertificate(sslSocket *ss)
     ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
 
     if (!ss->sec.isServer) {
         CERTCertificate *cert = ss->sec.peerCert;
 
         /* set the server authentication type and size from the value
         ** in the cert. */
         SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
-        ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType;
+        ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
         ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
         if (pubKey) {
             KeyType pubKeyType;
             PRInt32 minKey;
             /* This partly fixes Bug 124230 and may cause problems for
              * callers which depend on the old (wrong) behavior. */
             ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
             pubKeyType = SECKEY_GetPublicKeyType(pubKey);
@@ -11826,25 +11778,24 @@ 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, SSL3KEAType effectiveExchKeyType)
 {
     PK11SymKey *wrappingKey = NULL;
     PK11SlotInfo *symKeySlot;
     void *pwArg = ss->pkcs11PinArg;
     SECStatus rv = SECFailure;
     PRBool isServer = ss->sec.isServer;
     CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
-
     symKeySlot = PK11_GetSlotFromKey(spec->master_secret);
     if (!isServer) {
         int wrapKeyIndex;
         int incarnation;
 
         /* these next few functions are mere accessors and don't fail. */
         sid->u.ssl3.masterWrapIndex = wrapKeyIndex =
             PK11_GetCurrentWrapIndex(symKeySlot);
@@ -11880,17 +11831,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,
+                ssl3_GetWrappingKey(ss, symKeySlot, effectiveExchKeyType,
                                     mechanism, pwArg);
             if (wrappingKey) {
                 mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */
             }
         }
     }
 
     sid->u.ssl3.masterWrapMech = mechanism;
@@ -11917,16 +11868,17 @@ ssl3_CacheWrappedMasterSecret(sslSocket 
 static SECStatus
 ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
                     const SSL3Hashes *hashes)
 {
     sslSessionID *sid = ss->sec.ci.sid;
     SECStatus rv = SECSuccess;
     PRBool isServer = ss->sec.isServer;
     PRBool isTLS;
+    SSL3KEAType effectiveExchKeyType;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle finished handshake",
                 SSL_GETPID(), ss->fd));
 
     if (ss->ssl3.hs.ws != wait_finished) {
@@ -11993,17 +11945,17 @@ ssl3_HandleFinished(sslSocket *ss, SSL3O
         /* Send a NewSessionTicket message if the client sent us
          * either an empty session ticket, or one that did not verify.
          * (Note that if either of these conditions was met, then the
          * server has sent a SessionTicket extension in the
          * ServerHello message.)
          */
         if (isServer && !ss->ssl3.hs.isResuming &&
             ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) &&
-            ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def)) {
+            ssl3_KEAAllowsSessionTicket(ss->ssl3.hs.suite_def->key_exchange_alg)) {
             /* RFC 5077 Section 3.3: "In the case of a full handshake, the
              * server MUST verify the client's Finished message before sending
              * the ticket." Presumably, this also means that the client's
              * certificate, if any, must be verified beforehand too.
              */
             rv = ssl3_SendNewSessionTicket(ss);
             if (rv != SECSuccess) {
                 goto xmit_loser;
@@ -12041,18 +11993,25 @@ ssl3_HandleFinished(sslSocket *ss, SSL3O
     }
 
 xmit_loser:
     ssl_ReleaseXmitBufLock(ss); /*************************************/
     if (rv != SECSuccess) {
         return rv;
     }
 
+    if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+        ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
+        effectiveExchKeyType = kt_rsa;
+    } else {
+        effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+
     if (sid->cached == never_cached && !ss->opt.noCache && ss->sec.cache) {
-        rv = ssl3_FillInCachedSID(ss, sid);
+        rv = ssl3_FillInCachedSID(ss, sid, effectiveExchKeyType);
 
         /* If the wrap failed, we don't cache the sid.
          * The connection continues normally however.
          */
         ss->ssl3.hs.cacheSID = rv == SECSuccess;
     }
 
     if (ss->ssl3.hs.authCertificatePending) {
@@ -12066,31 +12025,33 @@ xmit_loser:
         return SECWouldBlock;
     }
 
     rv = ssl3_FinishHandshake(ss);
     return rv;
 }
 
 SECStatus
-ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
+ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
+                     SSL3KEAType effectiveExchKeyType)
 {
     SECStatus rv;
 
     /* fill in the sid */
     sid->u.ssl3.cipherSuite =
             ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ?
             ss->ssl3.hs.origCipherSuite : ss->ssl3.hs.cipher_suite;
     sid->u.ssl3.compression = ss->ssl3.hs.compression;
     sid->u.ssl3.policy = ss->ssl3.policy;
 #ifndef NSS_DISABLE_ECC
     sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
 #endif
+    sid->u.ssl3.exchKeyType = effectiveExchKeyType;
     sid->version = ss->version;
-    sid->authType = ss->sec.authType;
+    sid->authAlgorithm = ss->sec.authAlgorithm;
     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);
 
     ssl_GetSpecReadLock(ss); /*************************************/
@@ -12102,17 +12063,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
         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);
+                                           effectiveExchKeyType);
         sid->u.ssl3.keys.msIsWrapped = PR_TRUE;
     }
     ssl_ReleaseSpecReadLock(ss); /*************************************/
 
     return rv;
 }
 
 /* The return type is SECStatus instead of void because this function needs
@@ -12166,17 +12127,17 @@ ssl3_FinishHandshake(sslSocket *ss)
  * hanshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus rv = SECSuccess;
     SSL3HandshakeType type = ss->ssl3.hs.msg_type;
-    SSL3Hashes hashes; /* computed hashes are put here. */
+    SSL3Hashes hashes;            /* computed hashes are put here. */
     SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
     PRUint8 hdr[4];
     PRUint8 dtlsData[8];
     PRBool computeHashes = PR_FALSE;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     /*
@@ -12536,17 +12497,17 @@ ssl3_HandleHandshake(sslSocket *ss, sslB
             } else {
                 PORT_Assert(buf->len == 0);
                 break;
             }
         }
     } /* end loop */
 
     origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
-    buf->buf = NULL; /* not a leak. */
+    buf->buf = NULL;  /* not a leak. */
     return SECSuccess;
 }
 
 /* These macros return the given value with the MSB copied to all the other
  * bits. They use the fact that arithmetic shift shifts-in the sign bit.
  * However, this is not ensured by the C standard so you may need to replace
  * them with something else for odd compilers. */
 #define DUPLICATE_MSB_TO_ALL(x) ((unsigned)((int)(x) >> (sizeof(int) * 8 - 1)))
@@ -13350,31 +13311,25 @@ ssl3_FreeKeyPair(ssl3KeyPair *keyPair)
  * Creates the public and private RSA keys for SSL Step down.
  * Called from SSL_ConfigSecureServer in sslsecur.c
  */
 SECStatus
 ssl3_CreateRSAStepDownKeys(sslSocket *ss)
 {
     SECStatus rv = SECSuccess;
     SECKEYPrivateKey *privKey; /* RSA step down key */
-    SECKEYPublicKey *pubKey; /* RSA step down key */
-    const sslServerCert *cert;
-    unsigned int len;
+    SECKEYPublicKey *pubKey;   /* RSA step down key */
 
     if (ss->stepDownKeyPair)
         ssl3_FreeKeyPair(ss->stepDownKeyPair);
     ss->stepDownKeyPair = NULL;
 #ifndef HACKED_EXPORT_SERVER
-    cert = ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_decrypt);
-    if (!cert) {
-        return SECFailure;
-    }
-    len = PK11_GetPrivateModulusLen(cert->serverKeyPair->privKey);
     /* Sigh, should have a get key strength call for private keys */
-    if (len > EXPORT_RSA_KEY_LENGTH) {
+    if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].SERVERKEY) >
+        EXPORT_RSA_KEY_LENGTH) {
         /* need to ask for the key size in bits */
         privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB,
                                              &pubKey, NULL);
         if (!privKey || !pubKey ||
             !(ss->stepDownKeyPair = ssl3_NewKeyPair(privKey, pubKey))) {
             ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
             rv = SECFailure;
         }
@@ -13595,17 +13550,17 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool
 
     if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
         PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
         return SECFailure;
     }
     if (sid && flushCache) {
         if (ss->sec.uncache)
             ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
-        ssl_FreeSID(sid); /* dec ref count and free if zero. */
+        ssl_FreeSID(sid);         /* dec ref count and free if zero. */
         ss->sec.ci.sid = NULL;
     }
 
     ssl_GetXmitBufLock(ss); /**************************************/
 
     /* start off a new handshake. */
     rv = (ss->sec.isServer) ? ssl3_SendHelloRequest(ss)
                             : ssl3_SendClientHello(ss, PR_FALSE);
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -35,16 +35,25 @@
 
 #ifndef PK11_SETATTRS
 #define PK11_SETATTRS(x, id, v, l) \
     (x)->type = (id);              \
     (x)->pValue = (v);             \
     (x)->ulValueLen = (l);
 #endif
 
+#define SSL_GET_SERVER_PUBLIC_KEY(sock, type)                                          \
+    (ss->serverCerts[type].serverKeyPair ? ss->serverCerts[type].serverKeyPair->pubKey \
+                                         : NULL)
+
+#define SSL_IS_CURVE_NEGOTIATED(curvemsk, curveName) \
+    ((curveName > ec_noName) &&                      \
+     (curveName < ec_pastLastName) &&                \
+     ((1UL << curveName) & curvemsk) != 0)
+
 static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
 
 #define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
 
 /* Table containing OID tags for elliptic curves named in the
  * ECC-TLS IETF draft.
  */
 static const SECOidTag ecName2OIDTag[] = {
@@ -570,49 +579,48 @@ ssl3_GetCurveWithECKeyStrength(PRUint32 
 }
 
 /* find the "weakest link".  Get strength of signature key and of sym key.
  * choose curve for the weakest of those two.
  */
 ECName
 ssl3_GetCurveNameForServerSocket(sslSocket *ss)
 {
+    SECKEYPublicKey *svrPublicKey = NULL;
     ECName ec_curve = ec_noName;
     int signatureKeyStrength = 521;
     int requiredECCbits = ss->sec.secretKeyBits * 2;
 
-    PORT_Assert(ss->sec.serverCert);
-    if (!ss->sec.serverCert ||
-        !ss->sec.serverCert->serverKeyPair ||
-        !ss->sec.serverCert->serverKeyPair->pubKey) {
-        PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
-        return ec_noName;
-    }
-
-    if (ss->sec.serverCert->certType.authType == ssl_auth_ecdsa ||
-        ss->sec.serverCert->certType.authType == ssl_auth_ecdh) {
-        ec_curve = ss->sec.serverCert->certType.u.namedCurve;
-        /* We won't select a certificate unless the named curve has been
-         * negotiated (or supported_curves was absent), double check that. */
-        PORT_Assert(SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                            ec_curve));
-        if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                     ec_curve)) {
+    if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
+        svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh);
+        if (svrPublicKey)
+            ec_curve = ssl3_PubKey2ECName(svrPublicKey);
+        if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) {
+            PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
             return ec_noName;
         }
         signatureKeyStrength = curve2bits[ec_curve];
     } else {
         /* RSA is our signing cert */
-        unsigned int serverKeyStrengthInBits;
-        const sslServerCert *cert = ss->sec.serverCert;
-        PORT_Assert(cert->certType.authType == ssl_auth_rsa_sign ||
-                    cert->certType.authType == ssl_auth_rsa_decrypt);
+        int serverKeyStrengthInBits;
+
+        svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa);
+        if (!svrPublicKey) {
+            PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+            return ec_noName;
+        }
 
-        serverKeyStrengthInBits
-                = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
+        /* currently strength in bytes */
+        serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len;
+        if (svrPublicKey->u.rsa.modulus.data[0] == 0) {
+            serverKeyStrengthInBits--;
+        }
+        /* convert to strength in bits */
+        serverKeyStrengthInBits *= BPB;
+
         signatureKeyStrength =
             SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
     }
     if (requiredECCbits > signatureKeyStrength)
         requiredECCbits = signatureKeyStrength;
 
     return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves,
                                           requiredECCbits);
@@ -891,27 +899,28 @@ no_memory: /* no-memory error has alread
     return SECFailure;
 }
 
 SECStatus
 ssl3_SendECDHServerKeyExchange(
     sslSocket *ss,
     const SSLSignatureAndHashAlg *sigAndHash)
 {
+    const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
     SECStatus rv = SECFailure;
     int length;
     PRBool isTLS, isTLS12;
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SSL3Hashes hashes;
 
     SECKEYPublicKey *ecdhePub;
     SECItem ec_params = { siBuffer, NULL, 0 };
     unsigned char paramBuf[3];
     ECName curve;
-    ssl3KeyPair *keyPair;
+    SSL3KEAType certIndex;
 
     /* Generate ephemeral ECDH key pair and send the public key */
     curve = ssl3_GetCurveNameForServerSocket(ss);
     if (curve == ec_noName) {
         goto loser;
     }
 
     if (ss->opt.reuseServerECDHEKey) {
@@ -951,18 +960,27 @@ ssl3_SendECDHServerKeyExchange(
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    keyPair = ss->sec.serverCert->serverKeyPair;
-    rv = ssl3_SignHashes(&hashes, keyPair->privKey, &signed_hash, isTLS);
+    /* XXX SSLKEAType isn't really a good choice for
+     * indexing certificates but that's all we have
+     * for now.
+     */
+    if (kea_def->kea == kea_ecdhe_rsa)
+        certIndex = kt_rsa;
+    else /* kea_def->kea == kea_ecdhe_ecdsa */
+        certIndex = kt_ecdh;
+
+    rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY,
+                         &signed_hash, isTLS);
     if (rv != SECSuccess) {
         goto loser; /* ssl3_SignHashes has set err. */
     }
     if (signed_hash.data == NULL) {
         /* how can this happen and rv == SECSuccess ?? */
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
@@ -1107,38 +1125,33 @@ ssl3_DisableECCSuites(sslSocket *ss, con
     for (; *suite; ++suite) {
         PORT_CheckSuccess(ssl3_CipherPrefSet(ss, *suite, PR_FALSE));
     }
     return SECSuccess;
 }
 
 /* Look at the server certs configured on this socket, and disable any
  * ECC cipher suites that are not supported by those certs.
- *
- * libssl generally supports multiple ECDH certificates.  However,
- * this function will only filter based on the first of those certificates.
  */
 void
 ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss)
 {
-    sslServerCert *ecdhCert;
+    CERTCertificate *svrCert;
 
-    if (!ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_sign)) {
+    svrCert = ss->serverCerts[kt_rsa].serverCert;
+    if (!svrCert) {
         ssl3_DisableECCSuites(ss, ecdhe_rsa_suites);
     }
 
-    if (!ssl_FindServerCertByAuthType(ss, ssl_auth_ecdsa)) {
+    svrCert = ss->serverCerts[kt_ecdh].serverCert;
+    if (!svrCert) {
+        ssl3_DisableECCSuites(ss, ecdh_suites);
         ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
-    }
-
-    ecdhCert = ssl_FindServerCertByAuthType(ss, ssl_auth_ecdh);
-    if (!ecdhCert || !ecdhCert->serverCert) {
-        ssl3_DisableECCSuites(ss, ecdh_suites);
     } else {
-        SECOidTag sigTag = SECOID_GetAlgorithmTag(&ecdhCert->serverCert->signature);
+        SECOidTag sigTag = SECOID_GetAlgorithmTag(&svrCert->signature);
 
         switch (sigTag) {
             case SEC_OID_PKCS1_RSA_ENCRYPTION:
             case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
             case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
             case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
             case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
             case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
@@ -1385,28 +1398,44 @@ ssl3_HandleSupportedPointFormatsXtn(sslS
         }
     }
 
     /* evil client doesn't support uncompressed */
     ssl3_DisableECCSuites(ss, ecSuites);
     return SECSuccess;
 }
 
+#define SSL3_GET_SERVER_PUBLICKEY(sock, type)                                          \
+    (ss->serverCerts[type].serverKeyPair ? ss->serverCerts[type].serverKeyPair->pubKey \
+                                         : NULL)
+
+/* Extract the TLS curve name for the public key in our EC server cert. */
+ECName
+ssl3_GetSvrCertCurveName(sslSocket *ss)
+{
+    SECKEYPublicKey *srvPublicKey;
+    ECName ec_curve = ec_noName;
+
+    srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
+    if (srvPublicKey) {
+        ec_curve = ssl3_PubKey2ECName(srvPublicKey);
+    }
+    return ec_curve;
+}
+
 /* Ensure that the curve in our server cert is one of the ones supported
  * by the remote client, and disable all ECC cipher suites if not.
  */
 SECStatus
 ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
 {
     PRInt32 list_len;
     PRUint32 peerCurves = 0;
     PRUint32 mutualCurves = 0;
-    PRCList *cursor;
-    PRBool foundECDH = PR_FALSE;
-    PRBool foundECDSA = PR_FALSE;
+    PRUint16 svrCertCurveName;
 
     if (!data->data || data->len < 4) {
         (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
 
     /* get the length of elliptic_curve_list */
     list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
@@ -1428,37 +1457,25 @@ ssl3_HandleSupportedCurvesXtn(sslSocket 
     /* What curves do we support in common? */
     mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
     if (!mutualCurves) {
         /* no mutually supported EC Curves, disable ECC */
         ssl3_DisableECCSuites(ss, ecSuites);
         return SECSuccess;
     }
 
-    /* if we don't have a cert with one of these curves,
+    /* if our ECC cert doesn't use one of these supported curves,
      * disable ECC cipher suites that require an ECC cert.
      */
-    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_ecdh
-            && (mutualCurves & (1U << cert->certType.u.namedCurve))) {
-            foundECDH = PR_TRUE;
-        }
-        if (cert->certType.authType == ssl_auth_ecdsa
-            && (mutualCurves & (1U << cert->certType.u.namedCurve))) {
-            foundECDSA = PR_TRUE;
-        }
+    svrCertCurveName = ssl3_GetSvrCertCurveName(ss);
+    if (svrCertCurveName != ec_noName &&
+        (mutualCurves & (1U << svrCertCurveName)) != 0) {
+        return SECSuccess;
     }
     /* Our EC cert doesn't contain a mutually supported curve.
-     * Disable the affected cipher suites.
+     * Disable all ECC cipher suites that require an EC cert
      */
-    if (!foundECDH) {
-        ssl3_DisableECCSuites(ss, ecdh_suites);
-    }
-    if (!foundECDSA) {
-        ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
-    }
+    ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
+    ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
     return SECSuccess;
 }
 
 #endif /* NSS_DISABLE_ECC */
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -185,30 +185,19 @@ ssl3_SessionTicketShutdown(void *appData
     return SECSuccess;
 }
 
 static PRStatus
 ssl3_GenerateSessionTicketKeysPKCS11(void *data)
 {
     SECStatus rv;
     sslSocket *ss = (sslSocket *)data;
-    sslServerCertType certType;
-    const sslServerCert *sc;
-    SECKEYPrivateKey *svrPrivKey;
-    SECKEYPublicKey *svrPubKey;
-
-    certType.authType = ssl_auth_rsa_decrypt;
-    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;
+    SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY;
+    SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].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,
@@ -332,20 +321,16 @@ static const ssl3HelloExtensionHandler s
     { -1, NULL }
 };
 
 /* Tables of functions to format TLS hello extensions, one function per
  * extension.
  * These static tables are for the formatting of client hello extensions.
  * The server's table of hello senders is dynamic, in the socket struct,
  * and sender functions are registered there.
- * NB: the order of these extensions can have an impact on compatibility. Some
- * servers (e.g. Tomcat) will terminate the connection if the last extension in
- * the client hello is empty (for example, the extended master secret
- * extension, if it were listed last). See bug 1243641.
  */
 static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] =
     {
       { ssl_server_name_xtn, &ssl3_SendServerNameXtn },
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
 #ifndef NSS_DISABLE_ECC
       { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn },
@@ -1035,21 +1020,32 @@ ssl3_ClientHandleStatusRequestXtn(sslSoc
 
 static PRInt32
 ssl3_ServerSendStatusRequestXtn(
     sslSocket *ss,
     PRBool append,
     PRUint32 maxBytes)
 {
     PRInt32 extension_length;
-    const sslServerCert *serverCert = ss->sec.serverCert;
+    SSLKEAType effectiveExchKeyType;
     SECStatus rv;
 
-    if (!serverCert->certStatusArray ||
-        !serverCert->certStatusArray->len) {
+    /* ssl3_SendCertificateStatus (which sents the certificate status data)
+     * uses the exact same logic to select the server certificate
+     * and determine if we have the status for that certificate. */
+
+    if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+        ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
+        effectiveExchKeyType = ssl_kea_rsa;
+    } else {
+        effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+
+    if (!ss->certStatusArray[effectiveExchKeyType] ||
+        !ss->certStatusArray[effectiveExchKeyType]->len) {
         return 0;
     }
 
     extension_length = 2 + 2;
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
     if (append) {
@@ -1134,16 +1130,17 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     NewSessionTicket ticket;
     SECItem plaintext;
     SECItem plaintext_item = { 0, NULL, 0 };
     SECItem ciphertext = { 0, NULL, 0 };
     PRUint32 ciphertext_length;
     PRBool ms_is_wrapped;
     unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH];
     SECItem ms_item = { 0, NULL, 0 };
+    SSL3KEAType effectiveExchKeyType = ssl_kea_null;
     PRUint32 padding_length;
     PRUint32 message_length;
     PRUint32 cert_length = 0;
     PRUint8 length_buf[4];
     PRUint32 now;
     PK11SymKey *aes_key_pkcs11 = NULL;
     PK11SymKey *mac_key_pkcs11 = NULL;
 #ifndef NO_PKCS11_BYPASS
@@ -1208,18 +1205,25 @@ ssl3_SendNewSessionTicket(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));
 
+        if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+            ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
+            effectiveExchKeyType = kt_rsa;
+        } else {
+            effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+        }
+
         rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec,
-                                           ss->ssl3.hs.kea_def->authKeyType);
+                                           effectiveExchKeyType);
         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;
@@ -1236,18 +1240,18 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     }
 
     ciphertext_length =
         sizeof(PRUint16)              /* ticket_version */
         + sizeof(SSL3ProtocolVersion) /* ssl_version */
         + sizeof(ssl3CipherSuite)     /* ciphersuite */
         + 1                           /* compression */
         + 10                          /* cipher spec parameters */
-        + 1                           /* certType arguments */
         + 1                           /* SessionTicket.ms_is_wrapped */
+        + 1                           /* effectiveExchKeyType */
         + 4                           /* msWrapMech */
         + 2                           /* master_secret.length */
         + ms_item.len                 /* master_secret */
         + 1                           /* client_auth_type */
         + cert_length                 /* cert */
         + 1                           /* server name type */
         + srvNameLen                  /* name len + length field */
         + 1                           /* extendedMasterSecretUsed */
@@ -1290,51 +1294,36 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         goto loser;
 
     /* compression */
     rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1);
     if (rv != SECSuccess)
         goto loser;
 
     /* cipher spec parameters */
-    rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1);
+    rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authAlgorithm, 1);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4);
     if (rv != SECSuccess)
         goto loser;
     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 slot */
-    PORT_Assert(ss->sec.serverCert->certType.authType == ss->sec.authType);
-    switch (ss->sec.authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            /* Too many curves and we will need two bytes here. */
-            PORT_Assert(ec_pastLastName < 256);
-            rv = ssl3_AppendNumberToItem(&plaintext,
-                                         ss->sec.serverCert->certType.u.namedCurve, 1);
-            break;
-#endif
-        default:
-            rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
-            break;
-    }
-    if (rv != SECSuccess) goto loser;
-
     /* master_secret */
     rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1);
     if (rv != SECSuccess)
         goto loser;
+    rv = ssl3_AppendNumberToItem(&plaintext, effectiveExchKeyType, 1);
+    if (rv != SECSuccess)
+        goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len);
     if (rv != SECSuccess)
@@ -1415,17 +1404,16 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         rv = AES_Encrypt(aes_ctx, ciphertext.data, &ciphertext.len,
                          ciphertext.len, plaintext_item.data,
                          plaintext_item.len);
         if (rv != SECSuccess)
             goto loser;
     } else
 #endif
     {
-        PORT_Assert(aes_key_pkcs11);
         aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech,
                                                     CKA_ENCRYPT, aes_key_pkcs11, &ivItem);
         if (!aes_ctx_pkcs11)
             goto loser;
 
         rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data,
                            (int *)&ciphertext.len, ciphertext.len,
                            plaintext_item.data, plaintext_item.len);
@@ -1437,18 +1425,16 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
 
     /* Convert ciphertext length to network order. */
     length_buf[0] = (ciphertext.len >> 8) & 0xff;
     length_buf[1] = (ciphertext.len) & 0xff;
 
 /* Compute MAC. */
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
-        PORT_Assert(mac_key);
-
         hmac_ctx = (HMACContext *)hmac_ctx_buf;
         hashObj = HASH_GetRawHashObject(HASH_AlgSHA256);
         if (HMAC_Init(hmac_ctx, hashObj, mac_key,
                       mac_key_length, PR_FALSE) != SECSuccess)
             goto loser;
 
         HMAC_Begin(hmac_ctx);
         HMAC_Update(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN);
@@ -1456,17 +1442,16 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         HMAC_Update(hmac_ctx, (unsigned char *)length_buf, 2);
         HMAC_Update(hmac_ctx, ciphertext.data, ciphertext.len);
         HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length,
                     sizeof(computed_mac));
     } else
 #endif
     {
         SECItem macParam;
-        PORT_Assert(mac_key_pkcs11);
         macParam.data = NULL;
         macParam.len = 0;
         hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech,
                                                      CKA_SIGN, mac_key_pkcs11, &macParam);
         if (!hmac_ctx_pkcs11)
             goto loser;
 
         rv = PK11_DigestBegin(hmac_ctx_pkcs11);
@@ -1797,52 +1782,41 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->compression_method = (SSLCompressionMethod)temp;
 
     /* Read cipher spec parameters. */
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
-    parsed_session_ticket->authType = (SSLAuthType)temp;
+    parsed_session_ticket->authAlgorithm = (SSLSignType)temp;
     temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->authKeyBits = (PRUint32)temp;
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->keaType = (SSLKEAType)temp;
     temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->keaKeyBits = (PRUint32)temp;
 
-    /* Read certificate slot */
-    parsed_session_ticket->certType.authType = parsed_session_ticket->authType;
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
-    if (temp < 0)
-        goto no_ticket;
-    switch (parsed_session_ticket->authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            parsed_session_ticket->certType.u.namedCurve = (ECName)temp;
-            break;
-#endif
-        default:
-            break;
-    }
-
     /* Read wrapped master_secret. */
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
 
+    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    if (temp < 0)
+        goto no_ticket;
+    parsed_session_ticket->exchKeyType = (SSL3KEAType)temp;
+
     temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp;
 
     temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
@@ -1928,41 +1902,39 @@ ssl3_ProcessSessionTicketCommon(sslSocke
             rv = SECFailure;
             goto loser;
         }
 
         /* 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->authAlgorithm = parsed_session_ticket->authAlgorithm;
         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));
-
-        if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
-                             &extension_data) != SECSuccess)
-            goto no_ticket;
-
-        /* Copy master secret. */
+       if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
+                            &extension_data) != SECSuccess)
+           goto no_ticket;
+
+       /* Copy master secret. */
 #ifndef NO_PKCS11_BYPASS
         if (ss->opt.bypassPKCS11 &&
             parsed_session_ticket->ms_is_wrapped)
             goto no_ticket;
 #endif
         if (parsed_session_ticket->ms_length >
             sizeof(sid->u.ssl3.keys.wrapped_master_secret))
             goto no_ticket;
         PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
                     parsed_session_ticket->master_secret,
                     parsed_session_ticket->ms_length);
         sid->u.ssl3.keys.wrapped_master_secret_len =
                 parsed_session_ticket->ms_length;
+        sid->u.ssl3.exchKeyType = parsed_session_ticket->exchKeyType;
         sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech;
         sid->u.ssl3.keys.msIsWrapped =
                 parsed_session_ticket->ms_is_wrapped;
         sid->u.ssl3.masterValid = PR_TRUE;
         sid->u.ssl3.keys.resumable = PR_TRUE;
         sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->extendedMasterSecretUsed;
 
         /* Copy over client cert from session ticket if there is one. */
@@ -2984,17 +2956,27 @@ ssl3_ClientHandleSignedCertTimestampXtn(
 }
 
 static PRInt32
 ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss,
                                       PRBool append,
                                       PRUint32 maxBytes)
 {
     PRInt32 extension_length;
-    const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps;
+    SSLKEAType effectiveExchKeyType;
+    const SECItem *scts;
+
+    if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+        ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
+        effectiveExchKeyType = ssl_kea_rsa;
+    } else {
+        effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+    }
+
+    scts = &ss->signedCertTimestamps[effectiveExchKeyType];
 
     if (!scts->len) {
         /* No timestamps to send */
         return 0;
     }
 
     extension_length = 2 /* extension_type */ +
                        2 /* length(extension_data) */ +
@@ -3253,17 +3235,16 @@ tls13_ServerSendKeyShareXtn(sslSocket *s
 {
     PRUint32 extension_length;
     PRUint32 entry_length;
     SECStatus rv;
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
 #ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
-        case ssl_kea_ecdh_psk:
             PORT_Assert(ss->ephemeralECDHKeyPair);
             break;
 #endif
         default:
             /* got an unknown or unsupported Key Exchange Algorithm.
              * Can't happen because tls13_HandleClientKeyShare
              * enforces that we are ssl_kea_ecdh. */
             PORT_Assert(0);
deleted file mode 100644
--- a/lib/ssl/sslcert.c
+++ /dev/null
@@ -1,877 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * SSL server certificate configuration functions.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "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;
-
-static SECStatus
-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;
-    }
-    setupServerCAListOnce = pristineCallOnce;
-    return SECSuccess;
-}
-
-static PRStatus
-serverCAListSetup(void *arg)
-{
-    CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
-    SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
-    PORT_Assert(SECSuccess == rv);
-    if (SECSuccess == rv) {
-        ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
-        return PR_SUCCESS;
-    }
-    return PR_FAILURE;
-}
-
-sslServerCert *
-ssl_NewServerCert(const sslServerCertType *certType)
-{
-    sslServerCert *sc = PORT_ZNew(sslServerCert);
-    if (!sc) {
-        return NULL;
-    }
-    memcpy(&sc->certType, certType, sizeof(sc->certType));
-    sc->serverCert = NULL;
-    sc->serverCertChain = NULL;
-    sc->certStatusArray = NULL;
-    sc->signedCertTimestamps.len = 0;
-    return sc;
-}
-
-void
-ssl_FreeServerCert(sslServerCert *sc)
-{
-    if (!sc) {
-        return;
-    }
-
-    if (sc->serverCert) {
-        CERT_DestroyCertificate(sc->serverCert);
-    }
-    if (sc->serverCertChain) {
-        CERT_DestroyCertificateList(sc->serverCertChain);
-    }
-    if (sc->serverKeyPair) {
-        ssl3_FreeKeyPair(sc->serverKeyPair);
-    }
-    if (sc->certStatusArray) {
-        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)
-{
-    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) {
-            switch (cert->certType.authType) {
-#ifndef NSS_DISABLE_ECC
-                case ssl_auth_ecdsa:
-                case ssl_auth_ecdh:
-                    /* Note: For deprecated APIs, we need to be able to find and
-                       match a slot with any named curve. */
-                    if (certType->u.namedCurve == ec_noName ||
-                        cert->certType.u.namedCurve == certType->u.namedCurve) {
-                        return cert;
-                    }
-                    break;
-#endif
-                default:
-                    return cert;
-            }
-        }
-    }
-    return NULL;
-}
-
-sslServerCert *
-ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType)
-{
-    sslServerCertType certType;
-    certType.authType = authType;
-    switch (authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            /* Setting the named curve to ec_noName ensures that all EC certificates
-             * are matched when searching for this slot. */
-            certType.u.namedCurve = ec_noName;
-            break;
-#endif
-        default:
-            break;
-    }
-    return ssl_FindServerCert(ss, &certType);
-}
-
-SECStatus
-ssl_OneTimeCertSetup(sslSocket *ss, const sslServerCert *sc)
-{
-    /* Generate a step-down RSA key. */
-    if (sc->certType.authType == ssl_auth_rsa_sign && sc->serverKeyBits > 512 &&
-        !ss->opt.noStepDown && !ss->stepDownKeyPair) {
-        if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
-            return SECFailure;
-        }
-    }
-
-    /* DH parameters are only needed for DHE_RSA_* and DHE_DSS_* suites.  Make
-     * sure that they are properly setup here. */
-    if (sc->certType.authType == ssl_auth_rsa_sign ||
-        sc->certType.authType == ssl_auth_rsa_decrypt ||
-        sc->certType.authType == ssl_auth_dsa) {
-        if (ssl3_SelectDHParams(ss) != SECSuccess) {
-            return SECFailure;
-        }
-    }
-
-    if (PR_SUCCESS != PR_CallOnceWithArg(&setupServerCAListOnce,
-                                         &serverCAListSetup,
-                                         (void *)(ss->dbHandle))) {
-        return SECFailure;
-    }
-    return SECSuccess;
-}
-
-static SECStatus
-ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert,
-                       const CERTCertificateList *certChain)
-{
-    if (sc->serverCert) {
-        CERT_DestroyCertificate(sc->serverCert);
-    }
-    if (sc->serverCertChain) {
-        CERT_DestroyCertificateList(sc->serverCertChain);
-    }
-
-    if (!cert) {
-        sc->serverCert = NULL;
-        sc->serverCertChain = NULL;
-        return SECSuccess;
-    }
-
-    sc->serverCert = CERT_DupCertificate(cert);
-    if (certChain) {
-        sc->serverCertChain = CERT_DupCertList(certChain);
-    } else {
-        sc->serverCertChain =
-            CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
-                                   PR_TRUE);
-    }
-    return sc->serverCertChain ? SECSuccess : SECFailure;
-}
-
-static SECStatus
-ssl_PopulateKeyPair(sslServerCert *sc, ssl3KeyPair *keyPair)
-{
-    /* Copy over the key pair. */
-    if (sc->serverKeyPair) {
-        ssl3_FreeKeyPair(sc->serverKeyPair);
-    }
-    if (keyPair) {
-        /* 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); /* zero bits! */
-            return SECFailure;
-        }
-
-        SECKEY_CacheStaticFlags(keyPair->privKey);
-        sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
-    } else {
-        sc->serverKeyPair = NULL;
-    }
-    return SECSuccess;
-}
-
-static SECStatus
-ssl_PopulateOCSPResponses(sslServerCert *sc,
-                          const SECItemArray *stapledOCSPResponses)
-{
-    if (sc->certStatusArray) {
-        SECITEM_FreeArray(sc->certStatusArray, PR_TRUE);
-    }
-    if (stapledOCSPResponses) {
-        sc->certStatusArray = SECITEM_DupArray(NULL, stapledOCSPResponses);
-        return sc->certStatusArray ? SECSuccess : SECFailure;
-    } else {
-        sc->certStatusArray = NULL;
-    }
-    return SECSuccess;
-}
-
-static SECStatus
-ssl_PopulateSignedCertTimestamps(sslServerCert *sc,
-                                 const SECItem *signedCertTimestamps)
-{
-    if (sc->signedCertTimestamps.len) {
-        SECITEM_FreeItem(&sc->signedCertTimestamps, PR_FALSE);
-    }
-    if (signedCertTimestamps) {
-        return SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
-                                signedCertTimestamps);
-    }
-    return SECSuccess;
-}
-
-static SECStatus
-ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
-               ssl3KeyPair *keyPair, const SSLExtraServerCertData *data)
-{
-    sslServerCert *oldsc;
-    sslServerCert *sc;
-    sslServerCertType certType;
-    SECStatus rv;
-    int error_code = SEC_ERROR_NO_MEMORY;
-
-    PORT_Assert(cert);
-    PORT_Assert(keyPair);
-    PORT_Assert(data);
-    PORT_Assert(data->authType != ssl_auth_null);
-
-    /* Determine which slot this falls into.  A value for SSLAuthType is already
-     * set in |*data|, we just need to work out any extra information. */
-    certType.authType = data->authType;
-    switch (data->authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            certType.u.namedCurve = ssl3_PubKey2ECName(keyPair->pubKey);
-            break;
-#endif
-        default:
-            break;
-    }
-
-    /* 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);
-    if (!sc) {
-        goto loser;
-    }
-
-    rv = ssl_PopulateServerCert(sc, cert, data->certChain);
-    if (rv != SECSuccess) {
-        goto loser;
-    }
-    rv = ssl_PopulateKeyPair(sc, keyPair);
-    if (rv != SECSuccess) {
-        goto loser;
-    }
-    rv = ssl_PopulateOCSPResponses(sc, data->stapledOCSPResponses);
-    if (rv != SECSuccess) {
-        goto loser;
-    }
-    rv = ssl_PopulateSignedCertTimestamps(sc, data->signedCertTimestamps);
-    if (rv != SECSuccess) {
-        goto loser;
-    }
-    PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-
-    /* This one-time setupdepends 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. */
-    PORT_SetError(error_code);
-    return SECFailure;
-}
-
-/* This function examines the type of certificate and its key usage and
- * configures a certificate based on that information.  For RSA certificates
- * only, this can mean that two certificates are configured.
- *
- * If the optional data argument is non-NULL and 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,
-                      ssl3KeyPair *keyPair, const SSLExtraServerCertData *data)
-{
-    SECStatus rv = SECFailure;
-    SSLExtraServerCertData arg = {
-        ssl_auth_null, NULL, NULL, NULL
-    };
-    SECOidTag tag;
-
-    if (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:
-            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                if ((cert->keyUsage & KU_KEY_ENCIPHERMENT) &&
-                    arg.authType == ssl_auth_null) {
-                    /* Two usages is bad form, but there are enough dual-usage RSA
-                     * certs that we can't really break by limiting this to one.
-                     * Configure both slots only if no explicit slot was set. */
-                    arg.authType = ssl_auth_rsa_decrypt;
-                    rv = ssl_ConfigCert(ss, cert, keyPair, &arg);
-                    if (rv != SECSuccess) {
-                        return rv;
-                    }
-                }
-
-                arg.authType = ssl_auth_rsa_sign;
-            } else if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
-                arg.authType = ssl_auth_rsa_decrypt;
-            }
-            break;
-
-        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
-            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_rsa_pss;
-            }
-            break;
-
-        case SEC_OID_ANSIX9_DSA_SIGNATURE:
-            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_dsa;
-            }
-            break;
-
-#ifndef NSS_DISABLE_ECC
-        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
-            /* Yes, this means that you can't do both ECDSA and ECDH, but that is a
-             * bad practice, and ECDH isn't used that much (if at all). */
-            if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-                arg.authType = ssl_auth_ecdsa;
-            } else if (cert->keyUsage & KU_KEY_AGREEMENT) {
-                arg.authType = ssl_auth_ecdh;
-            }
-            break;
-#endif /* NSS_DISABLE_ECC */
-
-        default:
-            return SECFailure;
-    }
-
-    /* Setting data->authType explicitly limits the usage. */
-    if ((!data || data->authType == ssl_auth_null) &&
-        arg.authType != ssl_auth_null) {
-        rv = ssl_ConfigCert(ss, cert, keyPair, &arg);
-    }
-    return rv;
-}
-
-/* This function adopts pubKey and destroys it if things go wrong. */
-static ssl3KeyPair *
-ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey)
-{
-    ssl3KeyPair *keyPair = NULL;
-    SECKEYPrivateKey *privKeyCopy = NULL;
-    PK11SlotInfo *bestSlot;
-
-    if (key->pkcs11Slot) {
-        bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
-        if (bestSlot) {
-            privKeyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
-            PK11_FreeSlot(bestSlot);
-        }
-    }
-    if (!privKeyCopy) {
-        CK_MECHANISM_TYPE keyMech = PK11_MapSignKeyType(key->keyType);
-        /* XXX Maybe should be bestSlotMultiple? */
-        bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */);
-        if (bestSlot) {
-            privKeyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
-            PK11_FreeSlot(bestSlot);
-        }
-    }
-    if (!privKeyCopy) {
-        privKeyCopy = SECKEY_CopyPrivateKey(key);
-    }
-    if (privKeyCopy) {
-        keyPair = ssl3_NewKeyPair(privKeyCopy, pubKey);
-    }
-    if (!keyPair) {
-        if (privKeyCopy) {
-            SECKEY_DestroyPrivateKey(privKeyCopy);
-        }
-        /* We adopted the public key, so we're responsible. */
-        if (pubKey) {
-            SECKEY_DestroyPublicKey(pubKey);
-        }
-    }
-    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.
- */
-SECStatus
-SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
-                     SECKEYPrivateKey *key,
-                     const SSLExtraServerCertData *data, unsigned int data_len)
-{
-    sslSocket *ss;
-    SECKEYPublicKey *pubKey;
-    ssl3KeyPair *keyPair;
-
-    ss = ssl_FindSocket(fd);
-    if (!ss) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-
-    if (!cert || !key) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-
-    if (data_len < sizeof(SSLExtraServerCertData)) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-
-    pubKey = CERT_ExtractPublicKey(cert);
-    if (!pubKey) {
-        return SECFailure;
-    }
-
-    keyPair = ssl_MakeKeyPairForCert(key, pubKey);
-    if (!keyPair) {
-        /* pubKey is adopted by ssl_MakeKeyPairForCert() */
-        return SECFailure;
-    }
-
-    return ssl_ConfigCertByUsage(ss, cert, keyPair, data);
-}
-
-/*******************************************************************/
-/* 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
- * functions create certificate slots based on SSLKEAType values.  Some values
- * of SSLKEAType cause multiple certificates to be configured.
- */
-
-SECStatus
-SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
-                       SECKEYPrivateKey *key, SSLKEAType kea)
-{
-    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)
-{
-    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:
-#ifndef NSS_DISABLE_ECC
-            return tag == SEC_OID_ANSIX962_EC_PUBLIC_KEY;
-#endif /* NSS_DISABLE_ECC */
-        case ssl_auth_null:
-        case ssl_auth_kea:
-        case ssl_auth_rsa_pss: /* not supported with deprecated APIs */
-            return PR_FALSE;
-        default:
-            PORT_Assert(0);
-            return PR_FALSE;
-    }
-}
-
-/* This finds an existing server cert slot and unlinks it. */
-static sslServerCert *
-ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType)
-{
-    sslServerCert *sc;
-    sslServerCertType certType;
-
-    certType.authType = authType;
-    switch (authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            /* Setting the named curve to ec_noName ensures that all EC certificates
-             * are matched when searching for this slot. */
-            certType.u.namedCurve = ec_noName;
-            break;
-#endif
-        default:
-            break;
-    }
-    sc = ssl_FindServerCert(ss, &certType);
-    if (sc) {
-        PR_REMOVE_LINK(&sc->link);
-        return sc;
-    }
-
-    return ssl_NewServerCert(&certType);
-}
-
-static void
-ssl_RemoveCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType)
-{
-    sslServerCert *sc;
-
-    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. */
-    }
-}
-
-static SECStatus
-ssl_AddCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType,
-                            CERTCertificate *cert,
-                            const CERTCertificateList *certChainOpt,
-                            ssl3KeyPair *keyPair)
-{
-    sslServerCert *sc;
-    SECStatus rv;
-
-    if (!ssl_CertSuitableForAuthType(cert, authType)) {
-        return SECFailure;
-    }
-
-    sc = ssl_FindOrMakeCertType(ss, authType);
-    if (!sc) {
-        return SECFailure;
-    }
-    rv = ssl_PopulateKeyPair(sc, keyPair);
-    if (rv != SECSuccess) {
-        return SECFailure;
-    }
-    /* 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 ec_noName, which
-     * makes the slot unusable; this corrects that. */
-    switch (sc->certType.authType) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            sc->certType.u.namedCurve = ssl3_PubKey2ECName(keyPair->pubKey);
-            break;
-#endif
-        default:
-            break;
-    }
-    rv = ssl_PopulateServerCert(sc, cert, certChainOpt);
-    if (rv == SECSuccess) {
-        PR_APPEND_LINK(&sc->link, &ss->serverCerts);
-        rv = ssl_OneTimeCertSetup(ss, sc);
-    } else {
-        ssl_FreeServerCert(sc);
-    }
-    return rv;
-}
-
-static SECStatus
-ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert,
-                  const CERTCertificateList *certChainOpt,
-                  SECKEYPrivateKey *key, SSLKEAType certType)
-{
-    SECKEYPublicKey *pubKey;
-    ssl3KeyPair *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. */
-        return SECFailure;
-    }
-
-    switch (certType) {
-        case ssl_kea_rsa:
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt,
-                                             cert, certChainOpt, keyPair);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign,
-                                               cert, certChainOpt, keyPair);
-
-        case ssl_kea_dh:
-            return ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa,
-                                               cert, certChainOpt, keyPair);
-
-#ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
-            rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdsa,
-                                             cert, certChainOpt, keyPair);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdh,
-                                               cert, certChainOpt, keyPair);
-#endif
-
-        default:
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            return SECFailure;
-    }
-}
-
-/* Public deprecated function */
-SECStatus
-SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
-                                    const CERTCertificateList *certChainOpt,
-                                    SECKEYPrivateKey *key, SSLKEAType certType)
-{
-    sslSocket *ss;
-
-    ss = ssl_FindSocket(fd);
-    if (!ss) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        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;
-
-            case ssl_kea_dh:
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa);
-                break;
-
-#ifndef NSS_DISABLE_ECC
-            case ssl_kea_ecdh:
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdsa);
-                ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh);
-                break;
-#endif
-
-            default:
-                PORT_SetError(SEC_ERROR_INVALID_ARGS);
-                return SECFailure;
-        }
-        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) {
-        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_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
-                            SSLKEAType certType)
-{
-    sslSocket *ss;
-    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);
-
-#ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
-            rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdsa, responses);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh, responses);
-#endif
-
-        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) {
-        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 */
-SECStatus
-SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts,
-                            SSLKEAType certType)
-{
-    sslSocket *ss;
-    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);
-
-#ifndef NSS_DISABLE_ECC
-        case ssl_kea_ecdh:
-            rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh, scts);
-#endif
-
-        default:
-            SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps",
-                     SSL_GETPID(), fd));
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            return SECFailure;
-    }
-}
-
-/* Public deprecated function. */
-SSLKEAType
-NSS_FindCertKEAType(CERTCertificate *cert)
-{
-    int tag;
-
-    if (!cert)
-        return ssl_kea_null;
-
-    tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
-    switch (tag) {
-        case SEC_OID_X500_RSA_ENCRYPTION:
-        case SEC_OID_PKCS1_RSA_ENCRYPTION:
-            return ssl_kea_rsa;
-        case SEC_OID_ANSIX9_DSA_SIGNATURE: /* hah, signature, not a key? */
-        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
-            return ssl_kea_dh;
-#ifndef NSS_DISABLE_ECC
-        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
-            return ssl_kea_ecdh;
-#endif /* NSS_DISABLE_ECC */
-        default:
-            return ssl_kea_null;
-    }
-}
deleted file mode 100644
--- a/lib/ssl/sslcert.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is PRIVATE to SSL.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef __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_ecdh or ssl_auth_ecdsa) is assigned to a slot
-** based on the named curve of the key.
-*/
-typedef struct sslServerCertTypeStr {
-    SSLAuthType authType;
-    union {
-#ifndef NSS_DISABLE_ECC
-        /* for ssl_auth_ecdh and ssl_auth_ecdsa: */
-        ECName namedCurve;
-#endif
-    } u;
-} 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;
-    ssl3KeyPair *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);
-extern sslServerCert *ssl_FindServerCert(const sslSocket *ss,
-                                         const sslServerCertType *slot);
-extern sslServerCert *ssl_FindServerCertByAuthType(const sslSocket *ss,
-                                                   SSLAuthType authType);
-extern void ssl_FreeServerCert(sslServerCert *sc);
-
-#endif /* __sslcert_h_ */
--- a/lib/ssl/sslcon.c
+++ b/lib/ssl/sslcon.c
@@ -1,10 +1,10 @@
 /*
- * Basic SSL handshake functions.
+ * SSL v2 handshake functions, and functions common to SSL2 and SSL3.
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nssrenam.h"
 #include "cert.h"
 #include "secitem.h"
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -31,16 +31,17 @@
 #include "prclist.h"
 
 #include "sslt.h" /* for some formerly private types, now public */
 
 /* to make some of these old enums public without namespace pollution,
 ** it was necessary to prepend ssl_ to the names.
 ** These #defines preserve compatibility with the old code here in libssl.
 */
+typedef SSLKEAType SSL3KEAType;
 typedef SSLMACAlgorithm SSL3MACAlgorithm;
 
 #define calg_null ssl_calg_null
 #define calg_rc4 ssl_calg_rc4
 #define calg_rc2 ssl_calg_rc2
 #define calg_des ssl_calg_des
 #define calg_3des ssl_calg_3des
 #define calg_idea ssl_calg_idea
@@ -146,55 +147,16 @@ typedef enum { SSLAppOpRead = 0,
 
 /* The default value from RFC 4347 is 1s, which is too slow. */
 #define DTLS_RETRANSMIT_INITIAL_MS 50
 /* The maximum time to wait between retransmissions. */
 #define DTLS_RETRANSMIT_MAX_MS 10000
  /* Time to wait in FINISHED state for retransmissions. */
 #define DTLS_RETRANSMIT_FINISHED_MS 30000
 
-#ifndef NSS_DISABLE_ECC
-/* Types and names of elliptic curves used in TLS */
-typedef enum {
-    ec_type_explicitPrime      = 1,
-    ec_type_explicitChar2Curve = 2,
-    ec_type_named
-} ECType;
-
-typedef enum {
-    ec_noName     = 0,
-    ec_sect163k1  = 1,
-    ec_sect163r1  = 2,
-    ec_sect163r2  = 3,
-    ec_sect193r1  = 4,
-    ec_sect193r2  = 5,
-    ec_sect233k1  = 6,
-    ec_sect233r1  = 7,
-    ec_sect239k1  = 8,
-    ec_sect283k1  = 9,
-    ec_sect283r1  = 10,
-    ec_sect409k1  = 11,
-    ec_sect409r1  = 12,
-    ec_sect571k1  = 13,
-    ec_sect571r1  = 14,
-    ec_secp160k1  = 15,
-    ec_secp160r1  = 16,
-    ec_secp160r2  = 17,
-    ec_secp192k1  = 18,
-    ec_secp192r1  = 19,
-    ec_secp224k1  = 20,
-    ec_secp224r1  = 21,
-    ec_secp256k1  = 22,
-    ec_secp256r1  = 23,
-    ec_secp384r1  = 24,
-    ec_secp521r1  = 25,
-    ec_pastLastName
-} ECName;
-#endif /* ndef NSS_DISABLE_ECC */
-
 typedef struct sslBufferStr sslBuffer;
 typedef struct sslConnectInfoStr sslConnectInfo;
 typedef struct sslGatherStr sslGather;
 typedef struct sslSecurityInfoStr sslSecurityInfo;
 typedef struct sslSessionIDStr sslSessionID;
 typedef struct sslSocketStr sslSocket;
 typedef struct sslSocketOpsStr sslSocketOps;
 
@@ -365,16 +327,26 @@ typedef struct sslOptionsStr {
 } sslOptions;
 /* clang-format on */
 
 typedef enum { sslHandshakingUndetermined = 0,
                sslHandshakingAsClient,
                sslHandshakingAsServer
 } sslHandshakingType;
 
+typedef struct sslServerCertsStr {
+    /* Configuration state for server sockets */
+    CERTCertificate *serverCert;
+    CERTCertificateList *serverCertChain;
+    ssl3KeyPair *serverKeyPair;
+    unsigned int serverKeyBits;
+} sslServerCerts;
+
+#define SERVERKEY serverKeyPair->privKey
+
 #define SSL_LOCK_RANK_SPEC 255
 #define SSL_LOCK_RANK_GLOBAL NSS_RWLOCK_RANK_NONE
 
 /* These are the valid values for shutdownHow.
 ** These values are each 1 greater than the NSPR values, and the code
 ** depends on that relation to efficiently convert PR_SHUTDOWN values
 ** into ssl_SHUTDOWN values.  These values use one bit for read, and
 ** another bit for write, and can be used as bitmasks.
@@ -600,18 +572,16 @@ typedef struct {
 } ssl3CipherSpec;
 
 typedef enum { never_cached,
                in_client_cache,
                in_server_cache,
                invalid_cache /* no longer in any cache. */
 } Cached;
 
-#include "sslcert.h"
-
 struct sslSessionIDStr {
     /* The global cache lock must be held when accessing these members when the
      * sid is in any cache.
      */
     sslSessionID *next; /* chain used for client sockets, only */
     Cached cached;
     int references;
     PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */
@@ -619,44 +589,46 @@ struct sslSessionIDStr {
     /* 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;
     CERTCertificate *localCert;
 
     PRIPv6Addr addr;
     PRUint16 port;
 
     SSL3ProtocolVersion version;
 
     PRUint32 creationTime;   /* seconds since Jan 1, 1970 */
     PRUint32 expirationTime; /* seconds since Jan 1, 1970 */
 
-    SSLAuthType authType;
+    SSLSignType authAlgorithm;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
 
     union {
         struct {
             /* values that are copied into the server's on-disk SID cache. */
             PRUint8 sessionIDLength;
             SSL3Opaque sessionID[SSL3_SESSIONID_BYTES];
 
             ssl3CipherSuite cipherSuite;
             SSLCompressionMethod compression;
             int policy;
             ssl3SidKeys keys;
             CK_MECHANISM_TYPE masterWrapMech;
             /* mechanism used to wrap master secret */
+            SSL3KEAType exchKeyType;
+            /* key type used in exchange algorithm,
+             * and to wrap the sym wrapping key. */
 #ifndef NSS_DISABLE_ECC
             PRUint32 negotiatedECCurves;
 #endif /* NSS_DISABLE_ECC */
 
             /* The following values are NOT restored from the server's on-disk
              * session cache, but are restored from the client's cache.
              */
             PK11SymKey *clientWriteKey;
@@ -719,25 +691,19 @@ typedef struct ssl3CipherSuiteDefStr {
     SSL3MACAlgorithm mac_alg;
     SSL3KeyExchangeAlgorithm key_exchange_alg;
 } ssl3CipherSuiteDef;
 
 /*
 ** There are tables of these, all const.
 */
 typedef struct {
-    /* An identifier for this struct. */
     SSL3KeyExchangeAlgorithm kea;
-    /* The type of key exchange used by the cipher suite. */
-    SSLKEAType exchKeyType;
-    /* If the cipher suite uses a signature, the type of signature. */
+    SSL3KEAType exchKeyType;
     SSLSignType signKeyType;
-    /* In most cases, cipher suites depend on their signature type for
-     * authentication, ECDH certificates being the exception. */
-    SSLAuthType authKeyType;
     /* For export cipher suites:
      * is_limited identifies a suite as having a limit on the key size.
      * key_size_limit provides the corresponding limit. */
     PRBool is_limited;
     unsigned int key_size_limit;
     PRBool tls_keygen;
     /* True if the key exchange for the suite is ephemeral.  Or to be more
      * precise: true if the ServerKeyExchange message is always required. */
@@ -1078,35 +1044,36 @@ 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*/
+    SSL3KEAType exchKeyType; /* type of keys used to wrap SymWrapKey*/
     PRInt32 symWrapMechIndex;
     PRUint16 wrappedSymKeyLen;
 } SSLWrappedSymWrappingKey;
 
 typedef struct SessionTicketStr {
     PRUint16 ticket_version;
     SSL3ProtocolVersion ssl_version;
     ssl3CipherSuite cipher_suite;
     SSLCompressionMethod compression_method;
-    SSLAuthType authType;
+    SSLSignType authAlgorithm;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
-    sslServerCertType certType;
     /*
-     * msWrapMech contains a meaningful value only if ms_is_wrapped is true.
+     * exchKeyType and msWrapMech contain meaningful values only if
+     * ms_is_wrapped is true.
      */
     PRUint8 ms_is_wrapped;
+    SSLKEAType exchKeyType; /* XXX(wtc): same as keaType above? */
     CK_MECHANISM_TYPE msWrapMech;
     PRUint16 ms_length;
     SSL3Opaque master_secret[48];
     PRBool extendedMasterSecretUsed;
     ClientIdentity client_identity;
     SECItem peer_cert;
     PRUint32 timestamp;
     SECItem srvName; /* negotiated server name */
@@ -1148,22 +1115,20 @@ struct sslSecurityInfoStr {
 
     int cipherType;
     int keyBits;
     int secretKeyBits;
     CERTCertificate *localCert;
     CERTCertificate *peerCert;
     SECKEYPublicKey *peerKey;
 
-    SSLAuthType authType;
+    SSLSignType authAlgorithm;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
-    /* The selected certificate (for servers only). */
-    const sslServerCert *serverCert;
 
     /*
     ** Procs used for SID cache (nonce) management.
     ** Different implementations exist for clients/servers
     ** The lookup proc is only used for servers.  Baloney!
     */
     sslSessionIDCacheFunc cache;
     sslSessionIDUncacheFunc uncache;
@@ -1278,18 +1243,25 @@ struct sslSocketStr {
 
     /* Gather object used for gathering data */
     sslGather gs; /*recvBufLock*/
 
     sslBuffer saveBuf;    /*xmitBufLock*/
     sslBuffer pendingBuf; /*xmitBufLock*/
 
     /* Configuration state for server sockets */
-    /* One server cert and key for each authentication type. */
-    PRCList /* <sslServerCert> */ serverCerts;
+    /* server cert and key for each KEA type */
+    sslServerCerts serverCerts[kt_kea_size];
+    /* each cert needs its own status */
+    SECItemArray *certStatusArray[kt_kea_size];
+    /* 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[kt_kea_size];
 
     ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED];
     ssl3KeyPair *ephemeralECDHKeyPair; /* for ECDHE-* handshake */
 
     /* SSL3 state info.  Formerly was a pointer */
     ssl3State ssl3;
 
     /*
@@ -1646,31 +1618,61 @@ extern SECStatus ssl3_SelectDHParams(ssl
 
 #ifndef NSS_DISABLE_ECC
 extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
 extern PRBool ssl3_IsECCEnabled(sslSocket *ss);
 extern SECStatus ssl3_DisableECCSuites(sslSocket *ss,
                                        const ssl3CipherSuite *suite);
 extern PRUint32 ssl3_GetSupportedECCurveMask(sslSocket *ss);
 
-#define SSL_IS_CURVE_NEGOTIATED(curvemsk, curveName) \
-    ((curveName > ec_noName) && \
-     (curveName < ec_pastLastName) && \
-     ((1UL << curveName) & curvemsk) != 0)
-
 /* Macro for finding a curve equivalent in strength to RSA key's */
 /* clang-format off */
 #define SSL_RSASTRENGTH_TO_ECSTRENGTH(s)                                       \
         ((s <= 1024) ? 160                                                     \
                      : ((s <= 2048) ? 224                                      \
                                     : ((s <= 3072) ? 256                       \
                                                    : ((s <= 7168) ? 384        \
                                                                   : 521 ) ) ) )
 /* clang-format on */
 
+/* Types and names of elliptic curves used in TLS */
+typedef enum { ec_type_explicitPrime = 1,
+               ec_type_explicitChar2Curve = 2,
+               ec_type_named
+} ECType;
+
+typedef enum { ec_noName = 0,
+               ec_sect163k1 = 1,
+               ec_sect163r1 = 2,
+               ec_sect163r2 = 3,
+               ec_sect193r1 = 4,
+               ec_sect193r2 = 5,
+               ec_sect233k1 = 6,
+               ec_sect233r1 = 7,
+               ec_sect239k1 = 8,
+               ec_sect283k1 = 9,
+               ec_sect283r1 = 10,
+               ec_sect409k1 = 11,
+               ec_sect409r1 = 12,
+               ec_sect571k1 = 13,
+               ec_sect571r1 = 14,
+               ec_secp160k1 = 15,
+               ec_secp160r1 = 16,
+               ec_secp160r2 = 17,
+               ec_secp192k1 = 18,
+               ec_secp192r1 = 19,
+               ec_secp224k1 = 20,
+               ec_secp224r1 = 21,
+               ec_secp256k1 = 22,
+               ec_secp256r1 = 23,
+               ec_secp384r1 = 24,
+               ec_secp521r1 = 25,
+               ec_pastLastName
+} ECName;
+
 extern SECStatus ssl3_ECName2Params(PLArenaPool *arena, ECName curve,
                                     SECKEYECParams *params);
 ECName ssl3_PubKey2ECName(SECKEYPublicKey *pubKey);
 
 ECName ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
 ECName ssl3_GetCurveNameForServerSocket(sslSocket *ss);
 
 #endif /* NSS_DISABLE_ECC */
@@ -1748,19 +1750,19 @@ extern SECStatus ssl3_CheckSignatureAndH
 extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm(
     sslSocket *ss, SSL3Opaque **b, PRUint32 *length,
     SSLSignatureAndHashAlg *out);
 extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key,
                                  SECItem *buf, PRBool isTLS);
 extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
                                          CERTCertificate *cert, SECItem *buf, PRBool isTLS,
                                          void *pwArg);
-extern SECStatus ssl3_CacheWrappedMasterSecret(
-    sslSocket *ss, sslSessionID *sid,
-    ssl3CipherSpec *spec, SSLAuthType authType);
+extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss,
+                                               sslSessionID *sid, ssl3CipherSpec *spec,
+                                               SSL3KEAType effectiveExchKeyType);
 
 /* Functions that handle ClientHello and ServerHello extensions. */
 extern SECStatus ssl3_HandleServerNameXtn(sslSocket *ss,
                                           PRUint16 ex_type, SECItem *data);
 extern SECStatus ssl3_HandleSupportedCurvesXtn(sslSocket *ss,
                                                PRUint16 ex_type, SECItem *data);
 extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss,
                                                      PRUint16 ex_type, SECItem *data);
@@ -1777,16 +1779,24 @@ extern PRInt32 ssl3_SendSessionTicketXtn
                                          PRUint32 maxBytes);
 
 /* ClientHello and ServerHello extension senders.
  * The code is in ssl3ext.c.
  */
 extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
                                       PRUint32 maxBytes);
 
+/* Assigns new cert, cert chain and keys to ss->serverCerts
+ * struct. If certChain is NULL, tries to find one. Aborts if
+ * fails to do so. If cert and keyPair are NULL - unconfigures
+ * sslSocket of kea type.*/
+extern SECStatus ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+                                        const CERTCertificateList *certChain,
+                                        ssl3KeyPair *keyPair, SSLKEAType kea);
+
 #ifndef NSS_DISABLE_ECC
 extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss,
                                            PRBool append, PRUint32 maxBytes);
 extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss,
                                                  PRBool append, PRUint32 maxBytes);
 #endif
 
 /* call the registered extension handlers. */
@@ -1804,17 +1814,17 @@ extern PRBool ssl_GetSessionTicketKeys(u
 extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
                                              SECKEYPublicKey *svrPubKey, void *pwArg,
                                              unsigned char *keyName, PK11SymKey **aesKey,
                                              PK11SymKey **macKey);
 extern SECStatus ssl3_SessionTicketShutdown(void *appData, void *nssData);
 
 /* 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 (0x0102)
+#define TLS_EX_SESS_TICKET_VERSION (0x0101)
 
 extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
                                             unsigned int length);
 
 /* Construct a new NSPR socket for the app to use */
 extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
 extern void ssl_FreePRSocket(PRFileDesc *fd);
 
@@ -1829,17 +1839,18 @@ extern ssl3KeyPair *ssl3_NewKeyPair(SECK
 /* get a new reference (bump ref count) to an ssl3KeyPair. */
 extern ssl3KeyPair *ssl3_GetKeyPairRef(ssl3KeyPair *keyPair);
 
 /* Decrement keypair's ref count and free if zero. */
 extern void ssl3_FreeKeyPair(ssl3KeyPair *keyPair);
 
 /* calls for accessing wrapping keys across processes. */
 extern PRBool
-ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType,
+ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
+                   SSL3KEAType exchKeyType,
                    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.
@@ -1933,26 +1944,26 @@ SECStatus ssl3_CreateECDHEphemeralKeyPai
                                           ssl3KeyPair **keyPair);
 PK11SymKey *tls13_ComputeECDHSharedKey(sslSocket *ss,
                                        SECKEYPrivateKey *myPrivKey,
                                        SECKEYPublicKey *peerKey);
 #endif
 SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
 PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
                                 PK11SlotInfo *masterSecretSlot,
-                                const sslServerCert *serverCert,
+                                SSL3KEAType exchKeyType,
                                 CK_MECHANISM_TYPE masterWrapMech,
                                 void *pwArg);
 PRInt32 tls13_ServerSendPreSharedKeyXtn(sslSocket * ss,
                                         PRBool      append,
                                         PRUint32    maxBytes);
 PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type);
-SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
+SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
+                               SSL3KEAType effectiveExchKeyType);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
-SECStatus ssl3_SelectServerCert(sslSocket *ss);
 
 /* Pull in TLS 1.3 functions */
 #include "tls13con.h"
 
 /********************** misc calls *********************/
 
 #ifdef DEBUG
 extern void ssl3_CheckCipherSuiteOrderConsistency();
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -129,167 +129,145 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc
      */
     inf.cipherSuite = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ?
             ss->ssl3.hs.origCipherSuite : ss->ssl3.hs.cipher_suite;
 
     memcpy(info, &inf, inf.length);
     return SECSuccess;
 }
 
-/* name */
-#define CS_(x) x, #x
-#define CS(x) CS_(TLS_##x)
+#define CS(x) x, #x
+#define CK(x) x | 0xff00, #x
 
-/* legacy values for authAlgorithm */
 #define S_DSA "DSA", ssl_auth_dsa
-/* S_RSA is incorrect for signature-based suites */
-/* ECDH suites incorrectly report S_RSA or S_ECDSA */
-#define S_RSA "RSA", ssl_auth_rsa_decrypt
+#define S_RSA "RSA", ssl_auth_rsa
+#define S_KEA "KEA", ssl_auth_kea
 #define S_ECDSA "ECDSA", ssl_auth_ecdsa
 #define S_PSK   "PSK", ssl_auth_psk
 
-/* real authentication algorithm */
-#define A_DSA ssl_auth_dsa
-#define A_RSAD ssl_auth_rsa_decrypt
-#define A_RSAS ssl_auth_rsa_sign
-#define A_ECDSA ssl_auth_ecdsa
-#define A_ECDH ssl_auth_ecdh
-/* Report ssl_auth_null for export suites that can't decide between
- * ssl_auth_rsa_sign and ssl_auth_rsa_decrypt. */
-#define A_EXP ssl_auth_null
+#define K_DHE "DHE", kt_dh
+#define K_RSA "RSA", kt_rsa
+#define K_KEA "KEA", kt_kea
+#define K_ECDH "ECDH", kt_ecdh
+#define K_ECDHE "ECDHE", kt_ecdh
+#define K_ECDHE_PSK "ECDHE-PSK", kt_ecdh
 
-/* key exchange */
-#define K_DHE "DHE", ssl_kea_dh
-#define K_RSA "RSA", ssl_kea_rsa
-#define K_KEA "KEA", ssl_kea_kea
-#define K_ECDH "ECDH", ssl_kea_ecdh
-#define K_ECDHE "ECDHE", ssl_kea_ecdh
-#define K_ECDHE_PSK "ECDHE-PSK", ssl_kea_ecdh_psk
-
-/* record protection cipher */
 #define C_SEED "SEED", calg_seed
 #define C_CAMELLIA "CAMELLIA", calg_camellia
 #define C_AES "AES", calg_aes
 #define C_RC4 "RC4", calg_rc4
 #define C_RC2 "RC2", calg_rc2
 #define C_DES "DES", calg_des
 #define C_3DES "3DES", calg_3des
 #define C_NULL "NULL", calg_null
 #define C_SJ "SKIPJACK", calg_sj
 #define C_AESGCM "AES-GCM", calg_aes_gcm
 #define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20
 
-/* "block cipher" sizes */
 #define B_256 256, 256, 256
 #define B_128 128, 128, 128
 #define B_3DES 192, 156, 112
 #define B_SJ 96, 80, 80
 #define B_DES 64, 56, 56
 #define B_56 128, 56, 56
 #define B_40 128, 40, 40
 #define B_0 0, 0, 0
 
-/* "mac algorithm" and size */
 #define M_AEAD_128 "AEAD", ssl_mac_aead, 128
 #define M_SHA256 "SHA256", ssl_hmac_sha256, 256
 #define M_SHA "SHA1", ssl_mac_sha, 160
 #define M_MD5 "MD5", ssl_mac_md5, 128
 #define M_NULL "NULL", ssl_mac_null, 0
 
-/* flags */
-#define F_FIPS_STD 1, 0, 0, 0
-#define F_FIPS_NSTD 1, 0, 1, 0
-#define F_NFIPS_STD 0, 0, 0, 0
-#define F_NFIPS_NSTD 0, 0, 1, 0 /* i.e., trash */
-#define F_EXPORT 0, 1, 0, 0 /* i.e., trash */
-
+/* clang-format off */
 static const SSLCipherSuiteInfo suiteInfo[] = {
     /* <------ Cipher suite --------------------> <auth> <KEA>  <bulk cipher> <MAC> <FIPS> */
-    { 0, CS(RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAD },
-    { 0, CS(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
+    {0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256),       S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 
-    { 0, CS(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_DSA },
-    { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_DSA },
-    { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_DSA },
-    { 0, CS(RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAD },
+    {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA),      S_RSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA),      S_DSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256),   S_DSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA),     S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA256),       S_RSA, K_RSA, C_AES, B_256, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA),          S_RSA, K_RSA, C_AES, B_256, M_SHA, 1, 0, 0 },
 
-    { 0, CS(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_DSA },
-    { 0, CS(DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_DSA },
-    { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_DSA },
-    { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_DSA },
-    { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_DSA },
-    { 0, CS(RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED, B_128, M_SHA, F_FIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, F_NFIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAD },
-    { 0, CS(RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAD },
+    {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA),          S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256),   S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA),      S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256),   S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA),      S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256),   S_DSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_RSA_WITH_SEED_CBC_SHA),             S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA),     S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_RSA_WITH_RC4_128_SHA),              S_RSA, K_RSA, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_RSA_WITH_RC4_128_MD5),              S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0 },
+    {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA256),       S_RSA, K_RSA, C_AES, B_128, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA),          S_RSA, K_RSA, C_AES, B_128, M_SHA, 1, 0, 0 },
 
-    { 0, CS(DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_DSA },
-    { 0, CS_(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_NSTD, A_RSAD },
-    { 0, CS(RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAD },
+    {0,CS(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA),     S_RSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA),     S_DSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0 },
+    {0,CS(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA),    S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 1 },
+    {0,CS(TLS_RSA_WITH_3DES_EDE_CBC_SHA),         S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 0 },
 
-    { 0, CS(DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAS },
-    { 0, CS(DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_DSA },
-    { 0, CS_(SSL_RSA_FIPS_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_NSTD, A_RSAD },
-    { 0, CS(RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAD },
+    {0,CS(TLS_DHE_RSA_WITH_DES_CBC_SHA),          S_RSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_DHE_DSS_WITH_DES_CBC_SHA),          S_DSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0 },
+    {0,CS(SSL_RSA_FIPS_WITH_DES_CBC_SHA),         S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 1 },
+    {0,CS(TLS_RSA_WITH_DES_CBC_SHA),              S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 0 },
 
-    { 0, CS(RSA_EXPORT1024_WITH_RC4_56_SHA), S_RSA, K_RSA, C_RC4, B_56, M_SHA, F_EXPORT, A_EXP },
-    { 0, CS(RSA_EXPORT1024_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_EXPORT, A_EXP },
-    { 0, CS(RSA_EXPORT_WITH_RC4_40_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, F_EXPORT, A_EXP },
-    { 0, CS(RSA_EXPORT_WITH_RC2_CBC_40_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, F_EXPORT, A_EXP },
-    { 0, CS(RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL, B_0, M_SHA256, F_EXPORT, A_RSAD },
-    { 0, CS(RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL, B_0, M_SHA, F_EXPORT, A_RSAD },
-    { 0, CS(RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL, B_0, M_MD5, F_EXPORT, A_RSAD },
+    {0,CS(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA),    S_RSA, K_RSA, C_RC4, B_56,  M_SHA, 0, 1, 0 },
+    {0,CS(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA),   S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 1, 0 },
+    {0,CS(TLS_RSA_EXPORT_WITH_RC4_40_MD5),        S_RSA, K_RSA, C_RC4, B_40,  M_MD5, 0, 1, 0 },
+    {0,CS(TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5),    S_RSA, K_RSA, C_RC2, B_40,  M_MD5, 0, 1, 0 },
+    {0,CS(TLS_RSA_WITH_NULL_SHA256),              S_RSA, K_RSA, C_NULL,B_0,   M_SHA256, 0, 1, 0 },
+    {0,CS(TLS_RSA_WITH_NULL_SHA),                 S_RSA, K_RSA, C_NULL,B_0,   M_SHA, 0, 1, 0 },
+    {0,CS(TLS_RSA_WITH_NULL_MD5),                 S_RSA, K_RSA, C_NULL,B_0,   M_MD5, 0, 1, 0 },
 
 #ifndef NSS_DISABLE_ECC
     /* ECC cipher suites */
-    { 0, CS(ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_PSK_WITH_AES_128_GCM_SHA256), S_PSK, K_ECDHE_PSK, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256), S_PSK,   K_ECDHE_PSK, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
 
-    { 0, CS(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH },
-    { 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH },
-    { 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH },
-    { 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH },
-    { 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH },
+    {0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA),          S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA),       S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA),  S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA),   S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA),   S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 },
 
-    { 0, CS(ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDSA },
-    { 0, CS(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ECDSA },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA),         S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),      S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 
-    { 0, CS(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH },
-    { 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH },
-    { 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH },
-    { 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH },
-    { 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH },
+    {0,CS(TLS_ECDH_RSA_WITH_NULL_SHA),            S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA),         S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA),    S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 },
 
-    { 0, CS(ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
-    { 0, CS(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
+    {0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA),           S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA),        S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),   S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+    {0,CS(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 #endif /* NSS_DISABLE_ECC */
 };
+/* clang-format on */
 
 #define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0]))
 
 SECStatus
 SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,
                        SSLCipherSuiteInfo *info, PRUintn len)
 {
     unsigned int i;
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -618,16 +618,270 @@ DoRecv(sslSocket *ss, unsigned char *out
 done:
     ssl_ReleaseRecvBufLock(ss);
     ssl_Release1stHandshakeLock(ss);
     return rv;
 }
 
 /************************************************************************/
 
+/*
+** Return SSLKEAType derived from cert's Public Key algorithm info.
+*/
+SSLKEAType
+NSS_FindCertKEAType(CERTCertificate *cert)
+{
+    SSLKEAType keaType = kt_null;
+    int tag;
+
+    if (!cert)
+        goto loser;
+
+    tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+
+    switch (tag) {
+        case SEC_OID_X500_RSA_ENCRYPTION:
+        case SEC_OID_PKCS1_RSA_ENCRYPTION:
+            keaType = kt_rsa;
+            break;
+        case SEC_OID_ANSIX9_DSA_SIGNATURE: /* hah, signature, not a key? */
+        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
+            keaType = kt_dh;
+            break;
+#ifndef NSS_DISABLE_ECC
+        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+            keaType = kt_ecdh;
+            break;
+#endif /* NSS_DISABLE_ECC */
+        default:
+            keaType = kt_null;
+    }
+
+loser:
+
+    return keaType;
+}
+
+static const PRCallOnceType pristineCallOnce;
+static PRCallOnceType setupServerCAListOnce;
+
+static SECStatus
+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;
+    }
+    setupServerCAListOnce = pristineCallOnce;
+    return SECSuccess;
+}
+
+static PRStatus
+serverCAListSetup(void *arg)
+{
+    CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
+    SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
+    PORT_Assert(SECSuccess == rv);
+    if (SECSuccess == rv) {
+        ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
+        return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+}
+
+SECStatus
+ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+                       const CERTCertificateList *certChain,
+                       ssl3KeyPair *keyPair, SSLKEAType kea)
+{
+    CERTCertificateList *localCertChain = NULL;
+    sslServerCerts *sc = ss->serverCerts + kea;
+
+    /* load the server certificate */
+    if (sc->serverCert != NULL) {
+        CERT_DestroyCertificate(sc->serverCert);
+        sc->serverCert = NULL;
+        sc->serverKeyBits = 0;
+    }
+    /* load the server cert chain */
+    if (sc->serverCertChain != NULL) {
+        CERT_DestroyCertificateList(sc->serverCertChain);
+        sc->serverCertChain = NULL;
+    }
+    if (cert) {
+        sc->serverCert = CERT_DupCertificate(cert);
+        /* get the size of the cert's public key, and remember it */
+        sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
+        if (!certChain) {
+            localCertChain =
+                CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
+                                       PR_TRUE);
+            if (!localCertChain)
+                goto loser;
+        }
+        sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) :
+                                          localCertChain;
+        if (!sc->serverCertChain) {
+            goto loser;
+        }
+        localCertChain = NULL; /* consumed */
+    }
+
+    /* get keyPair */
+    if (sc->serverKeyPair != NULL) {
+        ssl3_FreeKeyPair(sc->serverKeyPair);
+        sc->serverKeyPair = NULL;
+    }
+    if (keyPair) {
+        SECKEY_CacheStaticFlags(keyPair->privKey);
+        sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
+    }
+    if (kea == kt_rsa && cert && sc->serverKeyBits > 512 &&
+        !ss->opt.noStepDown && !ss->stepDownKeyPair) {
+        if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
+            goto loser;
+        }
+    }
+    if (kea == ssl_kea_dh || kea == ssl_kea_rsa) {
+        if (ssl3_SelectDHParams(ss) != SECSuccess) {
+            goto loser;
+        }
+    }
+    return SECSuccess;
+
+loser:
+    if (localCertChain) {
+        CERT_DestroyCertificateList(localCertChain);
+    }
+    if (sc->serverCert != NULL) {
+        CERT_DestroyCertificate(sc->serverCert);
+        sc->serverCert = NULL;
+    }
+    if (sc->serverCertChain != NULL) {
+        CERT_DestroyCertificateList(sc->serverCertChain);
+        sc->serverCertChain = NULL;
+    }
+    if (sc->serverKeyPair != NULL) {
+        ssl3_FreeKeyPair(sc->serverKeyPair);
+        sc->serverKeyPair = NULL;
+    }
+    return SECFailure;
+}
+
+/* XXX need to protect the data that gets changed here.!! */
+
+SECStatus
+SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
+                       SECKEYPrivateKey *key, SSL3KEAType kea)
+{
+
+    return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea);
+}
+
+SECStatus
+SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
+                                    const CERTCertificateList *certChainOpt,
+                                    SECKEYPrivateKey *key, SSL3KEAType kea)
+{
+    sslSocket *ss;
+    SECKEYPublicKey *pubKey = NULL;
+    ssl3KeyPair *keyPair = NULL;
+    SECStatus rv = SECFailure;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        return SECFailure;
+    }
+
+    /* Both key and cert must have a value or be NULL */
+    /* Passing a value of NULL will turn off key exchange algorithms that were
+     * previously turned on */
+    if (!cert != !key) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    /* make sure the key exchange is recognized */
+    if ((kea >= kt_kea_size) || (kea < kt_null)) {
+        PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+        return SECFailure;
+    }
+
+    if (kea != NSS_FindCertKEAType(cert)) {
+        PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);
+        return SECFailure;
+    }
+
+    if (cert) {
+        /* get the size of the cert's public key, and remember it */
+        pubKey = CERT_ExtractPublicKey(cert);
+        if (!pubKey)
+            return SECFailure;
+    }
+
+    if (key) {
+        SECKEYPrivateKey *keyCopy = NULL;
+        CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM;
+
+        if (key->pkcs11Slot) {
+            PK11SlotInfo *bestSlot;
+            bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
+            if (bestSlot) {
+                keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
+                PK11_FreeSlot(bestSlot);
+            }
+        }
+        if (keyCopy == NULL)
+            keyMech = PK11_MapSignKeyType(key->keyType);
+        if (keyMech != CKM_INVALID_MECHANISM) {
+            PK11SlotInfo *bestSlot;
+            /* XXX Maybe should be bestSlotMultiple? */
+            bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */);
+            if (bestSlot) {
+                keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
+                PK11_FreeSlot(bestSlot);
+            }
+        }
+        if (keyCopy == NULL)
+            keyCopy = SECKEY_CopyPrivateKey(key);
+        if (keyCopy == NULL)
+            goto loser;
+        keyPair = ssl3_NewKeyPair(keyCopy, pubKey);
+        if (keyPair == NULL) {
+            SECKEY_DestroyPrivateKey(keyCopy);
+            goto loser;
+        }
+        pubKey = NULL; /* adopted by serverKeyPair */
+    }
+    if (ssl_ConfigSecureServer(ss, cert, certChainOpt,
+                               keyPair, kea) == SECFailure) {
+        goto loser;
+    }
+
+    /* Only do this once because it's global. */
+    if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce,
+                                         &serverCAListSetup,
+                                         (void *)(ss->dbHandle))) {
+        rv = SECSuccess;
+    }
+
+loser:
+    if (keyPair) {
+        ssl3_FreeKeyPair(keyPair);
+    }
+    if (pubKey) {
+        SECKEY_DestroyPublicKey(pubKey);
+        pubKey = NULL;
+    }
+    return rv;
+}
+
+/************************************************************************/
+
 SECStatus
 ssl_CreateSecurityInfo(sslSocket *ss)
 {
     SECStatus status;
 
     ssl_GetXmitBufLock(ss);
     status = sslBuffer_Grow(&ss->sec.writeBuf, 4096);
     ssl_ReleaseXmitBufLock(ss);
--- a/lib/ssl/sslsnce.c
+++ b/lib/ssl/sslsnce.c
@@ -28,17 +28,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[kt_kea_size][SSL_NUM_WRAP_MECHS];
  *     PRUint8                  keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
  *     encKeyCacheEntry         ticketEncKey; // Wrapped in non-bypass mode
  *     encKeyCacheEntry         ticketMacKey; // Wrapped in non-bypass mode
  *     PRBool                   ticketKeysValid;
  *     sidCacheLock             srvNameCacheLock;
  *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
  * } cacheMemCacheData;
  */
@@ -93,35 +93,35 @@ struct sidCacheEntryStr {
     /* 16 */ PRIPv6Addr addr; /* client's IP address */
     /*  4 */ PRUint32 creationTime;
     /*  4 */ PRUint32 lastAccessTime;
     /*  4 */ PRUint32 expirationTime;
     /*  2 */ PRUint16 version;
     /*  1 */ PRUint8 valid;
     /*  1 */ PRUint8 sessionIDLength;
     /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES];
-    /*  2 */ PRUint16 authType;
+    /*  2 */ PRUint16 authAlgorithm;
     /*  2 */ PRUint16 authKeyBits;
     /*  2 */ PRUint16 keaType;
     /*  2 */ PRUint16 keaKeyBits;
     /* 72  - common header total */
 
     union {
 struct {
     /*  2 */ ssl3CipherSuite cipherSuite;
     /*  2 */ PRUint16 compression; /* SSLCompressionMethod */
 
     /* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
 
     /*  4 */ PRUint32 masterWrapMech;
+    /*  4 */ SSL3KEAType exchKeyType;
     /*  4 */ PRInt32 certIndex;
     /*  4 */ PRInt32 srvNameIndex;
     /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
-    /*  2 */ PRUint16 certTypeArgs;
-/*104 */} ssl3;
+/*108 */} ssl3;
 
 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */
 struct {
     /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
 } forceSize;
     } u;
 };
 typedef struct sidCacheEntryStr sidCacheEntry;
@@ -431,42 +431,31 @@ static void
 ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
 {
     to->valid = 1;
     to->version = from->version;
     to->addr = from->addr;
     to->creationTime = from->creationTime;
     to->lastAccessTime = from->lastAccessTime;
     to->expirationTime = from->expirationTime;
-    to->authType = from->authType;
+    to->authAlgorithm = from->authAlgorithm;
     to->authKeyBits = from->authKeyBits;
     to->keaType = from->keaType;
     to->keaKeyBits = from->keaKeyBits;
 
     to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
     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->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
     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) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            to->u.ssl3.certTypeArgs = (PRUint16)from->certType.u.namedCurve;
-            break;
-#endif
-        default:
-            break;
-    }
-
 
     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));
 }
 
@@ -487,16 +476,17 @@ ConvertToSID(sidCacheEntry *from,
         return 0;
     }
 
     to->u.ssl3.sessionIDLength = from->sessionIDLength;
     to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
     to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
     to->u.ssl3.keys = from->u.ssl3.keys;
     to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
+    to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
     if (from->u.ssl3.srvNameIndex != -1 && psnce) {
         SECItem name;
         SECStatus rv;
         name.type = psnce->type;
         name.len = psnce->nameLen;
         name.data = psnce->name;
         rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
         if (rv != SECSuccess) {
@@ -531,36 +521,25 @@ 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) {
-#ifndef NSS_DISABLE_ECC
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh:
-            to->certType.u.namedCurve = (ECName)from->u.ssl3.certTypeArgs;
-            break;
-#endif
-        default:
-            break;
-    }
 
     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;
     to->references = 1;
-    to->authType = from->authType;
+    to->authAlgorithm = from->authAlgorithm;
     to->authKeyBits = from->authKeyBits;
     to->keaType = from->keaType;
     to->keaKeyBits = from->keaKeyBits;
 
     return to;
 
 loser:
     if (to) {
@@ -988,17 +967,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 = kt_kea_size * 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);
@@ -1620,60 +1599,60 @@ StopLockPoller(cacheDesc *cache)
  *  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.
 */
 static PRBool
 getSvrWrappingKey(PRInt32 symWrapMechIndex,
-                  SSLAuthType authType,
+                  SSL3KEAType exchKeyType,
                   SSLWrappedSymWrappingKey *wswk,
                   cacheDesc *cache,
                   PRUint32 lockTime)
 {
-    PRUint32 ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+    PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
     SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx;
     PRUint32 now = 0;
     PRBool rv = PR_FALSE;
 
     if (!cache->cacheMem) { /* cache is uninitialized */
         PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
         return rv;
     }
     if (!lockTime) {
         lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
         if (!lockTime) {
             return rv;
         }
     }
-    if (pwswk->authType == authType &&
+    if (pwswk->exchKeyType == exchKeyType &&
         pwswk->symWrapMechIndex == symWrapMechIndex &&
         pwswk->wrappedSymKeyLen != 0) {
         *wswk = *pwswk;
         rv = PR_TRUE;
     }
     if (now) {
         UnlockSidCacheLock(cache->keyCacheLock);
     }
     return rv;
 }
 
 PRBool
 ssl_GetWrappingKey(PRInt32 symWrapMechIndex,
-                   SSLAuthType authType,
+                   SSL3KEAType exchKeyType,
                    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 &&
+    PORT_Assert((unsigned)exchKeyType < kt_kea_size);
+    PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
+    if ((unsigned)exchKeyType < kt_kea_size &&
         (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
-        rv = getSvrWrappingKey(symWrapMechIndex, authType, wswk,
+        rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
                                &globalCache, 0);
     } else {
         rv = PR_FALSE;
     }
 
     return rv;
 }
 
@@ -1944,42 +1923,42 @@ loser:
  * This is all done while holding the locks/mutexes necessary to make
  * the operation atomic.
  */
 PRBool
 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
 {
     cacheDesc *cache = &globalCache;
     PRBool rv = PR_FALSE;
-    SSLAuthType authType = wswk->authType;
+    SSL3KEAType exchKeyType = wswk->exchKeyType;
     /* type of keys used to wrap SymWrapKey*/
     PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
     PRUint32 ndx;
     PRUint32 now = 0;
     SSLWrappedSymWrappingKey myWswk;
 
     if (!cache->cacheMem) { /* cache is uninitialized */
         PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
         return 0;
     }
 
-    PORT_Assert((unsigned)authType < ssl_auth_size);
-    if ((unsigned)authType >= ssl_auth_size)
+    PORT_Assert((unsigned)exchKeyType < kt_kea_size);
+    if ((unsigned)exchKeyType >= kt_kea_size)
         return 0;
 
     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 = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
     PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
 
     now = LockSidCacheLock(cache->keyCacheLock, now);
     if (now) {
-        rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->authType,
+        rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
                                &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;
         }
@@ -2019,17 +1998,17 @@ 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,
+                   SSL3KEAType exchKeyType,
                    SSLWrappedSymWrappingKey *wswk)
 {
     PRBool rv = PR_FALSE;
     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
     return rv;
 }
 
 /* This is a kind of test-and-set.  The caller passes in the new value it wants
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -207,17 +207,16 @@ ssl_FindSocket(PRFileDesc *fd)
     return ss;
 }
 
 static sslSocket *
 ssl_DupSocket(sslSocket *os)
 {
     sslSocket *ss;
     SECStatus rv;
-    sslServerCert *sc = NULL;
 
     ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant);
     if (ss) {
         ss->opt = os->opt;
         ss->opt.useSocks = PR_FALSE;
         ss->vrange = os->vrange;
 
         ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
@@ -250,52 +249,43 @@ ssl_DupSocket(sslSocket *os)
             }
             PORT_Memcpy(ss->ssl3.dheGroups, os->ssl3.dheGroups,
                         sizeof(SSLDHEGroupType) * os->ssl3.numDHEGroups);
         } else {
             ss->ssl3.dheGroups = NULL;
         }
 
         if (ss->opt.useSecurity) {
-            PRCList *cursor;
-            for (cursor = PR_NEXT_LINK(&os->serverCerts);
-                 cursor != &os->serverCerts;
-                 cursor = PR_NEXT_LINK(cursor)) {
-                sslServerCert *oc = (sslServerCert*)cursor;
-                sc = ssl_NewServerCert(&oc->certType);
-
+            /* This int should be SSLKEAType, but CC on Irix complains,
+             * during the for loop.
+             */
+            int i;
+            sslServerCerts *oc = os->serverCerts;
+            sslServerCerts *sc = ss->serverCerts;
+
+            for (i = kt_null; i < kt_kea_size; i++, oc++, sc++) {
                 if (oc->serverCert && oc->serverCertChain) {
                     sc->serverCert = CERT_DupCertificate(oc->serverCert);
                     sc->serverCertChain = CERT_DupCertList(oc->serverCertChain);
                     if (!sc->serverCertChain)
                         goto loser;
                 } else {
                     sc->serverCert = NULL;
                     sc->serverCertChain = NULL;
                 }
-                sc->serverKeyPair = oc->serverKeyPair ?
-                        ssl3_GetKeyPairRef(oc->serverKeyPair) : NULL;
+                sc->serverKeyPair = oc->serverKeyPair ? ssl3_GetKeyPairRef(oc->serverKeyPair)
+                                                      : NULL;
                 if (oc->serverKeyPair && !sc->serverKeyPair)
                     goto loser;
                 sc->serverKeyBits = oc->serverKeyBits;
-                sc->certStatusArray = !oc->certStatusArray ? NULL :
-                        SECITEM_DupArray(NULL, oc->certStatusArray);
-                if (SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
-                                     &oc->signedCertTimestamps) != SECSuccess)
-                    goto loser;
-                PR_APPEND_LINK(&sc->link, &ss->serverCerts);
+                ss->certStatusArray[i] = !os->certStatusArray[i] ? NULL : SECITEM_DupArray(NULL, os->certStatusArray[i]);
             }
-            sc = NULL;
-
-            ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL :
-                                  ssl3_GetKeyPairRef(os->stepDownKeyPair);
-            ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL :
-                                  ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
-            ss->dheKeyPair = !os->dheKeyPair ? NULL :
-                             ssl3_GetKeyPairRef(os->dheKeyPair);
+            ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL : ssl3_GetKeyPairRef(os->stepDownKeyPair);
+            ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL : ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
+            ss->dheKeyPair = !os->dheKeyPair ? NULL : ssl3_GetKeyPairRef(os->dheKeyPair);
             ss->dheParams = os->dheParams;
 
             /*
              * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
              * XXX We should detect this, and not just march on with NULL pointers.
              */
             ss->authCertificate = os->authCertificate;
             ss->authCertificateArg = os->authCertificateArg;
@@ -317,17 +307,16 @@ ssl_DupSocket(sslSocket *os)
                 goto loser;
             }
         }
     }
     return ss;
 
 loser:
     ssl_FreeSocket(ss);
-    ssl_FreeServerCert(sc);
     return NULL;
 }
 
 static void
 ssl_DestroyLocks(sslSocket *ss)
 {
     /* Destroy locks. */
     if (ss->firstHandshakeLock) {
@@ -360,37 +349,51 @@ ssl_DestroyLocks(sslSocket *ss)
         ss->recvBufLock = NULL;
     }
 }
 
 /* Caller holds any relevant locks */
 static void
 ssl_DestroySocketContents(sslSocket *ss)
 {
-    PRCList *cursor;
+    /* "i" should be of type SSLKEAType, but CC on IRIX complains during
+     * the for loop.
+     */
+    int i;
 
     /* Free up socket */
     ssl_DestroySecurityInfo(&ss->sec);
 
     ssl3_DestroySSL3Info(ss);
 
     PORT_Free(ss->saveBuf.buf);
     PORT_Free(ss->pendingBuf.buf);
     ssl3_DestroyGather(&ss->gs);
 
     if (ss->peerID != NULL)
         PORT_Free(ss->peerID);
     if (ss->url != NULL)
         PORT_Free((void *)ss->url); /* CONST */
 
-    /* Clean up server certificates and sundries. */
-    while (!PR_CLIST_IS_EMPTY(&ss->serverCerts)) {
-        cursor = PR_LIST_TAIL(&ss->serverCerts);
-        PR_REMOVE_LINK(cursor);
-        ssl_FreeServerCert((sslServerCert *)cursor);
+    /* Clean up server configuration */
+    for (i = kt_null; i < kt_kea_size; i++) {
+        sslServerCerts *sc = ss->serverCerts + i;
+        if (sc->serverCert != NULL)
+            CERT_DestroyCertificate(sc->serverCert);
+        if (sc->serverCertChain != NULL)
+            CERT_DestroyCertificateList(sc->serverCertChain);
+        if (sc->serverKeyPair != NULL)
+            ssl3_FreeKeyPair(sc->serverKeyPair);
+        if (ss->certStatusArray[i] != NULL) {
+            SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+            ss->certStatusArray[i] = NULL;
+        }
+        if (ss->signedCertTimestamps[i].data) {
+            SECITEM_FreeItem(&ss->signedCertTimestamps[i], PR_FALSE);
+        }
     }
     if (ss->stepDownKeyPair) {
         ssl3_FreeKeyPair(ss->stepDownKeyPair);
         ss->stepDownKeyPair = NULL;
     }
     if (ss->ephemeralECDHKeyPair) {
         ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
         ss->ephemeralECDHKeyPair = NULL;
@@ -1891,18 +1894,19 @@ SSL_GetSRTPCipher(PRFileDesc *fd, PRUint
     *cipher = ss->ssl3.dtlsSRTPCipherSuite;
     return SECSuccess;
 }
 
 PRFileDesc *
 SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
 {
     sslSocket *sm = NULL, *ss = NULL;
-    PRCList *cursor;
-    sslServerCert *sc = NULL;
+    int i;
+    sslServerCerts *mc = NULL;
+    sslServerCerts *sc = NULL;
 
     if (model == NULL) {
         PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
         return NULL;
     }
     sm = ssl_FindSocket(model);
     if (sm == NULL) {
         SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD",
@@ -1927,54 +1931,62 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
                     sm->ssl3.signatureAlgorithmCount);
     ss->ssl3.signatureAlgorithmCount = sm->ssl3.signatureAlgorithmCount;
     ss->ssl3.downgradeCheckVersion = sm->ssl3.downgradeCheckVersion;
 
     if (!ss->opt.useSecurity) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return NULL;
     }
-    while (!PR_CLIST_IS_EMPTY(&ss->serverCerts)) {
-        cursor = PR_LIST_TAIL(&ss->serverCerts);
-        PR_REMOVE_LINK(cursor);
-        ssl_FreeServerCert((sslServerCert *)cursor);
-    }
-    for (cursor = PR_NEXT_LINK(&sm->serverCerts);
-         cursor != &sm->serverCerts;
-         cursor = PR_NEXT_LINK(cursor)) {
-        sslServerCert *mc = (sslServerCert*)cursor;
-
-        sc = ssl_NewServerCert(&mc->certType);
+    /* This int should be SSLKEAType, but CC on Irix complains,
+     * during the for loop.
+     */
+    for (i = kt_null; i < kt_kea_size; i++) {
+        mc = &(sm->serverCerts[i]);
+        sc = &(ss->serverCerts[i]);
         if (mc->serverCert && mc->serverCertChain) {
-            sc->serverCert      = CERT_DupCertificate(mc->serverCert);
+            if (sc->serverCert) {
+                CERT_DestroyCertificate(sc->serverCert);
+            }
+            sc->serverCert = CERT_DupCertificate(mc->serverCert);
+            if (sc->serverCertChain) {
+                CERT_DestroyCertificateList(sc->serverCertChain);
+            }
             sc->serverCertChain = CERT_DupCertList(mc->serverCertChain);
             if (!sc->serverCertChain)
                 goto loser;
-            if (mc->certStatusArray) {
-                sc->certStatusArray = SECITEM_DupArray(NULL, mc->certStatusArray);
-                if (!sc->certStatusArray)
+            if (sm->certStatusArray[i]) {
+                if (ss->certStatusArray[i]) {
+                    SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+                    ss->certStatusArray[i] = NULL;
+                }
+                ss->certStatusArray[i] = SECITEM_DupArray(NULL, sm->certStatusArray[i]);
+                if (!ss->certStatusArray[i])
                     goto loser;
             }
-            if (mc->signedCertTimestamps.data) {
+            if (sm->signedCertTimestamps[i].data) {
+                if (ss->signedCertTimestamps[i].data) {
+                    SECITEM_FreeItem(&ss->signedCertTimestamps[i], PR_FALSE);
+                }
                 if (SECITEM_CopyItem(NULL,
-                                     &sc->signedCertTimestamps,
-                                     &mc->signedCertTimestamps) !=
+                                     &ss->signedCertTimestamps[i],
+                                     &sm->signedCertTimestamps[i]) !=
                     SECSuccess) {
                     goto loser;
                 }
             }
         }
         if (mc->serverKeyPair) {
+            if (sc->serverKeyPair) {
+                ssl3_FreeKeyPair(sc->serverKeyPair);
+            }
             sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair);
             sc->serverKeyBits = mc->serverKeyBits;
         }
-        PR_APPEND_LINK(&sc->link, &ss->serverCerts);
     }
-    sc = NULL;
-
     if (sm->stepDownKeyPair) {
         if (ss->stepDownKeyPair) {
             ssl3_FreeKeyPair(ss->stepDownKeyPair);
         }
         ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair);
     }
     if (sm->ephemeralECDHKeyPair) {
         if (ss->ephemeralECDHKeyPair) {
@@ -2013,17 +2025,16 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
     if (sm->handshakeCallback)
         ss->handshakeCallback = sm->handshakeCallback;
     if (sm->handshakeCallbackData)
         ss->handshakeCallbackData = sm->handshakeCallbackData;
     if (sm->pkcs11PinArg)
         ss->pkcs11PinArg = sm->pkcs11PinArg;
     return fd;
 loser:
-    ssl_FreeServerCert(sc);
     return NULL;
 }
 
 /*
  * Get the user supplied range
  */
 static SECStatus
 ssl3_GetRangePolicy(SSLProtocolVariant protocolVariant, SSLVersionRange *prange)
@@ -2669,16 +2680,74 @@ ssl_GetSockName(PRFileDesc *fd, PRNetAdd
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), fd));
         return PR_FAILURE;
     }
     return (PRStatus)(*ss->ops->getsockname)(ss, name);
 }
 
 SECStatus
+SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
+                            SSLKEAType kea)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetStapledOCSPResponses",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (kea <= 0 || kea >= kt_kea_size) {
+        SSL_DBG(("%d: SSL[%d]: invalid key type in SSL_SetStapledOCSPResponses",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (ss->certStatusArray[kea]) {
+        SECITEM_FreeArray(ss->certStatusArray[kea], PR_TRUE);
+        ss->certStatusArray[kea] = NULL;
+    }
+    if (responses) {
+        ss->certStatusArray[kea] = SECITEM_DupArray(NULL, responses);
+    }
+    return (ss->certStatusArray[kea] || !responses) ? SECSuccess : SECFailure;
+}
+
+SECStatus
+SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType kea)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSignedCertTimestamps",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (kea <= 0 || kea >= kt_kea_size) {
+        SSL_DBG(("%d: SSL[%d]: invalid key type in SSL_SetSignedCertTimestamps",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (ss->signedCertTimestamps[kea].data) {
+        SECITEM_FreeItem(&ss->signedCertTimestamps[kea], PR_FALSE);
+    }
+
+    if (!scts) {
+        return SECSuccess;
+    }
+
+    return SECITEM_CopyItem(NULL, &ss->signedCertTimestamps[kea], scts);
+}
+
+SECStatus
 SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID)
 {
     sslSocket *ss;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSockPeerID",
                  SSL_GETPID(), fd));
@@ -3359,34 +3428,42 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
     ssl_SetDefaultsFromEnvironment();
 
     if (ssl_force_locks)
         makeLocks = PR_TRUE;
 
     /* Make a new socket and get it ready */
     ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket));
     if (ss) {
-        /* This should be of type SSLAuthType, but CC on IRIX
+        /* This should be of type SSLKEAType, but CC on IRIX
          * complains during the for loop.
          */
+        int i;
         SECStatus status;
 
         ss->opt = ssl_defaults;
         ss->opt.useSocks = PR_FALSE;
         ss->opt.noLocks = !makeLocks;
         ss->vrange = *VERSIONS_DEFAULTS(protocolVariant);
         ss->protocolVariant = protocolVariant;
 
         ss->peerID = NULL;
         ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
         ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
         ss->cTimeout = PR_INTERVAL_NO_TIMEOUT;
         ss->url = NULL;
 
-        PR_INIT_CLIST(&ss->serverCerts);
+        for (i = kt_null; i < kt_kea_size; i++) {
+            sslServerCerts *sc = ss->serverCerts + i;
+            sc->serverCert = NULL;
+            sc->serverCertChain = NULL;
+            sc->serverKeyPair = NULL;
+            sc->serverKeyBits = 0;
+            ss->certStatusArray[i] = NULL;
+        }
         ss->stepDownKeyPair = NULL;
 
         ss->dheParams = NULL;
         ss->dheKeyPair = NULL;
 
         ss->dbHandle = CERT_GetDefaultCertDB();
 
         /* Provide default implementation of hooks */
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -5,18 +5,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __sslt_h_
 #define __sslt_h_
 
 #include "prtypes.h"
-#include "secitem.h"
-#include "certt.h"
 
 typedef struct SSL3StatisticsStr {
     /* statistics from ssl3_SendClientHello (sch) */
     long sch_sid_cache_hits;
     long sch_sid_cache_misses;
     long sch_sid_cache_not_ok;
 
     /* statistics from ssl3_HandleServerHello (hsh) */
@@ -38,17 +36,16 @@ typedef struct SSL3StatisticsStr {
 
 /* Key Exchange algorithm values */
 typedef enum {
     ssl_kea_null = 0,
     ssl_kea_rsa = 1,
     ssl_kea_dh = 2,
     ssl_kea_fortezza = 3, /* deprecated, now unused */
     ssl_kea_ecdh = 4,
-    ssl_kea_ecdh_psk = 5,
     ssl_kea_size /* number of ssl_kea_ algorithms */
 } SSLKEAType;
 
 /* The following defines are for backwards compatibility.
 ** They will be removed in a forthcoming release to reduce namespace pollution.
 ** programs that use the kt_ symbols should convert to the ssl_kt_ symbols
 ** soon.
 */
@@ -60,17 +57,18 @@ typedef enum {
 #define kt_kea_size ssl_kea_size
 
 /* Values of this enum match the SignatureAlgorithm enum from
  * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 typedef enum {
     ssl_sign_null = 0, /* "anonymous" in TLS */
     ssl_sign_rsa = 1,
     ssl_sign_dsa = 2,
-    ssl_sign_ecdsa = 3
+    ssl_sign_ecdsa = 3,
+    ssl_sign_psk = 4
 } SSLSignType;
 
 /* Values of this enum match the HashAlgorithm enum from
  * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 typedef enum {
     /* ssl_hash_none is used internally to mean the pre-1.2 combination of MD5
      * and SHA1. The other values are only used in TLS 1.2. */
     ssl_hash_none = 0,
@@ -82,36 +80,25 @@ typedef enum {
     ssl_hash_sha512 = 6
 } SSLHashType;
 
 typedef struct SSLSignatureAndHashAlgStr {
     SSLHashType hashAlg;
     SSLSignType sigAlg;
 } SSLSignatureAndHashAlg;
 
-/*
-** SSLAuthType describes the type of key that is used to authenticate a
-** connection.  That is, the type of key in the end-entity certificate.
-*/
 typedef enum {
     ssl_auth_null = 0,
-    ssl_auth_rsa_decrypt = 1, /* static RSA */
+    ssl_auth_rsa = 1,
     ssl_auth_dsa = 2,
-    ssl_auth_kea = 3, /* unused */
+    ssl_auth_kea = 3,
     ssl_auth_ecdsa = 4,
-    ssl_auth_ecdh = 5,
-    ssl_auth_rsa_sign = 6, /* RSA PKCS#1.5 signing */
-    ssl_auth_rsa_pss = 7,
-    ssl_auth_psk = 8,
-    ssl_auth_size /* number of authentication types */
+    ssl_auth_psk = 5         /* Used for both PSK and (EC)DHE-PSK */
 } SSLAuthType;
 
-/* This is defined for backward compatibility reasons */
-#define ssl_auth_rsa ssl_auth_rsa_sign
-
 typedef enum {
     ssl_calg_null = 0,
     ssl_calg_rc4 = 1,
     ssl_calg_rc2 = 2,
     ssl_calg_des = 3,
     ssl_calg_3des = 4,
     ssl_calg_idea = 5,
     ssl_calg_fortezza = 6, /* deprecated, now unused */
@@ -132,32 +119,16 @@ typedef enum {
     ssl_mac_aead = 6
 } SSLMACAlgorithm;
 
 typedef enum {
     ssl_compression_null = 0,
     ssl_compression_deflate = 1 /* RFC 3749 */
 } SSLCompressionMethod;
 
-typedef struct SSLExtraServerCertDataStr {
-    /* When this struct is passed to SSL_ConfigServerCert, and authType is set
-     * to a value other than ssl_auth_null, this limits the use of the key to
-     * the type defined; otherwise, the certificate is configured for all
-     * compatible types. */
-    SSLAuthType authType;
-    /* The remainder of the certificate chain. */
-    const CERTCertificateList *certChain;
-    /* A set of one or more stapled OCSP responses for the certificate.  This is
-     * used to generate the OCSP stapling answer provided by the server. */
-    const SECItemArray *stapledOCSPResponses;
-    /* A serialized sign_certificate_timestamp extension, used to answer
-     * requests from clients for this data. */
-    const SECItem *signedCertTimestamps;
-} SSLExtraServerCertData;
-
 typedef struct SSLChannelInfoStr {
     /* |length| is obsolete. On return, SSL_GetChannelInfo sets |length| to the
      * smaller of the |len| argument and the length of the struct. The caller
      * may ignore |length|. */
     PRUint32 length;
     PRUint16 protocolVersion;
     PRUint16 cipherSuite;
 
@@ -213,17 +184,17 @@ typedef struct SSLCipherSuiteInfoStr {
     PRUint16 length;
     PRUint16 cipherSuite;
 
     /* Cipher Suite Name */
     const char* cipherSuiteName;
 
     /* server authentication info */
     const char* authAlgorithmName;
-    SSLAuthType authAlgorithm; /* deprecated, use |authType| */
+    SSLAuthType authAlgorithm;
 
     /* key exchange algorithm info */
     const char* keaTypeName;
     SSLKEAType keaType;
 
     /* symmetric encryption info */
     const char* symCipherName;
     SSLCipherAlgorithm symCipher;
@@ -239,20 +210,16 @@ typedef struct SSLCipherSuiteInfoStr {
     SSLMACAlgorithm macAlgorithm;
     PRUint16 macBits;
 
     PRUintn isFIPS : 1;
     PRUintn isExportable : 1;
     PRUintn nonStandard : 1;
     PRUintn reservedBits : 29;
 
-    /* This reports the correct authentication type for the cipher suite, use
-     * this instead of |authAlgorithm|. */
-    SSLAuthType authType;
-
 } SSLCipherSuiteInfo;
 
 typedef enum {
     ssl_variant_stream = 0,
     ssl_variant_datagram = 1
 } SSLProtocolVariant;
 
 typedef struct SSLVersionRangeStr {
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -352,21 +352,18 @@ tls13_RecoverWrappedSharedSecret(sslSock
     if (!sid->u.ssl3.keys.msIsWrapped) {
         PORT_Assert(0); /* I think this can't happen. */
         return SECFailure;
     }
 
     /* If we are the server, we compute the wrapping key, but if we
      * are the client, it's 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.exchKeyType,
                                       sid->u.ssl3.masterWrapMech,
                                       ss->pkcs11PinArg);
     } else {
         slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
                                  sid->u.ssl3.masterSlotID);
         if (!slot)
             return SECFailure;
 
@@ -406,20 +403,20 @@ tls13_RecoverWrappedSharedSecret(sslSock
 
 static void
 tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid)
 {
     /* Set these to match the cached value.
      * TODO(ekr@rtfm.com): Make a version with the "true" values.
      * Bug 1256137.
      */
-    ss->sec.authType = sid->authType;
-    ss->sec.authKeyBits = sid->authKeyBits;
-    ss->sec.keaType = sid->keaType;
-    ss->sec.keaKeyBits = sid->keaKeyBits;
+    ss->sec.authAlgorithm = sid->authAlgorithm;
+    ss->sec.authKeyBits   = sid->authKeyBits;
+    ss->sec.keaType       = sid->keaType;
+    ss->sec.keaKeyBits    = sid->keaKeyBits;
     ss->ssl3.hs.origCipherSuite = sid->u.ssl3.cipherSuite;
 }
 
 PRBool
 tls13_AllowPskCipher(const sslSocket *ss, const ssl3CipherSuiteDef *cipher_def)
 {
     if (ss->sec.isServer) {
         if (!ss->statelessResume)
@@ -455,35 +452,16 @@ tls13_AllowPskCipher(const sslSocket *ss
      * adjustable KDFs. */
     SSL_TRC(3, ("%d: TLS 1.3[%d]: Enabling cipher suite suite 0x%04x",
                 SSL_GETPID(), ss->fd,
                 cipher_def->cipher_suite));
 
     return PR_TRUE;
 }
 
-/* Check whether resumption-PSK is allowed. */
-static PRBool
-tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
-{
-    if (sid->version != ss->version) {
-        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. */
-    if (!ssl_FindServerCert(ss, &sid->certType)) {
-        return PR_FALSE;
-    }
-
-    return PR_TRUE;
-}
-
 /* 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,
                              const SECItem *suites,
                              sslSessionID *sid)
 {
@@ -491,24 +469,35 @@ tls13_HandleClientHelloPart2(sslSocket *
     SSL3Statistics *ssl3stats = SSL_GetStatistics();
     int j;
 
     rv = tls13_SetupNullCipherSpec(ss);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
-    if (sid != NULL && !tls13_CanResume(ss, sid)) {
-        /* Destroy SID if it is present an unusable. */
-        SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
-        if (ss->sec.uncache)
-            ss->sec.uncache(sid);
-        ssl_FreeSID(sid);
-        sid = NULL;
-        ss->statelessResume = PR_FALSE;
+    /* Sanity check whether resumption-PSK is allowed. */
+    if (sid != NULL) {
+        PRBool resumeOK = PR_FALSE;
+
+        do {
+            if (sid->version != ss->version) {
+                break;
+            }
+            resumeOK = PR_TRUE;
+        } while(0);
+
+        if (!resumeOK) {
+            SSL_AtomicIncrementLong(& ssl3stats->hch_sid_cache_not_ok);
+            if (ss->sec.uncache)
+                ss->sec.uncache(sid);
+            ssl_FreeSID(sid);
+            sid = NULL;
+            ss->statelessResume = PR_FALSE;
+        }
     }
 
 #ifndef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
     if (j <= 0) {                  /* no ciphers are working/supported by PK11 */
         FATAL_ERROR(ss, PORT_GetError(), internal_error);
         goto loser;
@@ -516,39 +505,45 @@ tls13_HandleClientHelloPart2(sslSocket *
 #endif
 
     rv = ssl3_NegotiateCipherSuite(ss, suites);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
         goto loser;
     }
 
-    if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
+    /* TODO(ekr@rtfm.com): Update this when we have pure PSK. */
+    if (ss->ssl3.hs.suite_def->key_exchange_alg != kea_ecdhe_psk) {
         /* TODO(ekr@rtfm.com): Free resumeSID. */
         ss->statelessResume = PR_FALSE;
     }
 
     if (ss->statelessResume) {
         PORT_Assert(sid);
 
         rv = tls13_RecoverWrappedSharedSecret(ss, sid);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             goto loser;
         }
 
-        SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_hits);
-        SSL_AtomicIncrementLong(&ssl3stats->hch_sid_stateless_resumes);
+        SSL_AtomicIncrementLong(& ssl3stats->hch_sid_cache_hits);
+        SSL_AtomicIncrementLong(& ssl3stats->hch_sid_stateless_resumes);
         ss->ssl3.hs.isResuming = PR_TRUE;
 
         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);
+        /* server sids don't remember the server cert we previously sent,
+        ** but they do remember the kea type 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.localCert     =
+                CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert);
+
         if (sid->peerCert != NULL) {
             ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
         }
         ssl3_RegisterServerHelloExtensionSender(
             ss, ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
         ss->sec.ci.sid = sid;
     } else {
         if (sid) { /* we had a sid, but it's no longer valid, free it */
@@ -581,32 +576,16 @@ tls13_HandleClientHelloPart2(sslSocket *
                                 &ss->ssl3.pwSpec->srvVirtName) !=
             SECEqual) {
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
                         handshake_failure);
             goto loser;
         }
     }
 
-<<<<<<< dest
-=======
-    if (!ss->statelessResume) {
-        rv = ssl3_SelectServerCert(ss);
-        if (rv != SECSuccess) {
-            goto loser;
-        }
-    }
-
-    rv = ssl3_SetupPendingCipherSpec(ss);
-    if (rv != SECSuccess) {
-        FATAL_ERROR(ss, PORT_GetError(), internal_error);
-        goto loser;
-    }
-
->>>>>>> source
     /* If this is TLS 1.3 we are expecting a ClientKeyShare
      * extension. Missing/absent extension cause failure
      * below. */
     rv = tls13_HandleClientKeyShare(ss);
     if (rv != SECSuccess) {
         goto loser;  /* An alert was sent already. */
     }
 
@@ -651,17 +630,16 @@ tls13_HandleClientKeyShare(sslSocket *ss
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     /* Figure out what group we expect */
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
 #ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
-        case ssl_kea_ecdh_psk:
             expectedGroup = ssl3_GetCurveNameForServerSocket(ss);
             if (!expectedGroup) {
                 FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP,
                             handshake_failure);
                 return SECFailure;
             }
             break;
 #endif
@@ -877,17 +855,17 @@ loser:
 }
 
 static SECStatus
 tls13_InitializeHandshakeEncryption(sslSocket *ss)
 {
     SECStatus rv;
 
     PORT_Assert(!!ss->ssl3.hs.xSS ==
-                (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk));
+                (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk));
     if (!ss->ssl3.hs.xSS) {
         ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES);
         if (!ss->ssl3.hs.xSS) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             return SECFailure;
         }
     }
 
@@ -904,17 +882,17 @@ tls13_InitializeHandshakeEncryption(sslS
     return rv;
 }
 
 /* Called from:  ssl3_HandleClientHello */
 SECStatus
 tls13_SendServerHelloSequence(sslSocket *ss)
 {
     SECStatus rv;
-    SECKEYPrivateKey *svrPrivKey;
+    SSL3KEAType certIndex;
 
     SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     rv = ssl3_SendServerHello(ss);
@@ -933,33 +911,42 @@ tls13_SendServerHelloSequence(sslSocket 
     }
 
     if (ss->opt.requestCertificate) {
         rv = tls13_SendCertificateRequest(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
     }
-    if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
+    if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) {
         rv = ssl3_SendCertificate(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
         rv = ssl3_SendCertificateStatus(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
 
-        svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
-        rv = ssl3_SendCertificateVerify(ss, svrPrivKey);
+        /* This was copied from: ssl3_SendCertificate.
+         * TODO(ekr@rtfm.com): Verify that this selection logic is correct.
+         * Bug 1237514.
+         */
+        if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+            (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+            certIndex = kt_rsa;
+        } else {
+            certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+        }
+        rv = ssl3_SendCertificateVerify(ss,
+                                        ss->serverCerts[certIndex].SERVERKEY);
         if (rv != SECSuccess) {
             return rv; /* err code is set. */
         }
     }
-
     /* Compute the rest of the secrets except for the resumption
      * and exporter secret. */
     rv = tls13_ComputeSecrets1(ss);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
@@ -994,17 +981,17 @@ tls13_HandleServerHelloPart2(sslSocket *
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
     if (isPSK) {
         PRBool cacheOK = PR_FALSE;
         do {
-            if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
+            if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) {
                 FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO,
                             illegal_parameter);
                 break;
             }
             rv = tls13_RecoverWrappedSharedSecret(ss, sid);
             if (rv != SECSuccess) {
                 FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
                 break;
@@ -1020,17 +1007,17 @@ tls13_HandleServerHelloPart2(sslSocket *
         }
 
         tls13_RestoreCipherInfo(ss, sid);
 
         SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
         SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
     } else {
         /* No PSK negotiated.*/
-        if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) {
+        if (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk) {
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO,
                             illegal_parameter);
             return SECFailure;
         }
         if (ssl3_ClientExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
             SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses);
         }
 
@@ -1091,17 +1078,16 @@ tls13_HandleServerKeyShare(sslSocket *ss
     SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
 #ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
-        case ssl_kea_ecdh_psk:
             expectedGroup = ssl3_PubKey2ECName(ss->ephemeralECDHKeyPair->pubKey);
             break;
 #endif /* NSS_DISABLE_ECC */
         default:
             FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG, handshake_failure);
             return SECFailure;
     }
 
@@ -1907,17 +1893,17 @@ tls13_HandleEncryptedExtensions(sslSocke
 
     rv = ssl3_HandleHelloExtensions(ss, &b, &length, encrypted_extensions);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set below */
     }
 
     PORT_Assert(!ss->sec.isServer);
 
-    if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) {
+    if (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk) {
         /* Compute the rest of the secrets except for the resumption
          * and exporter secret. */
         rv = tls13_ComputeSecrets1(ss);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             return SECFailure;
         }
         TLS13_SET_HS_STATE(ss, wait_finished);
@@ -2232,17 +2218,17 @@ tls13_HandleFinished(sslSocket *ss, SSL3
         }
 
         rv = tls13_FinishHandshake(ss);
         if (rv != SECSuccess) {
             return SECFailure;  /* Error code and alerts handled below */
         }
         ssl_GetXmitBufLock(ss);
         if (ss->opt.enableSessionTickets &&
-            ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
+            ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) {
             /* TODO(ekr@rtfm.com): Add support for new tickets in PSK. */
             rv = ssl3_SendNewSessionTicket(ss);
             if (rv != SECSuccess) {
                 ssl_ReleaseXmitBufLock(ss);
                 return SECFailure;  /* Error code and alerts handled below */
             }
             rv = ssl3_FlushHandshake(ss, 0);
         }
@@ -2403,34 +2389,42 @@ tls13_HandleNewSessionTicket(sslSocket *
         return SECFailure;
     }
 
     /* TODO(ekr@rtfm.com): Re-enable new tickets when PSK mode is
      * in use. I believe this works, but I can't test it until the
      * server side supports it. Bug 1257047.
      */
     if (!ss->opt.noCache && ss->sec.cache &&
-        ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
+        ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) {
+        SSL3KEAType effectiveExchKeyType;
 
         /* Uncache so that we replace. */
         (*ss->sec.uncache)(ss->sec.ci.sid);
 
         rv = SECITEM_CopyItem(NULL, &ticket.ticket, &data);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
             return SECFailure;
         }
         PRINT_BUF(50, (ss, "Caching session ticket",
                        ticket.ticket.data,
                        ticket.ticket.len));
 
         ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket);
         PORT_Assert(!ticket.ticket.data);
 
-        rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid);
+        if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+            ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
+            effectiveExchKeyType = kt_rsa;
+        } else {
+            effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+        }
+
+        rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid, effectiveExchKeyType);
         if (rv != SECSuccess)
             return SECFailure;
 
         /* Cache the session. */
         ss->sec.ci.sid->cached = never_cached;
         (*ss->sec.cache)(ss->sec.ci.sid);
     }