summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Thomson <martin.thomson@gmail.com>2016-04-21 08:45:03 +1000
committerMartin Thomson <martin.thomson@gmail.com>2016-04-21 08:45:03 +1000
commit9b854d48f2eae8d6821979c71b9e06234aef76c0 (patch)
tree54d2b694e75c8e1426257f63ae48eed9015718d5
parentefe5b290c741ac43f20cfef1d138360f79bdcdc1 (diff)
downloadnss-hg-9b854d48f2eae8d6821979c71b9e06234aef76c0.tar.gz
Bug 1237514 - Index certificates by SSLAuthType, r=ttaubert,ekr,rrelyea
-rw-r--r--cmd/selfserv/selfserv.c6
-rw-r--r--external_tests/common/scoped_ptrs.h20
-rw-r--r--external_tests/ssl_gtest/libssl_internals.c7
-rw-r--r--external_tests/ssl_gtest/ssl_loopback_unittest.cc113
-rw-r--r--external_tests/ssl_gtest/tls_agent.cc113
-rw-r--r--external_tests/ssl_gtest/tls_agent.h18
-rw-r--r--external_tests/ssl_gtest/tls_connect.cc24
-rw-r--r--external_tests/ssl_gtest/tls_connect.h4
-rw-r--r--lib/pk11wrap/pk11auth.c3
-rw-r--r--lib/ssl/SSLerrs.h2
-rw-r--r--lib/ssl/manifest.mn1
-rw-r--r--lib/ssl/ssl.def1
-rw-r--r--lib/ssl/ssl.h69
-rw-r--r--lib/ssl/ssl3con.c564
-rw-r--r--lib/ssl/ssl3ecc.c214
-rw-r--r--lib/ssl/ssl3ext.c125
-rw-r--r--lib/ssl/sslcert.c960
-rw-r--r--lib/ssl/sslcert.h62
-rw-r--r--lib/ssl/sslcon.c2
-rw-r--r--lib/ssl/sslimpl.h155
-rw-r--r--lib/ssl/sslinfo.c203
-rw-r--r--lib/ssl/sslsecur.c254
-rw-r--r--lib/ssl/sslsnce.c70
-rw-r--r--lib/ssl/sslsock.c189
-rw-r--r--lib/ssl/sslt.h46
-rw-r--r--lib/ssl/tls13con.c132
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;