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