diff options
author | Martin Thomson <martin.thomson@gmail.com> | 2016-04-21 08:45:03 +1000 |
---|---|---|
committer | Martin Thomson <martin.thomson@gmail.com> | 2016-04-21 08:45:03 +1000 |
commit | 9b854d48f2eae8d6821979c71b9e06234aef76c0 (patch) | |
tree | 54d2b694e75c8e1426257f63ae48eed9015718d5 | |
parent | efe5b290c741ac43f20cfef1d138360f79bdcdc1 (diff) | |
download | nss-hg-9b854d48f2eae8d6821979c71b9e06234aef76c0.tar.gz |
Bug 1237514 - Index certificates by SSLAuthType, r=ttaubert,ekr,rrelyea
-rw-r--r-- | cmd/selfserv/selfserv.c | 6 | ||||
-rw-r--r-- | external_tests/common/scoped_ptrs.h | 20 | ||||
-rw-r--r-- | external_tests/ssl_gtest/libssl_internals.c | 7 | ||||
-rw-r--r-- | external_tests/ssl_gtest/ssl_loopback_unittest.cc | 113 | ||||
-rw-r--r-- | external_tests/ssl_gtest/tls_agent.cc | 113 | ||||
-rw-r--r-- | external_tests/ssl_gtest/tls_agent.h | 18 | ||||
-rw-r--r-- | external_tests/ssl_gtest/tls_connect.cc | 24 | ||||
-rw-r--r-- | external_tests/ssl_gtest/tls_connect.h | 4 | ||||
-rw-r--r-- | lib/pk11wrap/pk11auth.c | 3 | ||||
-rw-r--r-- | lib/ssl/SSLerrs.h | 2 | ||||
-rw-r--r-- | lib/ssl/manifest.mn | 1 | ||||
-rw-r--r-- | lib/ssl/ssl.def | 1 | ||||
-rw-r--r-- | lib/ssl/ssl.h | 69 | ||||
-rw-r--r-- | lib/ssl/ssl3con.c | 564 | ||||
-rw-r--r-- | lib/ssl/ssl3ecc.c | 214 | ||||
-rw-r--r-- | lib/ssl/ssl3ext.c | 125 | ||||
-rw-r--r-- | lib/ssl/sslcert.c | 960 | ||||
-rw-r--r-- | lib/ssl/sslcert.h | 62 | ||||
-rw-r--r-- | lib/ssl/sslcon.c | 2 | ||||
-rw-r--r-- | lib/ssl/sslimpl.h | 155 | ||||
-rw-r--r-- | lib/ssl/sslinfo.c | 203 | ||||
-rw-r--r-- | lib/ssl/sslsecur.c | 254 | ||||
-rw-r--r-- | lib/ssl/sslsnce.c | 70 | ||||
-rw-r--r-- | lib/ssl/sslsock.c | 189 | ||||
-rw-r--r-- | lib/ssl/sslt.h | 46 | ||||
-rw-r--r-- | lib/ssl/tls13con.c | 132 |
26 files changed, 2183 insertions, 1174 deletions
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c index bf85d1637..9a1572837 100644 --- a/cmd/selfserv/selfserv.c +++ b/cmd/selfserv/selfserv.c @@ -516,8 +516,8 @@ mySSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr, if (privKey == NULL) { goto loser; /* Send alert */ } - if (SSL_ConfigSecureServer(fd, cert, privKey, - kt_rsa) != SECSuccess) { + if (SSL_ConfigServerCert(fd, cert, privKey, NULL, 0) + != SECSuccess) { goto loser; /* Send alert */ } SECKEY_DestroyPrivateKey(privKey); @@ -1956,6 +1956,8 @@ server_main( } } + /* This uses the legacy certificate API. See mySSLSNISocketConfig() for the + * new, prefered API. */ for (kea = kt_rsa; kea < kt_kea_size; kea++) { if (cert[kea] != NULL) { secStatus = SSL_ConfigSecureServer(model_sock, diff --git a/external_tests/common/scoped_ptrs.h b/external_tests/common/scoped_ptrs.h index 374ad2a04..261ff7a9c 100644 --- a/external_tests/common/scoped_ptrs.h +++ b/external_tests/common/scoped_ptrs.h @@ -7,20 +7,23 @@ #ifndef scoped_ptrs_h__ #define scoped_ptrs_h__ +#include "cert.h" #include "keyhi.h" +#include "pk11pub.h" namespace nss_test { struct ScopedDelete { + void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); } + void operator()(CERTSubjectPublicKeyInfo* spki) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); } - void operator()(SECItem* item) { SECITEM_FreeItem(item, true); } void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); } + void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); } + void operator()(SECItem* item) { SECITEM_FreeItem(item, true); } void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); } void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); } - void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); } - void operator()(CERTSubjectPublicKeyInfo* spki) { - SECKEY_DestroySubjectPublicKeyInfo(spki); - } }; template<class T> @@ -30,13 +33,14 @@ struct ScopedMaybeDelete { #define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped ## x +SCOPED(CERTCertificate); +SCOPED(CERTSubjectPublicKeyInfo); SCOPED(PK11SlotInfo); -SCOPED(SECItem); SCOPED(PK11SymKey); +SCOPED(SECAlgorithmID); +SCOPED(SECItem); SCOPED(SECKEYPublicKey); SCOPED(SECKEYPrivateKey); -SCOPED(SECAlgorithmID); -SCOPED(CERTSubjectPublicKeyInfo); #undef SCOPED diff --git a/external_tests/ssl_gtest/libssl_internals.c b/external_tests/ssl_gtest/libssl_internals.c index 48d4412f8..17580ad67 100644 --- a/external_tests/ssl_gtest/libssl_internals.c +++ b/external_tests/ssl_gtest/libssl_internals.c @@ -29,11 +29,14 @@ 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) { + if (authAlgorithm == ssl_auth_ecdsa || + authAlgorithm == ssl_auth_ecdh_rsa || + authAlgorithm == ssl_auth_ecdh_ecdsa) { return serverKeyBits; } - PORT_Assert(authAlgorithm == ssl_auth_rsa); + PORT_Assert(authAlgorithm == ssl_auth_rsa_decrypt || + authAlgorithm == ssl_auth_rsa_sign); PRUint32 minKeaBits; #ifdef NSS_ECC_MORE_THAN_SUITE_B // P-192 is the smallest curve we want to use. diff --git a/external_tests/ssl_gtest/ssl_loopback_unittest.cc b/external_tests/ssl_gtest/ssl_loopback_unittest.cc index c5b0174af..a098d1203 100644 --- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc +++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc @@ -16,6 +16,7 @@ extern "C" { #include "libssl_internals.h" } +#include "scoped_ptrs.h" #include "tls_parser.h" #include "tls_filter.h" #include "tls_connect.h" @@ -109,35 +110,14 @@ class TlsServerKeyExchangeEcdhe { DataBuffer public_key_; }; -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. - uint16_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); - } -}; +class TlsChaCha20Poly1305Test : public TlsConnectTls12 {}; TEST_P(TlsConnectGeneric, SetupOnly) {} TEST_P(TlsConnectGeneric, Connect) { SetExpectedVersion(std::get<1>(GetParam())); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); } TEST_P(TlsConnectGeneric, ConnectEcdsa) { @@ -147,6 +127,22 @@ TEST_P(TlsConnectGeneric, ConnectEcdsa) { 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_ecdsa); +} + +TEST_P(TlsConnectStreamPre13, ConnectRC4) { + ConnectWithCipherSuite(TLS_RSA_WITH_RC4_128_SHA); +} + TEST_P(TlsConnectGenericPre13, ConnectFalseStart) { client_->EnableFalseStart(); Connect(); @@ -308,11 +304,56 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) { SendReceive(); } +// This callback switches out the "server" cert used on the server with +// the "client" certificate, which should be the same type. +static int32_t SwitchCertificates(TlsAgent& agent, const SECItem *srvNameArr, + uint32_t srvNameArrSize) { + bool ok = agent.ConfigServerCert("client"); + if (!ok) return SSL_SNI_SEND_ALERT; + + return 0; // first config +}; + +TEST_P(TlsConnectGeneric, ServerSNICertSwitch) { + Connect(); + ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd())); + + ResetRsa(); + EnsureTlsSetup(); + ConfigureSessionCache(RESUME_NONE, RESUME_NONE); + + server_->SetSniCallback(SwitchCertificates); + + Connect(); + ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd())); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); + EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert)); +} + +TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) { + ResetEcdsa(); + Connect(); + ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd())); + + ResetEcdsa(); + EnsureTlsSetup(); + ConfigureSessionCache(RESUME_NONE, RESUME_NONE); + + // Because we configure an RSA certificate here, it only adds a second, unused + // certificate, which has no effect on what the server uses. + server_->SetSniCallback(SwitchCertificates); + + Connect(); + ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd())); + CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa); + EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert)); +} + TEST_P(TlsConnectGeneric, ClientAuth) { client_->SetupClientAuth(); server_->RequestClientAuth(true); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); } // In TLS 1.3, the client sends its cert rejection on the @@ -328,7 +369,7 @@ TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) { TEST_P(TlsConnectGeneric, ClientAuthRequestedRejected) { server_->RequestClientAuth(false); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); } @@ -397,13 +438,13 @@ TEST_P(TlsConnectGenericPre13, SignatureAlgorithmNoOverlapStaticRsa) { PR_ARRAY_SIZE(SignatureRsaSha256)); DisableDheAndEcdheCiphers(); Connect(); - CheckKeys(ssl_kea_rsa, ssl_auth_rsa); + CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt); } TEST_P(TlsConnectGenericPre13, ConnectStaticRSA) { DisableDheAndEcdheCiphers(); Connect(); - CheckKeys(ssl_kea_rsa, ssl_auth_rsa); + CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt); } // Signature algorithms governs both verification and generation of signatures. @@ -538,7 +579,7 @@ TEST_P(TlsConnectStreamPre13, ConnectAndServerRenegotiate) { TEST_P(TlsConnectGenericPre13, ConnectDhe) { DisableEcdheCiphers(); Connect(); - CheckKeys(ssl_kea_dh, ssl_auth_rsa); + CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign); } // Test that a totally bogus EPMS is handled correctly. @@ -584,7 +625,7 @@ TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) { TEST_P(TlsConnectGeneric, ConnectEcdhe) { Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); } // Prior to TLS 1.3, we were not fully ephemeral; though 1.3 fixes that @@ -593,7 +634,7 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) { new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange); server_->SetPacketFilter(i1); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); TlsServerKeyExchangeEcdhe dhe1; EXPECT_TRUE(dhe1.Parse(i1->buffer())); @@ -604,7 +645,7 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) { server_->SetPacketFilter(i2); ConfigureSessionCache(RESUME_NONE, RESUME_NONE); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); TlsServerKeyExchangeEcdhe dhe2; EXPECT_TRUE(dhe2.Parse(i2->buffer())); @@ -625,7 +666,7 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) { new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange); server_->SetPacketFilter(i1); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); TlsServerKeyExchangeEcdhe dhe1; EXPECT_TRUE(dhe1.Parse(i1->buffer())); @@ -639,7 +680,7 @@ TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) { server_->SetPacketFilter(i2); ConfigureSessionCache(RESUME_NONE, RESUME_NONE); Connect(); - CheckKeys(ssl_kea_ecdh, ssl_auth_rsa); + CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); TlsServerKeyExchangeEcdhe dhe2; EXPECT_TRUE(dhe2.Parse(i2->buffer())); @@ -656,16 +697,16 @@ TEST_P(TlsConnectGeneric, ConnectSendReceive) { } TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305DheRsa) { - ConnectSendReceive(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + ConnectWithCipherSuite(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256); } TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheRsa) { - ConnectSendReceive(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + ConnectWithCipherSuite(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); } TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheEcdsa) { ResetEcdsa(); - ConnectSendReceive(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); + ConnectWithCipherSuite(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); } // The next two tests takes advantage of the fact that we diff --git a/external_tests/ssl_gtest/tls_agent.cc b/external_tests/ssl_gtest/tls_agent.cc index c0af1ebb5..bb9afbd2a 100644 --- a/external_tests/ssl_gtest/tls_agent.cc +++ b/external_tests/ssl_gtest/tls_agent.cc @@ -20,6 +20,7 @@ extern "C" { #define GTEST_HAS_RTTI 0 #include "gtest/gtest.h" +#include "scoped_ptrs.h" namespace nss_test { @@ -50,7 +51,8 @@ TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode, SSLKEAType kea recv_ctr_(0), expected_read_error_(false), handshake_callback_(), - auth_certificate_callback_() { + auth_certificate_callback_(), + sni_callback_() { memset(&info_, 0, sizeof(info_)); memset(&csinfo_, 0, sizeof(csinfo_)); @@ -77,6 +79,30 @@ TlsAgent::~TlsAgent() { } } +bool TlsAgent::ConfigServerCert(const std::string& name, bool updateKeyBits) { + ScopedCERTCertificate cert(PK11_FindCertFromNickname(name.c_str(), nullptr)); + EXPECT_NE(nullptr, cert.get()); + if (!cert.get()) return false; + + ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get())); + EXPECT_NE(nullptr, pub.get()); + if (!pub.get()) return false; + if (updateKeyBits) { + server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub.get()); + } + + ScopedSECKEYPrivateKey priv(PK11_FindKeyByAnyCert(cert.get(), nullptr)); + EXPECT_NE(nullptr, priv.get()); + if (!priv.get()) return false; + + SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, ssl_kea_null); + EXPECT_EQ(SECFailure, rv); + rv = SSL_ConfigServerCert(ssl_fd_, cert.get(), priv.get(), nullptr, 0); + EXPECT_EQ(SECSuccess, rv); + + return rv == SECSuccess; +} + bool TlsAgent::EnsureTlsSetup() { // Don't set up twice if (ssl_fd_) return true; @@ -91,40 +117,22 @@ bool TlsAgent::EnsureTlsSetup() { if (!ssl_fd_) return false; pr_fd_ = nullptr; - if (role_ == SERVER) { - CERTCertificate* cert = PK11_FindCertFromNickname(name_.c_str(), nullptr); - EXPECT_NE(nullptr, cert); - if (!cert) return false; - - SECKEYPublicKey* pub = CERT_ExtractPublicKey(cert); - EXPECT_NE(nullptr, pub); - if (!pub) return false; // Leak cert. - server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub); - SECKEY_DestroyPublicKey(pub); - - SECKEYPrivateKey* priv = PK11_FindKeyByAnyCert(cert, nullptr); - EXPECT_NE(nullptr, priv); - if (!priv) return false; // Leak cert. - - SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kea_); - EXPECT_EQ(SECSuccess, rv); - if (rv != SECSuccess) return false; // Leak cert and key. + SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_); + EXPECT_EQ(SECSuccess, rv); + if (rv != SECSuccess) return false; - SECKEY_DestroyPrivateKey(priv); - CERT_DestroyCertificate(cert); + if (role_ == SERVER) { + EXPECT_TRUE(ConfigServerCert(name_, true)); rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook, this); - EXPECT_EQ(SECSuccess, rv); // don't abort, just fail + EXPECT_EQ(SECSuccess, rv); + if (rv != SECSuccess) return false; } else { - SECStatus rv = SSL_SetURL(ssl_fd_, "server"); + rv = SSL_SetURL(ssl_fd_, "server"); EXPECT_EQ(SECSuccess, rv); if (rv != SECSuccess) return false; } - SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_); - EXPECT_EQ(SECSuccess, rv); - if (rv != SECSuccess) return false; - rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); EXPECT_EQ(SECSuccess, rv); if (rv != SECSuccess) return false; @@ -213,6 +221,30 @@ void TlsAgent::DisableCiphersByKeyExchange(SSLKEAType kea) { } } +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::EnableSingleCipher(uint16_t cipher) { + for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) { + bool enable = SSL_ImplementedCiphers[i] == cipher; + SECStatus rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], enable); + EXPECT_EQ(SECSuccess, rv); + } +} + void TlsAgent::SetSessionTicketsEnabled(bool en) { EXPECT_TRUE(EnsureTlsSetup()); @@ -302,7 +334,7 @@ void TlsAgent::CheckKEAType(SSLKEAType type) const { EXPECT_EQ(type, csinfo_.keaType); PRUint32 ecKEAKeyBits = SSLInt_DetermineKEABits(server_key_bits_, - csinfo_.authAlgorithm); + csinfo_.authType); switch (type) { case ssl_kea_ecdh: @@ -321,14 +353,37 @@ void TlsAgent::CheckKEAType(SSLKEAType type) const { void TlsAgent::CheckAuthType(SSLAuthType type) const { EXPECT_EQ(STATE_CONNECTED, state_); - EXPECT_EQ(type, csinfo_.authAlgorithm); + EXPECT_EQ(type, csinfo_.authType); 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_rsa: + EXPECT_EQ(ssl_auth_rsa_decrypt, csinfo_.authAlgorithm) + << "authAlgorithm for ECDH_RSA is RSA decrypt (i.e., wrong)"; + break; + case ssl_auth_ecdh_ecdsa: + EXPECT_EQ(ssl_auth_ecdsa, csinfo_.authAlgorithm) + << "authAlgorithm for ECDH_ECDSA is ECDSA (i.e., wrong)"; + break; default: + EXPECT_EQ(type, csinfo_.authAlgorithm) + << "authAlgorithm is (usually) the same as authType"; break; } } diff --git a/external_tests/ssl_gtest/tls_agent.h b/external_tests/ssl_gtest/tls_agent.h index ee4368217..e1b524eeb 100644 --- a/external_tests/ssl_gtest/tls_agent.h +++ b/external_tests/ssl_gtest/tls_agent.h @@ -39,6 +39,11 @@ typedef std::function<void(TlsAgent& agent)> HandshakeCallbackFunction; +typedef + std::function<int32_t(TlsAgent& agent, const SECItem *srvNameArr, + PRUint32 srvNameArrSize)> + SniCallbackFunction; + class TlsAgent : public PollTarget { public: enum Role { CLIENT, SERVER }; @@ -74,6 +79,9 @@ class TlsAgent : public PollTarget { // Prepares for renegotiation, then actually triggers it. void StartRenegotiate(); void DisableCiphersByKeyExchange(SSLKEAType kea); + void EnableCiphersByAuthType(SSLAuthType authType); + void EnableSingleCipher(uint16_t cipher); + bool ConfigServerCert(const std::string& name, bool updateKeyBits = false); bool EnsureTlsSetup(); void SetupClientAuth(); @@ -174,6 +182,10 @@ class TlsAgent : public PollTarget { auth_certificate_callback_ = auth_certificate_callback; } + void SetSniCallback(SniCallbackFunction sni_callback) { + sni_callback_ = sni_callback; + } + private: const static char* states[]; @@ -204,7 +216,7 @@ class TlsAgent : public PollTarget { EXPECT_TRUE(agent->expect_client_auth_); EXPECT_TRUE(isServer); if (agent->auth_certificate_callback_) { - agent->auth_certificate_callback_(*agent, checksig, isServer); + return agent->auth_certificate_callback_(*agent, checksig, isServer); } return SECSuccess; } @@ -243,6 +255,9 @@ class TlsAgent : public PollTarget { agent->CheckPreliminaryInfo(); agent->sni_hook_called_ = true; EXPECT_EQ(1UL, srvNameArrSize); + if (agent->sni_callback_) { + return agent->sni_callback_(*agent, srvNameArr, srvNameArrSize); + } return 0; // First configuration. } @@ -297,6 +312,7 @@ class TlsAgent : public PollTarget { bool expected_read_error_; HandshakeCallbackFunction handshake_callback_; AuthCertificateCallbackFunction auth_certificate_callback_; + SniCallbackFunction sni_callback_; }; class TlsAgentTestBase : public ::testing::Test { diff --git a/external_tests/ssl_gtest/tls_connect.cc b/external_tests/ssl_gtest/tls_connect.cc index 103da7ec7..ff3cbe45b 100644 --- a/external_tests/ssl_gtest/tls_connect.cc +++ b/external_tests/ssl_gtest/tls_connect.cc @@ -219,6 +219,23 @@ void TlsConnectTestBase::Connect() { CheckConnected(); } +void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite) +{ + EnsureTlsSetup(); + client_->EnableSingleCipher(cipher_suite); + + 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()); @@ -291,6 +308,13 @@ void TlsConnectTestBase::DisableDheAndEcdheCiphers() { DisableEcdheCiphers(); } +void TlsConnectTestBase::EnableSomeEcdhCiphers() { + client_->EnableCiphersByAuthType(ssl_auth_ecdh_rsa); + client_->EnableCiphersByAuthType(ssl_auth_ecdh_ecdsa); + server_->EnableCiphersByAuthType(ssl_auth_ecdh_rsa); + server_->EnableCiphersByAuthType(ssl_auth_ecdh_ecdsa); +} + void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client, SessionResumptionMode server) { client_->ConfigureSessionCache(client); diff --git a/external_tests/ssl_gtest/tls_connect.h b/external_tests/ssl_gtest/tls_connect.h index ab9a5dc8b..70b6c9ba9 100644 --- a/external_tests/ssl_gtest/tls_connect.h +++ b/external_tests/ssl_gtest/tls_connect.h @@ -66,7 +66,8 @@ class TlsConnectTestBase : public ::testing::Test { void CheckConnected(); // Connect and expect it to fail. void ConnectExpectFail(); - void CheckKeys(SSLKEAType keyType, SSLAuthType authType) const; + void ConnectWithCipherSuite(uint16_t cipher_suite); + void CheckKeys(SSLKEAType akeyType, SSLAuthType authType) const; void SetExpectedVersion(uint16_t version); // Expect resumption of a particular type. @@ -74,6 +75,7 @@ class TlsConnectTestBase : public ::testing::Test { void DisableDheAndEcdheCiphers(); void DisableDheCiphers(); void DisableEcdheCiphers(); + void EnableSomeEcdhCiphers(); void EnableExtendedMasterSecret(); void ConfigureSessionCache(SessionResumptionMode client, SessionResumptionMode server); diff --git a/lib/pk11wrap/pk11auth.c b/lib/pk11wrap/pk11auth.c index 14aeffa2b..25ea97551 100644 --- a/lib/pk11wrap/pk11auth.c +++ b/lib/pk11wrap/pk11auth.c @@ -311,6 +311,9 @@ pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx) */ SECStatus PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) { + if (!slot) { + return SECFailure; + } if (pk11_LoginStillRequired(slot,wincx)) { return PK11_DoPassword(slot, slot->session, loadCerts, wincx, PR_FALSE, PR_FALSE); diff --git a/lib/ssl/SSLerrs.h b/lib/ssl/SSLerrs.h index 6ae620b61..7da916b62 100644 --- a/lib/ssl/SSLerrs.h +++ b/lib/ssl/SSLerrs.h @@ -290,7 +290,7 @@ 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 key exchange algorithm.") + "The certificate provided cannot be used with the selected authentication type.") ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA, (SSL_ERROR_BASE + 89), "No certificate authority is trusted for SSL client authentication.") diff --git a/lib/ssl/manifest.mn b/lib/ssl/manifest.mn index 4c466488d..267a69dc5 100644 --- a/lib/ssl/manifest.mn +++ b/lib/ssl/manifest.mn @@ -45,6 +45,7 @@ CSRCS = \ ssl3ecc.c \ tls13con.c \ tls13hkdf.c \ + sslcert.c \ $(NULL) LIBRARY_NAME = ssl diff --git a/lib/ssl/ssl.def b/lib/ssl/ssl.def index a05cb6071..26840c497 100644 --- a/lib/ssl/ssl.def +++ b/lib/ssl/ssl.def @@ -196,6 +196,7 @@ SSL_SetSignedCertTimestamps; ;+}; ;+NSS_3.23 { # NSS 3.23 release ;+ global: +SSL_ConfigServerCert; SSL_SetDowngradeCheckVersion; ;+ local: ;+*; diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index 30555e32a..2c9a8e0ea 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -596,6 +596,8 @@ SSL_IMPORT const SECItem *SSL_PeerSignedCertTimestamps(PRFileDesc *fd); * 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, @@ -608,6 +610,8 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, * 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, @@ -764,14 +768,72 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, ** 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); /* -** Allows SSL socket configuration with caller-supplied certificate chain. -** If certChainOpt is NULL, tries to find one. +** Deprecated variant of SSL_ConfigSecureServerCert. The |data| argument to +** SSL_ConfigSecureServerCert can be used to pass a certificate chain. */ SSL_IMPORT SECStatus SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, @@ -1003,7 +1065,8 @@ SSL_IMPORT SECStatus SSL_GetSRTPCipher(PRFileDesc *fd, 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); diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index 8ae7dbaf0..494c7cad3 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -308,29 +308,30 @@ static const ssl3BulkCipherDef bulk_cipher_defs[] = { static const ssl3KEADef kea_defs[] = { /* indexed by SSL3KeyExchangeAlgorithm */ - /* 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}, + /* 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}, #ifndef NSS_DISABLE_ECC - {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} + {kea_ecdh_ecdsa, ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh_ecdsa, 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_rsa, 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} #endif /* NSS_DISABLE_ECC */ }; @@ -479,13 +480,29 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] = }; /* clang-format on */ +static const CK_MECHANISM_TYPE auth_alg_defs[] = { + CKM_INVALID_MECHANISM, /* ssl_auth_null */ + CKM_RSA_PKCS, /* ssl_auth_rsa_decrypt */ + CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */ + CKM_INVALID_MECHANISM, /* ssl_auth_kea (unused) */ + CKM_ECDSA, /* ssl_auth_ecdsa */ + CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_rsa */ + CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_ecdsa */ + 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) */ +}; +PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size); + static const CK_MECHANISM_TYPE kea_alg_defs[] = { - 0x80000000L, - CKM_RSA_PKCS, - CKM_DH_PKCS_DERIVE, - CKM_KEA_KEY_DERIVE, - CKM_ECDH1_DERIVE + CKM_INVALID_MECHANISM, /* ssl_kea_null */ + CKM_RSA_PKCS, /* ssl_kea_rsa */ + CKM_DH_PKCS_DERIVE, /* ssl_kea_dh */ + CKM_INVALID_MECHANISM, /* 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; @@ -809,6 +826,27 @@ ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, ssl3CipherSuiteCfg *suites) 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. @@ -821,12 +859,12 @@ ssl3_config_match_init(sslSocket *ss) const ssl3CipherSuiteDef *cipher_def; SSLCipherAlgorithm cipher_alg; CK_MECHANISM_TYPE cipher_mech; - SSL3KEAType exchKeyType; + SSLAuthType authType; + SSLKEAType keaType; int i; int numPresent = 0; int numEnabled = 0; PRBool isServer; - sslServerCerts *svrAuth; PORT_Assert(ss); if (!ss) { @@ -852,50 +890,34 @@ ssl3_config_match_init(sslSocket *ss) } 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 = (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) + 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) { ++numPresent; + } } } PORT_Assert(numPresent > 0 || numEnabled == 0); @@ -939,8 +961,8 @@ config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled, 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].signKeyType == - ssl_sign_psk) { + if (kea_defs[cipher_def->key_exchange_alg].authKeyType == + ssl_auth_psk) { return tls13_AllowPskCipher(ss, cipher_def); } @@ -3910,8 +3932,8 @@ ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, * 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 == kt_dh) || - (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh)); + PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) || + (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh)); CK_MECHANISM_TYPE master_derive; CK_MECHANISM_TYPE key_derive; SECItem params; @@ -3987,9 +4009,9 @@ tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms, */ /* * 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 == kt_dh) || - (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh)); + * mode. Bug 1198298 */ + PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) || + (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh)); CK_MECHANISM_TYPE master_derive; CK_MECHANISM_TYPE key_derive; SECItem params; @@ -5900,7 +5922,7 @@ static PK11SymKey * ssl_UnwrapSymWrappingKey( SSLWrappedSymWrappingKey *pWswk, SECKEYPrivateKey *svrPrivKey, - SSL3KEAType exchKeyType, + SSLAuthType authType, CK_MECHANISM_TYPE masterWrapMech, void *pwArg) { @@ -5914,9 +5936,9 @@ ssl_UnwrapSymWrappingKey( /* found the wrapping key on disk. */ PORT_Assert(pWswk->symWrapMechanism == masterWrapMech); - PORT_Assert(pWswk->exchKeyType == exchKeyType); + PORT_Assert(pWswk->authType == authType); if (pWswk->symWrapMechanism != masterWrapMech || - pWswk->exchKeyType != exchKeyType) { + pWswk->authType != authType) { goto loser; } wrappedKey.type = siBuffer; @@ -5924,18 +5946,21 @@ ssl_UnwrapSymWrappingKey( wrappedKey.len = pWswk->wrappedSymKeyLen; PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey); - switch (exchKeyType) { + switch (authType) { - case kt_rsa: + case ssl_auth_rsa_decrypt: + case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */ unwrappedWrappingKey = - PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, - masterWrapMech, CKA_UNWRAP, 0); + PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, + masterWrapMech, CKA_UNWRAP, 0); break; #ifndef NSS_DISABLE_ECC - case kt_ecdh: + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: /* - * For kt_ecdh, we first create an EC public key based on + * For ssl_auth_ecd*, 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 @@ -5994,14 +6019,14 @@ 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 KEA 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 authentication type. These Symkeys * correspond to the wrapped SymKeys kept in the server session cache. */ typedef struct { - PK11SymKey *symWrapKey[kt_kea_size]; + PK11SymKey *symWrapKey[ssl_auth_size]; } ssl3SymWrapKey; static PZLock *symWrapKeysLock = NULL; @@ -6029,7 +6054,7 @@ SSL3_ShutdownServerCache(void) PZ_Lock(symWrapKeysLock); /* get rid of all symWrapKeys */ for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) { - for (j = 0; j < kt_kea_size; ++j) { + for (j = 0; j < ssl_auth_size; ++j) { PK11SymKey **pSymWrapKey; pSymWrapKey = &symWrapKeys[i].symWrapKey[j]; if (*pSymWrapKey) { @@ -6055,14 +6080,19 @@ ssl_InitSymWrapKeysLock(void) * 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, - SSL3KEAType exchKeyType, + const sslServerCert *serverCert, CK_MECHANISM_TYPE masterWrapMech, void *pwArg) { + SSLAuthType authType; SECKEYPrivateKey *svrPrivKey; SECKEYPublicKey *svrPubKey = NULL; PK11SymKey *unwrappedWrappingKey = NULL; @@ -6080,18 +6110,25 @@ ssl3_GetWrappingKey(sslSocket *ss, ECCWrappedKeyInfo *ecWrapped; #endif /* NSS_DISABLE_ECC */ - svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY; - PORT_Assert(svrPrivKey != NULL); - if (!svrPrivKey) { - return NULL; /* why are we here?!? */ + 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; symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech); PORT_Assert(symWrapMechIndex >= 0); if (symWrapMechIndex < 0) return NULL; /* invalid masterWrapMech. */ - pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[exchKeyType]; + pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType]; ssl_InitSessionCacheLocks(PR_TRUE); @@ -6110,10 +6147,10 @@ ssl3_GetWrappingKey(sslSocket *ss, /* Try to get wrapped SymWrapping key out of the (disk) cache. */ /* Following call fills in wswk on success. */ - if (ssl_GetWrappingKey(symWrapMechIndex, exchKeyType, &wswk)) { + if (ssl_GetWrappingKey(symWrapMechIndex, authType, &wswk)) { /* found the wrapped sym wrapping key on disk. */ unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType, + ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType, masterWrapMech, pwArg); if (unwrappedWrappingKey) { goto install; @@ -6138,13 +6175,7 @@ ssl3_GetWrappingKey(sslSocket *ss, */ PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */ - if (ss->serverCerts[exchKeyType].serverKeyPair) { - svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey; - } - if (svrPubKey == NULL) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - goto loser; - } + svrPubKey = serverCert->serverKeyPair->pubKey; wrappedKey.type = siBuffer; wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); wrappedKey.data = wswk.wrappedSymmetricWrappingkey; @@ -6154,15 +6185,18 @@ ssl3_GetWrappingKey(sslSocket *ss, goto loser; /* wrap symmetric wrapping key in server's public key. */ - switch (exchKeyType) { - case kt_rsa: + switch (authType) { + case ssl_auth_rsa_decrypt: + case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */ asymWrapMechanism = CKM_RSA_PKCS; rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey, unwrappedWrappingKey, &wrappedKey); break; #ifndef NSS_DISABLE_ECC - case kt_ecdh: + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: /* * We generate an ephemeral EC key pair. Perform an ECDH * computation involving this ephemeral EC public key and @@ -6267,7 +6301,7 @@ ssl3_GetWrappingKey(sslSocket *ss, wswk.symWrapMechanism = masterWrapMech; wswk.symWrapMechIndex = symWrapMechIndex; wswk.asymWrapMechanism = asymWrapMechanism; - wswk.exchKeyType = exchKeyType; + wswk.authType = authType; wswk.wrappedSymKeyLen = wrappedKey.len; /* put it on disk. */ @@ -6283,7 +6317,7 @@ ssl3_GetWrappingKey(sslSocket *ss, PK11_FreeSymKey(unwrappedWrappingKey); unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType, + ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType, masterWrapMech, pwArg); } @@ -6560,16 +6594,16 @@ ssl3_SendClientKeyExchange(sslSocket *ss) ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); switch (ss->ssl3.hs.kea_def->exchKeyType) { - case kt_rsa: + case ssl_kea_rsa: rv = sendRSAClientKeyExchange(ss, serverKey); break; - case kt_dh: + case ssl_kea_dh: rv = sendDHClientKeyExchange(ss, serverKey); break; #ifndef NSS_DISABLE_ECC - case kt_ecdh: + case ssl_kea_ecdh: rv = ssl3_SendECDHClientKeyExchange(ss, serverKey); break; #endif /* NSS_DISABLE_ECC */ @@ -7032,7 +7066,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, goto alert_loser; } - ss->sec.authAlgorithm = sid->authAlgorithm; + ss->sec.authType = sid->authType; ss->sec.authKeyBits = sid->authKeyBits; ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; @@ -7178,8 +7212,8 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, } ss->ssl3.hs.isResuming = PR_FALSE; - if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_null) { - /* All current cipher suites other than those with ssl_sign_null (i.e., + if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_null) { + /* All current cipher suites other than those with ssl_auth_null (i.e., * (EC)DH_anon_* suites) require a certificate, so use that signal. */ ss->ssl3.hs.ws = wait_server_cert; } else { @@ -7233,8 +7267,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); switch (ss->ssl3.hs.kea_def->exchKeyType) { - - case kt_rsa: { + case ssl_kea_rsa: { SECItem modulus = { siBuffer, NULL, 0 }; SECItem exponent = { siBuffer, NULL, 0 }; @@ -7270,8 +7303,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (length != 0) { if (isTLS) - desc = - decode_error; + desc = decode_error; goto alert_loser; /* malformed. */ } @@ -7327,7 +7359,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return SECSuccess; } - case kt_dh: { + case ssl_kea_dh: { SECItem dh_p = { siBuffer, NULL, 0 }; SECItem dh_g = { siBuffer, NULL, 0 }; SECItem dh_Ys = { siBuffer, NULL, 0 }; @@ -7383,8 +7415,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (length != 0) { if (isTLS) - desc = - decode_error; + desc = decode_error; goto alert_loser; /* malformed. */ } @@ -7447,7 +7478,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } #ifndef NSS_DISABLE_ECC - case kt_ecdh: + case ssl_kea_ecdh: rv = ssl3_HandleECDHServerKeyExchange(ss, b, length); return rv; #endif /* NSS_DISABLE_ECC */ @@ -8221,15 +8252,26 @@ ssl3_SendServerHelloSequence(sslSocket *ss) kea_def = ss->ssl3.hs.kea_def; ss->ssl3.hs.usedStepDownKey = PR_FALSE; - if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) { + if (kea_def->is_limited) { /* see if we can legally use the key in the cert. */ - unsigned int keyLen; /* bytes */ + 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); - keyLen = PK11_GetPrivateModulusLen( - ss->serverCerts[kea_def->exchKeyType].SERVERKEY); + cert = ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_sign); + if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) { + PORT_SetError(SSL_ERROR_NO_CERTIFICATE); + return SECFailure; + } - if (keyLen > 0 && - keyLen * BPB <= kea_def->key_size_limit) { + keyBits = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey); + PORT_Assert(keyBits); + + if (keyBits <= kea_def->key_size_limit) { /* XXX AND cert is not signing only!! */ /* just fall through and use it. */ } else if (ss->stepDownKeyPair != NULL) { @@ -8271,19 +8313,14 @@ ssl3_SendServerHelloSequence(sslSocket *ss) static const PRUint8 emptyRIext[5] = { 0xff, 0x01, 0x00, 0x01, 0x00 }; static PRBool -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; - }; +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; } /* Select a cipher suite. @@ -8497,6 +8534,46 @@ alert_loser: 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_ecdsa || + cert->certType.authType == ssl_auth_ecdh_rsa || + cert->certType.authType == ssl_auth_ecdh_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. @@ -8978,8 +9055,8 @@ static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss, } if (canOfferSessionTicket) - canOfferSessionTicket = ssl3_KEAAllowsSessionTicket( - ss->ssl3.hs.suite_def->key_exchange_alg); + canOfferSessionTicket = + ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def); if (canOfferSessionTicket) { ssl3_RegisterServerHelloExtensionSender(ss, @@ -9016,6 +9093,7 @@ compression_found: do { ssl3CipherSpec *pwSpec; SECItem wrappedMS; /* wrapped key */ + const sslServerCert *serverCert; if (sid->version != ss->version || sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || @@ -9023,6 +9101,14 @@ compression_found: break; /* not an error */ } + serverCert = ssl_FindServerCert(ss, &sid->certType); + if (!serverCert || !serverCert->serverCert) { + /* A compatible certificate must not have been configured. It + * might not be the same certificate, but we only find that out + * when the ticket fails to decrypt. */ + break; + } + /* [draft-ietf-tls-session-hash-06; Section 5.3] * o If the original session did not use the "extended_master_secret" * extension but the new ClientHello contains the extension, then the @@ -9073,7 +9159,7 @@ compression_found: } #endif - wrapKey = ssl3_GetWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType, + wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert, sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg); if (!wrapKey) { @@ -9082,8 +9168,7 @@ compression_found: } 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; @@ -9137,18 +9222,18 @@ compression_found: SSL_AtomicIncrementLong(&ssl3stats.hch_sid_stateless_resumes); ss->ssl3.hs.isResuming = PR_TRUE; - ss->sec.authAlgorithm = sid->authAlgorithm; + ss->sec.authType = sid->authType; ss->sec.authKeyBits = sid->authKeyBits; ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; /* server sids don't remember the server cert we previously sent, - ** but they do remember the kea type we originally used, so we + ** but they do remember the slot we originally used, so we ** can locate it again, provided that the current ssl socket ** has had its server certs configured the same as the previous one. */ - ss->sec.localCert = - CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert); + ss->sec.serverCert = serverCert; + ss->sec.localCert = CERT_DupCertificate(serverCert->serverCert); /* Copy cached name in to pending spec */ if (sid != NULL && @@ -9237,6 +9322,13 @@ compression_found: 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(); @@ -9470,6 +9562,13 @@ suite_found: 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); @@ -9650,7 +9749,7 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) ssl3KeyPair *keyPair = NULL; SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */ - int certIndex = -1; + SECKEYPrivateKey *certPrivateKey; 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. @@ -9703,16 +9802,9 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) 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); - rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY, - &signed_hash, isTLS); + certPrivateKey = ss->sec.serverCert->serverKeyPair->privKey; + rv = ssl3_SignHashes(&hashes, certPrivateKey, &signed_hash, isTLS); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ } @@ -9860,7 +9952,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss) } switch (kea_def->exchKeyType) { - case kt_rsa: + case ssl_kea_rsa: /* Perform SSL Step-Down here. */ sdPub = ss->stepDownKeyPair->pubKey; PORT_Assert(sdPub != NULL); @@ -9880,7 +9972,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss) } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].SERVERKEY, + rv = ssl3_SignHashes(&hashes, ss->sec.serverCert->serverKeyPair->privKey, &signed_hash, isTLS); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ @@ -9891,8 +9983,8 @@ ssl3_SendServerKeyExchange(sslSocket *ss) 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; @@ -9937,13 +10029,13 @@ ssl3_SendServerKeyExchange(sslSocket *ss) } #ifndef NSS_DISABLE_ECC - case kt_ecdh: { + case ssl_kea_ecdh: { rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash); return rv; } #endif /* NSS_DISABLE_ECC */ - case kt_null: + case ssl_kea_null: default: PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); break; @@ -10560,11 +10652,10 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (ss->ssl3.hs.usedStepDownKey) { PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */ - && - kea_def->exchKeyType == kt_rsa && - ss->stepDownKeyPair != NULL); + && kea_def->authKeyType == ssl_auth_rsa_sign + && ss->stepDownKeyPair != NULL); if (!kea_def->is_limited || - kea_def->exchKeyType != kt_rsa || + kea_def->authKeyType != ssl_auth_rsa_sign || ss->stepDownKeyPair == NULL) { /* shouldn't happen, don't use step down if it does */ goto skip; @@ -10573,38 +10664,27 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; } else skip: - if (kea_def->kea == kea_dhe_dss || - kea_def->kea == kea_dhe_rsa) { - if (ss->dheKeyPair) { + if (kea_def->ephemeral) { + if (kea_def->exchKeyType == ssl_kea_dh && ss->dheKeyPair) { serverKeyPair = ss->dheKeyPair; if (serverKeyPair->pubKey) { ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); } } - } else #ifndef NSS_DISABLE_ECC - /* 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) { + else if (kea_def->exchKeyType == ssl_kea_ecdh && + ss->ephemeralECDHKeyPair) { serverKeyPair = ss->ephemeralECDHKeyPair; if (serverKeyPair->pubKey) { ss->sec.keaKeyBits = - SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); + SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); } } - } else #endif - { - sslServerCerts *sc = ss->serverCerts + kea_def->exchKeyType; - serverKeyPair = sc->serverKeyPair; - ss->sec.keaKeyBits = sc->serverKeyBits; + } else { + serverKeyPair = ss->sec.serverCert->serverKeyPair; + ss->sec.keaKeyBits = ss->sec.serverCert->serverKeyBits; } if (serverKeyPair) { @@ -10620,7 +10700,7 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->sec.keaType = kea_def->exchKeyType; switch (kea_def->exchKeyType) { - case kt_rsa: + case ssl_kea_rsa: rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey); if (rv != SECSuccess) { SEND_ALERT @@ -10645,13 +10725,7 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) break; #ifndef NSS_DISABLE_ECC - 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. - */ + case ssl_kea_ecdh: if (serverKeyPair) { serverPubKey = serverKeyPair->pubKey; } @@ -10838,7 +10912,6 @@ ssl3_SendCertificate(sslSocket *ss) CERTCertificateList *certChain; int certChainLen = 0; int i; - SSL3KEAType certIndex; #ifdef NISCC_TEST SECItem fakeCert; int ndex = -1; @@ -10855,27 +10928,11 @@ ssl3_SendCertificate(sslSocket *ss) if (ss->sec.localCert) CERT_DestroyCertificate(ss->sec.localCert); if (ss->sec.isServer) { - 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); + /* 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); } else { certChain = ss->ssl3.clientCertChain; ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate); @@ -10962,7 +11019,7 @@ ssl3_SendCertificateStatus(sslSocket *ss) SECStatus rv; int len = 0; SECItemArray *statusToSend = NULL; - SSL3KEAType certIndex; + const sslServerCert *serverCert; SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake", SSL_GETPID(), ss->fd)); @@ -10975,14 +11032,9 @@ ssl3_SendCertificateStatus(sslSocket *ss) return SECSuccess; /* Use certStatus based on the cert being used. */ - 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]; + serverCert = ss->sec.serverCert; + if (serverCert->certStatusArray && serverCert->certStatusArray->len) { + statusToSend = serverCert->certStatusArray; } if (!statusToSend) return SECSuccess; @@ -11339,7 +11391,7 @@ ssl3_AuthCertificate(sslSocket *ss) /* set the server authentication type and size from the value ** in the cert. */ SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert); - ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType; + ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType; ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; if (pubKey) { KeyType pubKeyType; @@ -11806,7 +11858,7 @@ fail: */ SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec, SSL3KEAType effectiveExchKeyType) + ssl3CipherSpec *spec, SSLAuthType authType) { PK11SymKey *wrappingKey = NULL; PK11SlotInfo *symKeySlot; @@ -11814,6 +11866,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, 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; @@ -11859,7 +11912,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, mechanism = PK11_GetBestWrapMechanism(symKeySlot); if (mechanism != CKM_INVALID_MECHANISM) { wrappingKey = - ssl3_GetWrappingKey(ss, symKeySlot, effectiveExchKeyType, + ssl3_GetWrappingKey(ss, symKeySlot, ss->sec.serverCert, mechanism, pwArg); if (wrappingKey) { mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ @@ -11896,7 +11949,6 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, 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)); @@ -11973,7 +12025,7 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, */ if (isServer && !ss->ssl3.hs.isResuming && ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && - ssl3_KEAAllowsSessionTicket(ss->ssl3.hs.suite_def->key_exchange_alg)) { + ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def)) { /* 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 @@ -12021,15 +12073,8 @@ xmit_loser: 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, effectiveExchKeyType); + rv = ssl3_FillInCachedSID(ss, sid); /* If the wrap failed, we don't cache the sid. * The connection continues normally however. @@ -12053,8 +12098,7 @@ xmit_loser: } SECStatus -ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, - SSL3KEAType effectiveExchKeyType) +ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) { SECStatus rv; @@ -12067,15 +12111,19 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, #ifndef NSS_DISABLE_ECC sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves; #endif - sid->u.ssl3.exchKeyType = effectiveExchKeyType; sid->version = ss->version; - sid->authAlgorithm = ss->sec.authAlgorithm; + sid->authType = ss->sec.authType; sid->authKeyBits = ss->sec.authKeyBits; sid->keaType = ss->sec.keaType; sid->keaKeyBits = ss->sec.keaKeyBits; sid->lastAccessTime = sid->creationTime = ssl_Time(); sid->expirationTime = sid->creationTime + ssl3_sid_timeout; sid->localCert = CERT_DupCertificate(ss->sec.localCert); + if (ss->sec.isServer) { + memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType)); + } else { + sid->certType.authType = ssl_auth_null; + } ssl_GetSpecReadLock(ss); /*************************************/ @@ -12091,7 +12139,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, } else { rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid, ss->ssl3.crSpec, - effectiveExchKeyType); + ss->ssl3.hs.kea_def->authKeyType); sid->u.ssl3.keys.msIsWrapped = PR_TRUE; } ssl_ReleaseSpecReadLock(ss); /*************************************/ @@ -12155,7 +12203,7 @@ 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]; @@ -12525,7 +12573,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) } /* 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; } @@ -13339,15 +13387,21 @@ ssl3_CreateRSAStepDownKeys(sslSocket *ss) { SECStatus rv = SECSuccess; SECKEYPrivateKey *privKey; /* RSA step down key */ - SECKEYPublicKey *pubKey; /* RSA step down key */ + SECKEYPublicKey *pubKey; /* RSA step down key */ + const sslServerCert *cert; + unsigned int len; if (ss->stepDownKeyPair) ssl3_FreeKeyPair(ss->stepDownKeyPair); ss->stepDownKeyPair = NULL; #ifndef HACKED_EXPORT_SERVER + cert = ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_decrypt); + if (!cert || !cert->serverKeyPair) { + return SECFailure; + } + len = PK11_GetPrivateModulusLen(cert->serverKeyPair->privKey); /* Sigh, should have a get key strength call for private keys */ - if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].SERVERKEY) > - EXPORT_RSA_KEY_LENGTH) { + if (len > EXPORT_RSA_KEY_LENGTH) { /* need to ask for the key size in bits */ privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB, &pubKey, NULL); @@ -13578,7 +13632,7 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) 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; } diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c index a28362773..7fb7ad59b 100644 --- a/lib/ssl/ssl3ecc.c +++ b/lib/ssl/ssl3ecc.c @@ -40,15 +40,6 @@ (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)) @@ -593,43 +584,44 @@ ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits) ECName ssl3_GetCurveNameForServerSocket(sslSocket *ss) { - SECKEYPublicKey *svrPublicKey = NULL; ECName ec_curve = ec_noName; - int signatureKeyStrength = 521; + const sslServerCert *cert = ss->sec.serverCert; + int certKeySize; int requiredECCbits = ss->sec.secretKeyBits * 2; - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) { - svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh); - if (svrPublicKey) - ec_curve = ssl3_PubKey2ECName(svrPublicKey); - if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return ec_noName; - } - signatureKeyStrength = curve2bits[ec_curve]; - } else { - /* RSA is our signing cert */ - int serverKeyStrengthInBits; + PORT_Assert(cert); + if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return ec_noName; + } - svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa); - if (!svrPublicKey) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + if (cert->certType.authType == ssl_auth_rsa_sign) { + certKeySize + = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey); + certKeySize = + SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize); + } else if (cert->certType.authType == ssl_auth_ecdsa || + cert->certType.authType == ssl_auth_ecdh_rsa || + cert->certType.authType == ssl_auth_ecdh_ecdsa) { + ec_curve = cert->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(ec_curve != ec_noName); + PORT_Assert(SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, + ec_curve)); + if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, + ec_curve)) { return ec_noName; } - - /* 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); + certKeySize = curve2bits[ec_curve]; + } else { + PORT_Assert(0); + return ec_noName; + } + if (requiredECCbits > certKeySize) { + requiredECCbits = certKeySize; } - if (requiredECCbits > signatureKeyStrength) - requiredECCbits = signatureKeyStrength; return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves, requiredECCbits); @@ -920,7 +912,6 @@ ssl3_SendECDHServerKeyExchange( sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash) { - const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; SECStatus rv = SECFailure; int length; PRBool isTLS, isTLS12; @@ -931,7 +922,7 @@ ssl3_SendECDHServerKeyExchange( SECItem ec_params = { siBuffer, NULL, 0 }; unsigned char paramBuf[3]; ECName curve; - SSL3KEAType certIndex; + ssl3KeyPair *keyPair; /* Generate ephemeral ECDH key pair and send the public key */ curve = ssl3_GetCurveNameForServerSocket(ss); @@ -981,17 +972,8 @@ ssl3_SendECDHServerKeyExchange( isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - /* 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); + keyPair = ss->sec.serverCert->serverKeyPair; + rv = ssl3_SignHashes(&hashes, keyPair->privKey, &signed_hash, isTLS); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ } @@ -1045,20 +1027,6 @@ loser: /* Lists of ECC cipher suites for searching and disabling. */ -static const ssl3CipherSuite ecdh_suites[] = { - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_ECDSA_WITH_NULL_SHA, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS_ECDH_RSA_WITH_NULL_SHA, - TLS_ECDH_RSA_WITH_RC4_128_SHA, - 0 /* end of list marker */ -}; - static const ssl3CipherSuite ecdh_ecdsa_suites[] = { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, @@ -1144,51 +1112,37 @@ ssl3_DisableECCSuites(sslSocket *ss, const ssl3CipherSuite *suite) return SECSuccess; } +static PRBool +ssl_HasCertOfAuthType(sslSocket *ss, SSLAuthType authType) { + const sslServerCert* sc; + + sc = ssl_FindServerCertByAuthType(ss, authType); + return sc && sc->serverCert; +} + /* 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) { - CERTCertificate *svrCert; - - svrCert = ss->serverCerts[kt_rsa].serverCert; - if (!svrCert) { + if (!ssl_HasCertOfAuthType(ss, ssl_auth_rsa_sign)) { ssl3_DisableECCSuites(ss, ecdhe_rsa_suites); } - svrCert = ss->serverCerts[kt_ecdh].serverCert; - if (!svrCert) { - ssl3_DisableECCSuites(ss, ecdh_suites); + if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdsa)) { ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); - } else { - 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: - case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: - case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: - ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); - break; - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: - ssl3_DisableECCSuites(ss, ecdh_rsa_suites); - break; - default: - ssl3_DisableECCSuites(ss, ecdh_suites); - break; - } + } + + if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdh_rsa)) { + ssl3_DisableECCSuites(ss, ecdh_rsa_suites); + } + + if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdh_ecdsa)) { + ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); } } @@ -1419,24 +1373,6 @@ ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type, 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. */ @@ -1446,7 +1382,10 @@ ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) PRInt32 list_len; PRUint32 peerCurves = 0; PRUint32 mutualCurves = 0; - PRUint16 svrCertCurveName; + PRCList *cursor; + PRBool foundECDH_RSA = PR_FALSE; + PRBool foundECDH_ECDSA = PR_FALSE; + PRBool foundECDSA = PR_FALSE; if (!data->data || data->len < 4) { (void)ssl3_DecodeError(ss); @@ -1478,19 +1417,38 @@ ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) return SECSuccess; } - /* if our ECC cert doesn't use one of these supported curves, + /* if we don't have a cert with one of these curves, * disable ECC cipher suites that require an ECC cert. */ - svrCertCurveName = ssl3_GetSvrCertCurveName(ss); - if (svrCertCurveName != ec_noName && - (mutualCurves & (1U << svrCertCurveName)) != 0) { - return SECSuccess; + 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_rsa + && (mutualCurves & (1U << cert->certType.u.namedCurve))) { + foundECDH_RSA = PR_TRUE; + } + if (cert->certType.authType == ssl_auth_ecdh_ecdsa + && (mutualCurves & (1U << cert->certType.u.namedCurve))) { + foundECDH_ECDSA = PR_TRUE; + } + if (cert->certType.authType == ssl_auth_ecdsa + && (mutualCurves & (1U << cert->certType.u.namedCurve))) { + foundECDSA = PR_TRUE; + } } /* Our EC cert doesn't contain a mutually supported curve. - * Disable all ECC cipher suites that require an EC cert + * Disable the affected cipher suites. */ - ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); - ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); + if (!foundECDH_RSA) { + ssl3_DisableECCSuites(ss, ecdh_rsa_suites); + } + if (!foundECDH_ECDSA) { + ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); + } + if (!foundECDSA) { + ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); + } return SECSuccess; } diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c index 27f15eeab..df3e134d8 100644 --- a/lib/ssl/ssl3ext.c +++ b/lib/ssl/ssl3ext.c @@ -190,9 +190,20 @@ ssl3_GenerateSessionTicketKeysPKCS11(void *data) { SECStatus rv; sslSocket *ss = (sslSocket *)data; - SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY; - SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].serverKeyPair->pubKey; - + 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; if (svrPrivKey == NULL || svrPubKey == NULL) { SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.", SSL_GETPID(), ss->fd)); @@ -326,6 +337,10 @@ static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = { * 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] = { @@ -1025,22 +1040,11 @@ ssl3_ServerSendStatusRequestXtn( PRUint32 maxBytes) { PRInt32 extension_length; - SSLKEAType effectiveExchKeyType; + const sslServerCert *serverCert = ss->sec.serverCert; SECStatus rv; - /* 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) { + if (!serverCert->certStatusArray || + !serverCert->certStatusArray->len) { return 0; } @@ -1135,7 +1139,6 @@ ssl3_SendNewSessionTicket(sslSocket *ss) 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; @@ -1210,15 +1213,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) 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, - effectiveExchKeyType); + ss->ssl3.hs.kea_def->authKeyType); if (rv == SECSuccess) { if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) goto loser; @@ -1245,8 +1241,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) + 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 */ @@ -1299,7 +1295,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) goto loser; /* cipher spec parameters */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authAlgorithm, 1); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1); if (rv != SECSuccess) goto loser; rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); @@ -1312,13 +1308,29 @@ ssl3_SendNewSessionTicket(sslSocket *ss) 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_rsa: + case ssl_auth_ecdh_ecdsa: + /* 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; @@ -1409,6 +1421,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) } else #endif { + PORT_Assert(aes_key_pkcs11); aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, aes_key_pkcs11, &ivItem); if (!aes_ctx_pkcs11) @@ -1430,6 +1443,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) /* 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, @@ -1447,6 +1462,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) #endif { SECItem macParam; + PORT_Assert(mac_key_pkcs11); macParam.data = NULL; macParam.len = 0; hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, @@ -1787,7 +1803,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); if (temp < 0) goto no_ticket; - parsed_session_ticket->authAlgorithm = (SSLSignType)temp; + parsed_session_ticket->authType = (SSLAuthType)temp; temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); if (temp < 0) goto no_ticket; @@ -1801,16 +1817,28 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) goto no_ticket; parsed_session_ticket->keaKeyBits = (PRUint32)temp; - /* Read wrapped master_secret. */ + /* 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; - parsed_session_ticket->ms_is_wrapped = (PRBool)temp; + switch (parsed_session_ticket->authType) { +#ifndef NSS_DISABLE_ECC + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: + 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->exchKeyType = (SSL3KEAType)temp; + parsed_session_ticket->ms_is_wrapped = (PRBool)temp; temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); if (temp < 0) @@ -1907,15 +1935,18 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) 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->authAlgorithm = parsed_session_ticket->authAlgorithm; + sid->authType = parsed_session_ticket->authType; sid->authKeyBits = parsed_session_ticket->authKeyBits; sid->keaType = parsed_session_ticket->keaType; sid->keaKeyBits = parsed_session_ticket->keaKeyBits; - if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket, - &extension_data) != SECSuccess) - goto no_ticket; + 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. */ + /* Copy master secret. */ #ifndef NO_PKCS11_BYPASS if (ss->opt.bypassPKCS11 && parsed_session_ticket->ms_is_wrapped) @@ -1929,7 +1960,6 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) 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; @@ -2956,17 +2986,7 @@ ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss, PRUint32 maxBytes) { PRInt32 extension_length; - 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]; + const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps; if (!scts->len) { /* No timestamps to send */ @@ -3235,6 +3255,7 @@ tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append, 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 diff --git a/lib/ssl/sslcert.c b/lib/ssl/sslcert.c new file mode 100644 index 000000000..3ab7712bf --- /dev/null +++ b/lib/ssl/sslcert.c @@ -0,0 +1,960 @@ +/* -*- 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) { + continue; + } + switch (cert->certType.authType) { +#ifndef NSS_DISABLE_ECC + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: + /* Note: For deprecated APIs, we need to be able to find and + match a slot with any named curve or sign type. */ + if (certType->u.namedCurve != ec_noName && + cert->certType.u.namedCurve != certType->u.namedCurve) { + continue; + } + break; +#endif + default: + break; + } + return cert; + } + return NULL; +} + +sslServerCert * +ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType) +{ + sslServerCertType certType; + certType.authType = authType; + switch (authType) { +#ifndef NSS_DISABLE_ECC + /* Setting the named curve to ec_noName ensures that all EC certificates + * are matched when searching for this slot. */ + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: + 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; +} + +/* Determine which slot a certificate fits into. SSLAuthType is known, but + * extra information needs to be worked out from the cert and key. */ +static void +ssl_PopulateCertType(sslServerCertType *certType, SSLAuthType authType, + CERTCertificate *cert, ssl3KeyPair *keyPair) +{ + certType->authType = authType; +#ifndef NSS_DISABLE_ECC + switch (authType) { + case ssl_auth_ecdsa: + case ssl_auth_ecdh_rsa: + case ssl_auth_ecdh_ecdsa: + certType->u.namedCurve = ssl3_PubKey2ECName(keyPair->pubKey); + break; + default: + break; + } +#endif +} + +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) { + 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; + sslServerCertType certType; + SECStatus rv; + sslServerCert *sc = NULL; + int error_code = SEC_ERROR_NO_MEMORY; + + PORT_Assert(cert); + PORT_Assert(keyPair); + PORT_Assert(data); + PORT_Assert(data->authType != ssl_auth_null); + + if (!cert || !keyPair || !data || data->authType == ssl_auth_null) { + error_code = SEC_ERROR_INVALID_ARGS; + goto loser; + } + + ssl_PopulateCertType(&certType, data->authType, cert, keyPair); + + /* Delete any existing certificate that matches this one, since we can only + * use one certificate of a given type. */ + oldsc = ssl_FindServerCert(ss, &certType); + if (oldsc) { + PR_REMOVE_LINK(&oldsc->link); + ssl_FreeServerCert(oldsc); + } + sc = ssl_NewServerCert(&certType); + if (!sc) { + goto loser; + } + + rv = ssl_PopulateServerCert(sc, cert, data->certChain); + if (rv != SECSuccess) { + goto loser; + } + rv = ssl_PopulateKeyPair(sc, keyPair); + if (rv != SECSuccess) { + error_code = SEC_ERROR_INVALID_ARGS; + 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 setup depends on having the certificate in place. */ + rv = ssl_OneTimeCertSetup(ss, sc); + if (rv != SECSuccess) { + PR_REMOVE_LINK(&sc->link); + error_code = PORT_GetError(); + goto loser; + } + return SECSuccess; + +loser: + if (sc) { + ssl_FreeServerCert(sc); + } + /* This is the only way any of the calls above can fail, except the one time + * setup, which doesn't land here. */ + PORT_SetError(error_code); + return SECFailure; +} + +static SSLAuthType +ssl_GetEcdhAuthType(CERTCertificate *cert) { + SECOidTag sigTag = SECOID_GetAlgorithmTag(&cert->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: + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + return ssl_auth_ecdh_rsa; + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: + return ssl_auth_ecdh_ecdsa; + default: + return ssl_auth_null; + } +} + +/* This function examines the 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 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, ssl_sign_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: + if (cert->keyUsage & KU_KEY_ENCIPHERMENT) { + if ((cert->keyUsage & KU_DIGITAL_SIGNATURE) && + arg.authType == ssl_auth_null) { + /* See above regarding bad practice. */ + arg.authType = ssl_auth_ecdsa; + rv = ssl_ConfigCert(ss, cert, keyPair, &arg); + if (rv != SECSuccess) { + return rv; + } + } + + arg.authType = ssl_GetEcdhAuthType(cert); + } else if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { + arg.authType = ssl_auth_ecdsa; + } + break; +#endif /* NSS_DISABLE_ECC */ + + default: + break; + } + + /* Check that we successfully picked an authType */ + if (arg.authType == ssl_auth_null) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + /* |data->authType| has to either agree or be ssl_auth_null. */ + if (data->authType != ssl_auth_null && data->authType != arg.authType) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + return ssl_ConfigCert(ss, cert, keyPair, &arg); +} + +/* 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; + SECStatus rv; + SSLExtraServerCertData dataCopy = { + ssl_auth_null, NULL, NULL, NULL + }; + + ss = ssl_FindSocket(fd); + if (!ss) { + return SECFailure; + } + + if (!cert || !key) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (data) { + if (data_len > sizeof(dataCopy)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + PORT_Memcpy(&dataCopy, data, data_len); + } + + pubKey = CERT_ExtractPublicKey(cert); + if (!pubKey) { + return SECFailure; + } + + keyPair = ssl_MakeKeyPairForCert(key, pubKey); + if (!keyPair) { + /* pubKey is adopted by ssl_MakeKeyPairForCert() */ + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy); + ssl3_FreeKeyPair(keyPair); + return rv; +} + +/*******************************************************************/ +/* 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_rsa: + case ssl_auth_ecdh_ecdsa: +#ifndef NSS_DISABLE_ECC + return tag == SEC_OID_ANSIX962_EC_PUBLIC_KEY; +#endif + 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, or it makes a new + * server cert slot of the right type. */ +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_rsa: + case ssl_auth_ecdh_ecdsa: + /* 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)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + sc = ssl_FindOrMakeCertType(ss, authType); + if (!sc) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + rv = ssl_PopulateKeyPair(sc, keyPair); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + /* Now that we have a key pair, update the details of the slot. Many of the + * legacy functions create a slot with a namedCurve of ec_noName, which + * makes the slot unusable; this corrects that. */ + ssl_PopulateCertType(&sc->certType, authType, cert, keyPair); + rv = ssl_PopulateServerCert(sc, cert, certChainOpt); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto loser; + } + PR_APPEND_LINK(&sc->link, &ss->serverCerts); + return ssl_OneTimeCertSetup(ss, sc); +loser: + ssl_FreeServerCert(sc); + return SECFailure; +} + +static SECStatus +ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert, + const CERTCertificateList *certChainOpt, + SECKEYPrivateKey *key, SSLKEAType certType) +{ + SECKEYPublicKey *pubKey; + 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. */ + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + switch (certType) { + case ssl_kea_rsa: + rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt, + cert, certChainOpt, keyPair); + if (rv != SECSuccess) { + return SECFailure; + } + rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign, + cert, certChainOpt, keyPair); + break; + + case ssl_kea_dh: + rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa, + cert, certChainOpt, keyPair); + break; + +#ifndef NSS_DISABLE_ECC + case ssl_kea_ecdh: + rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdsa, + cert, certChainOpt, keyPair); + if (rv != SECSuccess) { + return SECFailure; + } + rv = ssl_AddCertAndKeyByAuthType(ss, ssl_GetEcdhAuthType(cert), + cert, certChainOpt, keyPair); + break; +#endif + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + break; + } + + ssl3_FreeKeyPair(keyPair); + return rv; +} + +/* 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) { + 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_rsa); + ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_ecdsa); + 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) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + rv = ssl_PopulateOCSPResponses(sc, responses); + if (rv == SECSuccess) { + PR_APPEND_LINK(&sc->link, &ss->serverCerts); + } else { + ssl_FreeServerCert(sc); + } + return rv; +} + +/* 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; + } + rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_rsa, responses); + if (rv != SECSuccess) { + return SECFailure; + } + return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_ecdsa, 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) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + 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; + } + rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts); + if (rv != SECSuccess) { + return SECFailure; + } + return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, 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; + } +} diff --git a/lib/ssl/sslcert.h b/lib/ssl/sslcert.h new file mode 100644 index 000000000..75074f25b --- /dev/null +++ b/lib/ssl/sslcert.h @@ -0,0 +1,62 @@ +/* -*- 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_ecdsa or ssl_auth_ecdh_*) 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_ecdsa and ssl_auth_ecdh_*. This is only the named curve + * of the end-entity certificate key. The keys in other certificates in + * the chain aren't directly relevant to the operation of TLS (though it + * might make certificate validation difficult, libssl doesn't care). */ + 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_ */ diff --git a/lib/ssl/sslcon.c b/lib/ssl/sslcon.c index c4c1a4c3e..0c48c8f1f 100644 --- a/lib/ssl/sslcon.c +++ b/lib/ssl/sslcon.c @@ -1,5 +1,5 @@ /* - * SSL v2 handshake functions, and functions common to SSL2 and SSL3. + * Basic SSL handshake 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 diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index f97196238..0f701b950 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -36,7 +36,6 @@ ** 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 @@ -152,6 +151,45 @@ typedef enum { SSLAppOpRead = 0, /* 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; @@ -332,16 +370,6 @@ typedef enum { sslHandshakingUndetermined = 0, 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 @@ -577,6 +605,8 @@ typedef enum { never_cached, 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. @@ -594,6 +624,7 @@ struct sslSessionIDStr { SECItemArray peerCertStatus; /* client only */ const char *peerID; /* client only */ const char *urlSvrName; /* client only */ + sslServerCertType certType; CERTCertificate *localCert; PRIPv6Addr addr; @@ -604,7 +635,7 @@ struct sslSessionIDStr { PRUint32 creationTime; /* seconds since Jan 1, 1970 */ PRUint32 expirationTime; /* seconds since Jan 1, 1970 */ - SSLSignType authAlgorithm; + SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; @@ -621,9 +652,6 @@ struct sslSessionIDStr { 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 */ @@ -696,9 +724,15 @@ typedef struct ssl3CipherSuiteDefStr { ** There are tables of these, all const. */ typedef struct { + /* An identifier for this struct. */ SSL3KeyExchangeAlgorithm kea; - SSL3KEAType exchKeyType; + /* The type of key exchange used by the cipher suite. */ + SSLKEAType exchKeyType; + /* If the cipher suite uses a signature, the type of signature. */ 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. */ @@ -1049,7 +1083,7 @@ typedef struct SSLWrappedSymWrappingKeyStr { CK_MECHANISM_TYPE asymWrapMechanism; /* mechanism used to wrap the SymmetricWrappingKey using * server's public and/or private keys. */ - SSL3KEAType exchKeyType; /* type of keys used to wrap SymWrapKey*/ + SSLAuthType authType; /* type of keys used to wrap SymWrapKey*/ PRInt32 symWrapMechIndex; PRUint16 wrappedSymKeyLen; } SSLWrappedSymWrappingKey; @@ -1059,16 +1093,15 @@ typedef struct SessionTicketStr { SSL3ProtocolVersion ssl_version; ssl3CipherSuite cipher_suite; SSLCompressionMethod compression_method; - SSLSignType authAlgorithm; + SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; + sslServerCertType certType; /* - * exchKeyType and msWrapMech contain meaningful values only if - * ms_is_wrapped is true. + * msWrapMech contains a meaningful value 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]; @@ -1120,10 +1153,12 @@ struct sslSecurityInfoStr { CERTCertificate *peerCert; SECKEYPublicKey *peerKey; - SSLSignType authAlgorithm; + SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; + /* The selected certificate (for servers only). */ + const sslServerCert *serverCert; /* ** Procs used for SID cache (nonce) management. @@ -1248,15 +1283,8 @@ struct sslSocketStr { sslBuffer pendingBuf; /*xmitBufLock*/ /* Configuration state for server sockets */ - /* 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]; + /* One server cert and key for each authentication type. */ + PRCList /* <sslServerCert> */ serverCerts; ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED]; ssl3KeyPair *ephemeralECDHKeyPair; /* for ECDHE-* handshake */ @@ -1623,6 +1651,11 @@ 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) \ @@ -1633,41 +1666,6 @@ extern PRUint32 ssl3_GetSupportedECCurveMask(sslSocket *ss); : 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); @@ -1755,9 +1753,9 @@ extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, SECItem *buf, PRBool isTLS, void *pwArg); -extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss, - sslSessionID *sid, ssl3CipherSpec *spec, - SSL3KEAType effectiveExchKeyType); +extern SECStatus ssl3_CacheWrappedMasterSecret( + sslSocket *ss, sslSessionID *sid, + ssl3CipherSpec *spec, SSLAuthType authType); /* Functions that handle ClientHello and ServerHello extensions. */ extern SECStatus ssl3_HandleServerNameXtn(sslSocket *ss, @@ -1784,14 +1782,6 @@ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append, 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); @@ -1819,7 +1809,7 @@ 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 (0x0101) +#define TLS_EX_SESS_TICKET_VERSION (0x0102) extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length); @@ -1844,8 +1834,7 @@ extern void ssl3_FreeKeyPair(ssl3KeyPair *keyPair); /* calls for accessing wrapping keys across processes. */ extern PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, +ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType, SSLWrappedSymWrappingKey *wswk); /* The caller passes in the new value it wants @@ -1949,16 +1938,16 @@ PK11SymKey *tls13_ComputeECDHSharedKey(sslSocket *ss, SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags); PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, - SSL3KEAType exchKeyType, + const sslServerCert *serverCert, 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, - SSL3KEAType effectiveExchKeyType); +SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid); const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite); +SECStatus ssl3_SelectServerCert(sslSocket *ss); /* Pull in TLS 1.3 functions */ #include "tls13con.h" diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c index 6a8fec144..08b0b9a49 100644 --- a/lib/ssl/sslinfo.c +++ b/lib/ssl/sslinfo.c @@ -134,22 +134,38 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, return SECSuccess; } -#define CS(x) x, #x -#define CK(x) x | 0xff00, #x +/* name */ +#define CS_(x) x, #x +#define CS(x) CS_(TLS_##x) +/* legacy values for authAlgorithm */ #define S_DSA "DSA", ssl_auth_dsa -#define S_RSA "RSA", ssl_auth_rsa -#define S_KEA "KEA", ssl_auth_kea +/* 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_ECDSA "ECDSA", ssl_auth_ecdsa #define S_PSK "PSK", ssl_auth_psk -#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 - +/* 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_R ssl_auth_ecdh_rsa +#define A_ECDH_E ssl_auth_ecdh_ecdsa +/* 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 + +/* 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 @@ -162,6 +178,7 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, #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 @@ -171,98 +188,104 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, #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 -/* clang-format off */ +/* 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 */ + static const SSLCipherSuiteInfo suiteInfo[] = { /* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */ - {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(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(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(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(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(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 }, + { 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(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(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(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(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(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 }, #ifndef NSS_DISABLE_ECC /* ECC cipher suites */ - {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(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(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(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(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 }, + { 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(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_E }, + { 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_E }, + { 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_E }, + { 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_E }, + { 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_E }, + + { 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(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_R }, + { 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_R }, + { 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_R }, + { 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_R }, + { 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_R }, + + { 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 }, #endif /* NSS_DISABLE_ECC */ }; -/* clang-format on */ #define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0])) diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c index a3383f64e..6c26c7e87 100644 --- a/lib/ssl/sslsecur.c +++ b/lib/ssl/sslsecur.c @@ -623,260 +623,6 @@ done: /************************************************************************/ -/* -** 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) { diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c index 81c85328a..bcadb242b 100644 --- a/lib/ssl/sslsnce.c +++ b/lib/ssl/sslsnce.c @@ -33,7 +33,7 @@ * sidCacheSet sidCacheSets[ numSIDCacheSets ]; * sidCacheEntry sidCacheData[ numSIDCacheEntries]; * certCacheEntry certCacheData[numCertCacheEntries]; - * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; + * SSLWrappedSymWrappingKey keyCacheData[ssl_auth_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 @@ -98,7 +98,7 @@ struct sidCacheEntryStr { /* 1 */ PRUint8 valid; /* 1 */ PRUint8 sessionIDLength; /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; - /* 2 */ PRUint16 authAlgorithm; + /* 2 */ PRUint16 authType; /* 2 */ PRUint16 authKeyBits; /* 2 */ PRUint16 keaType; /* 2 */ PRUint16 keaKeyBits; @@ -112,11 +112,11 @@ struct { /* 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 */ -/*108 */} ssl3; + /* 2 */ PRUint16 certTypeArgs; +/*104 */} ssl3; /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ struct { @@ -436,7 +436,7 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->creationTime = from->creationTime; to->lastAccessTime = from->lastAccessTime; to->expirationTime = from->expirationTime; - to->authAlgorithm = from->authAlgorithm; + to->authType = from->authType; to->authKeyBits = from->authKeyBits; to->keaType = from->keaType; to->keaKeyBits = from->keaKeyBits; @@ -445,12 +445,24 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) 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_rsa: + case ssl_auth_ecdh_ecdsa: + 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", @@ -481,7 +493,6 @@ ConvertToSID(sidCacheEntry *from, 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; @@ -526,6 +537,19 @@ ConvertToSID(sidCacheEntry *from, 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_rsa: + case ssl_auth_ecdh_ecdsa: + to->certType.u.namedCurve = + (ECName)from->u.ssl3.certTypeArgs; + break; +#endif + default: + break; + } to->version = from->version; to->creationTime = from->creationTime; @@ -534,7 +558,7 @@ ConvertToSID(sidCacheEntry *from, to->cached = in_server_cache; to->addr = from->addr; to->references = 1; - to->authAlgorithm = from->authAlgorithm; + to->authType = from->authType; to->authKeyBits = from->authKeyBits; to->keaType = from->keaType; to->keaKeyBits = from->keaKeyBits; @@ -972,7 +996,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->certCacheSize = (char *)cache->keyCacheData - (char *)cache->certCacheData; - cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS; + cache->numKeyCacheEntries = ssl_auth_size * SSL_NUM_WRAP_MECHS; ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); @@ -1604,12 +1628,12 @@ StopLockPoller(cacheDesc *cache) */ static PRBool getSvrWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, + SSLAuthType authType, SSLWrappedSymWrappingKey *wswk, cacheDesc *cache, PRUint32 lockTime) { - PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; + PRUint32 ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx; PRUint32 now = 0; PRBool rv = PR_FALSE; @@ -1624,7 +1648,7 @@ getSvrWrappingKey(PRInt32 symWrapMechIndex, return rv; } } - if (pwswk->exchKeyType == exchKeyType && + if (pwswk->authType == authType && pwswk->symWrapMechIndex == symWrapMechIndex && pwswk->wrappedSymKeyLen != 0) { *wswk = *pwswk; @@ -1638,16 +1662,16 @@ getSvrWrappingKey(PRInt32 symWrapMechIndex, PRBool ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, + SSLAuthType authType, SSLWrappedSymWrappingKey *wswk) { PRBool rv; - PORT_Assert((unsigned)exchKeyType < kt_kea_size); - PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)exchKeyType < kt_kea_size && + PORT_Assert( (unsigned)authType < ssl_auth_size); + PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); + if ((unsigned)authType < ssl_auth_size && (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { - rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, + rv = getSvrWrappingKey(symWrapMechIndex, authType, wswk, &globalCache, 0); } else { rv = PR_FALSE; @@ -1928,7 +1952,7 @@ ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) { cacheDesc *cache = &globalCache; PRBool rv = PR_FALSE; - SSL3KEAType exchKeyType = wswk->exchKeyType; + SSLAuthType authType = wswk->authType; /* type of keys used to wrap SymWrapKey*/ PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; PRUint32 ndx; @@ -1940,20 +1964,20 @@ ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) return 0; } - PORT_Assert((unsigned)exchKeyType < kt_kea_size); - if ((unsigned)exchKeyType >= kt_kea_size) + PORT_Assert((unsigned)authType < ssl_auth_size); + if ((unsigned)authType >= ssl_auth_size) return 0; PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) return 0; - ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; + ndx = (authType * 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->exchKeyType, + rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->authType, &myWswk, cache, now); if (rv) { /* we found it on disk, copy it out to the caller. */ @@ -2003,7 +2027,7 @@ SSL_InheritMPServerSIDCache(const char *envString) PRBool ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, + SSLAuthType authType, SSLWrappedSymWrappingKey *wswk) { PRBool rv = PR_FALSE; diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c index 12735557f..b970133ae 100644 --- a/lib/ssl/sslsock.c +++ b/lib/ssl/sslsock.c @@ -216,6 +216,7 @@ ssl_DupSocket(sslSocket *os) { sslSocket *ss; SECStatus rv; + sslServerCert *sc = NULL; ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant); if (ss) { @@ -258,14 +259,13 @@ ssl_DupSocket(sslSocket *os) } if (ss->opt.useSecurity) { - /* This int should be SSLKEAType, but CC on Irix complains, - * during the for loop. - */ - int i; - sslServerCerts *oc = os->serverCerts; - sslServerCerts *sc = ss->serverCerts; + 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); - 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); @@ -275,16 +275,26 @@ ssl_DupSocket(sslSocket *os) 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; - ss->certStatusArray[i] = !os->certStatusArray[i] ? NULL : SECITEM_DupArray(NULL, os->certStatusArray[i]); + 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->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); + 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->dheParams = os->dheParams; /* @@ -316,6 +326,7 @@ ssl_DupSocket(sslSocket *os) loser: ssl_FreeSocket(ss); + ssl_FreeServerCert(sc); return NULL; } @@ -358,10 +369,7 @@ ssl_DestroyLocks(sslSocket *ss) static void ssl_DestroySocketContents(sslSocket *ss) { - /* "i" should be of type SSLKEAType, but CC on IRIX complains during - * the for loop. - */ - int i; + PRCList *cursor; /* Free up socket */ ssl_DestroySecurityInfo(&ss->sec); @@ -377,22 +385,11 @@ ssl_DestroySocketContents(sslSocket *ss) if (ss->url != NULL) PORT_Free((void *)ss->url); /* CONST */ - /* 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); - } + /* 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); } if (ss->stepDownKeyPair) { ssl3_FreeKeyPair(ss->stepDownKeyPair); @@ -1903,9 +1900,8 @@ PRFileDesc * SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) { sslSocket *sm = NULL, *ss = NULL; - int i; - sslServerCerts *mc = NULL; - sslServerCerts *sc = NULL; + PRCList *cursor; + sslServerCert *sc = NULL; if (model == NULL) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); @@ -1940,52 +1936,44 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } - /* 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]); + 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); if (mc->serverCert && mc->serverCertChain) { - if (sc->serverCert) { - CERT_DestroyCertificate(sc->serverCert); - } - sc->serverCert = CERT_DupCertificate(mc->serverCert); - if (sc->serverCertChain) { - CERT_DestroyCertificateList(sc->serverCertChain); - } + sc->serverCert = CERT_DupCertificate(mc->serverCert); sc->serverCertChain = CERT_DupCertList(mc->serverCertChain); if (!sc->serverCertChain) goto loser; - 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]) + if (mc->certStatusArray) { + sc->certStatusArray = SECITEM_DupArray(NULL, mc->certStatusArray); + if (!sc->certStatusArray) goto loser; } - if (sm->signedCertTimestamps[i].data) { - if (ss->signedCertTimestamps[i].data) { - SECITEM_FreeItem(&ss->signedCertTimestamps[i], PR_FALSE); - } + if (mc->signedCertTimestamps.data) { if (SECITEM_CopyItem(NULL, - &ss->signedCertTimestamps[i], - &sm->signedCertTimestamps[i]) != + &sc->signedCertTimestamps, + &mc->signedCertTimestamps) != 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); @@ -2034,6 +2022,7 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) ss->pkcs11PinArg = sm->pkcs11PinArg; return fd; loser: + ssl_FreeServerCert(sc); return NULL; } @@ -2689,64 +2678,6 @@ ssl_GetSockName(PRFileDesc *fd, PRNetAddr *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; @@ -3439,10 +3370,9 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) /* Make a new socket and get it ready */ ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket)); if (ss) { - /* This should be of type SSLKEAType, but CC on IRIX + /* This should be of type SSLAuthType, but CC on IRIX * complains during the for loop. */ - int i; SECStatus status; ss->opt = ssl_defaults; @@ -3457,14 +3387,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) ss->cTimeout = PR_INTERVAL_NO_TIMEOUT; ss->url = NULL; - 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; - } + PR_INIT_CLIST(&ss->serverCerts); ss->stepDownKeyPair = NULL; ss->dheParams = NULL; diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h index 098ce88e5..daacb239d 100644 --- a/lib/ssl/sslt.h +++ b/lib/ssl/sslt.h @@ -10,6 +10,8 @@ #define __sslt_h_ #include "prtypes.h" +#include "secitem.h" +#include "certt.h" typedef struct SSL3StatisticsStr { /* statistics from ssl3_SendClientHello (sch) */ @@ -41,6 +43,7 @@ typedef enum { 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; @@ -62,8 +65,7 @@ typedef enum { ssl_sign_null = 0, /* "anonymous" in TLS */ ssl_sign_rsa = 1, ssl_sign_dsa = 2, - ssl_sign_ecdsa = 3, - ssl_sign_psk = 4 + ssl_sign_ecdsa = 3 } SSLSignType; /* Values of this enum match the HashAlgorithm enum from @@ -85,15 +87,27 @@ typedef struct SSLSignatureAndHashAlgStr { 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 = 1, + ssl_auth_rsa_decrypt = 1, /* static RSA */ ssl_auth_dsa = 2, - ssl_auth_kea = 3, + ssl_auth_kea = 3, /* unused */ ssl_auth_ecdsa = 4, - ssl_auth_psk = 5 /* Used for both PSK and (EC)DHE-PSK */ + ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature */ + ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature */ + ssl_auth_rsa_sign = 7, /* RSA PKCS#1.5 signing */ + ssl_auth_rsa_pss = 8, + ssl_auth_psk = 9, + ssl_auth_size /* number of authentication types */ } SSLAuthType; +/* This is defined for backward compatibility reasons */ +#define ssl_auth_rsa ssl_auth_rsa_decrypt + typedef enum { ssl_calg_null = 0, ssl_calg_rc4 = 1, @@ -124,6 +138,22 @@ typedef enum { 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 @@ -189,7 +219,7 @@ typedef struct SSLCipherSuiteInfoStr { /* server authentication info */ const char* authAlgorithmName; - SSLAuthType authAlgorithm; + SSLAuthType authAlgorithm; /* deprecated, use |authType| */ /* key exchange algorithm info */ const char* keaTypeName; @@ -215,6 +245,10 @@ typedef struct SSLCipherSuiteInfoStr { 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 { diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c index 3260a061c..7abbab349 100644 --- a/lib/ssl/tls13con.c +++ b/lib/ssl/tls13con.c @@ -357,8 +357,11 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid) /* 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) { - wrapKey = ssl3_GetWrappingKey(ss, NULL, - sid->u.ssl3.exchKeyType, + const sslServerCert *serverCert; + + serverCert = ssl_FindServerCert(ss, &sid->certType); + PORT_Assert(serverCert); + wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert, sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg); } else { @@ -408,10 +411,10 @@ tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid) * TODO(ekr@rtfm.com): Make a version with the "true" values. * Bug 1256137. */ - ss->sec.authAlgorithm = sid->authAlgorithm; - ss->sec.authKeyBits = sid->authKeyBits; - ss->sec.keaType = sid->keaType; - ss->sec.keaKeyBits = sid->keaKeyBits; + ss->sec.authType = sid->authType; + ss->sec.authKeyBits = sid->authKeyBits; + ss->sec.keaType = sid->keaType; + ss->sec.keaKeyBits = sid->keaKeyBits; ss->ssl3.hs.origCipherSuite = sid->u.ssl3.cipherSuite; } @@ -457,6 +460,28 @@ tls13_AllowPskCipher(const sslSocket *ss, const ssl3CipherSuiteDef *cipher_def) return PR_TRUE; } +/* Check whether resumption-PSK is allowed. */ +static PRBool +tls13_CanResume(sslSocket *ss, const sslSessionID *sid) +{ + const sslServerCert* sc; + + 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. */ + sc = ssl_FindServerCert(ss, &sid->certType); + if (!sc || !sc->serverCert) { + 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. */ @@ -474,25 +499,14 @@ tls13_HandleClientHelloPart2(sslSocket *ss, FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; } - /* 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; - } + 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; } #ifndef PARANOID @@ -510,8 +524,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss, goto loser; } - /* TODO(ekr@rtfm.com): Update this when we have pure PSK. */ - if (ss->ssl3.hs.suite_def->key_exchange_alg != kea_ecdhe_psk) { + if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) { /* TODO(ekr@rtfm.com): Free resumeSID. */ ss->statelessResume = PR_FALSE; } @@ -525,19 +538,14 @@ tls13_HandleClientHelloPart2(sslSocket *ss, 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); tls13_RestoreCipherInfo(ss, sid); - /* 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); - + ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType); + PORT_Assert(ss->sec.serverCert); + ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert); if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); } @@ -580,6 +588,13 @@ tls13_HandleClientHelloPart2(sslSocket *ss, } } + if (!ss->statelessResume) { + rv = ssl3_SelectServerCert(ss); + if (rv != SECSuccess) { + goto loser; + } + } + /* If this is TLS 1.3 we are expecting a ClientKeyShare * extension. Missing/absent extension cause failure * below. */ @@ -633,6 +648,7 @@ tls13_HandleClientKeyShare(sslSocket *ss) 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, @@ -858,7 +874,7 @@ tls13_InitializeHandshakeEncryption(sslSocket *ss) SECStatus rv; PORT_Assert(!!ss->ssl3.hs.xSS == - (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk)); + (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk)); if (!ss->ssl3.hs.xSS) { ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES); if (!ss->ssl3.hs.xSS) { @@ -885,7 +901,7 @@ SECStatus tls13_SendServerHelloSequence(sslSocket *ss) { SECStatus rv; - SSL3KEAType certIndex; + SECKEYPrivateKey *svrPrivKey; SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence", SSL_GETPID(), ss->fd)); @@ -914,7 +930,7 @@ tls13_SendServerHelloSequence(sslSocket *ss) return SECFailure; /* error code is set. */ } } - if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) { + if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) { rv = ssl3_SendCertificate(ss); if (rv != SECSuccess) { return SECFailure; /* error code is set. */ @@ -924,22 +940,13 @@ tls13_SendServerHelloSequence(sslSocket *ss) return SECFailure; /* error code is set. */ } - /* This was copied from: ssl3_SendCertificate. - * TODO(ekr@rtfm.com): Verify that this selection logic is correct. - * Bug 1237514. - */ - if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) || - (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) { - certIndex = kt_rsa; - } else { - certIndex = ss->ssl3.hs.kea_def->exchKeyType; - } - rv = ssl3_SendCertificateVerify(ss, - ss->serverCerts[certIndex].SERVERKEY); + svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey; + rv = ssl3_SendCertificateVerify(ss, svrPrivKey); 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); @@ -984,7 +991,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss) if (isPSK) { PRBool cacheOK = PR_FALSE; do { - if (ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) { + if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter); break; @@ -1013,7 +1020,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss) SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes); } else { /* No PSK negotiated.*/ - if (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk) { + if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter); return SECFailure; @@ -1089,6 +1096,7 @@ tls13_HandleServerKeyShare(sslSocket *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 */ @@ -1904,7 +1912,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length) PORT_Assert(!ss->sec.isServer); - if (ss->ssl3.hs.kea_def->signKeyType == ssl_sign_psk) { + if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) { /* Compute the rest of the secrets except for the resumption * and exporter secret. */ rv = tls13_ComputeSecrets1(ss); @@ -2229,7 +2237,7 @@ tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } ssl_GetXmitBufLock(ss); if (ss->opt.enableSessionTickets && - ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) { + ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) { /* TODO(ekr@rtfm.com): Add support for new tickets in PSK. */ rv = ssl3_SendNewSessionTicket(ss); if (rv != SECSuccess) { @@ -2400,8 +2408,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * server side supports it. Bug 1257047. */ if (!ss->opt.noCache && ss->sec.cache && - ss->ssl3.hs.kea_def->signKeyType != ssl_sign_psk) { - SSL3KEAType effectiveExchKeyType; + ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) { /* Uncache so that we replace. */ (*ss->sec.uncache)(ss->sec.ci.sid); @@ -2418,14 +2425,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket); PORT_Assert(!ticket.ticket.data); - 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); + rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid); if (rv != SECSuccess) return SECFailure; |