From a3d3f697380506322398c94c9f96016f8ab2aa0b Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Thu, 26 Jan 2017 06:41:37 +0900 Subject: [PATCH] Bug 1325035 - Streamline session ticket key wrapping, r=ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D127 --HG-- extra : rebase_source : 8efefb1f37dd327397d259c342e60223bd9bed9b extra : amend_source : bdae9423ae41ed762c18718715425646a5ad0ec2 extra : histedit_source : 2d211aa721bc82eae4a1fb1895e1b2529899c3ae%2C640dfe56df26288f8ba8608dd24d277396d839bb --- gtests/ssl_gtest/libssl_internals.c | 7 +- gtests/ssl_gtest/ssl_cert_ext_unittest.cc | 29 +- gtests/ssl_gtest/ssl_ciphersuite_unittest.cc | 20 +- gtests/ssl_gtest/tls_agent.cc | 61 +- gtests/ssl_gtest/tls_agent.h | 6 +- gtests/ssl_gtest/tls_connect.cc | 23 +- lib/ssl/ssl.def | 6 + lib/ssl/ssl.h | 13 + lib/ssl/ssl3con.c | 195 +++-- lib/ssl/ssl3ecc.c | 20 +- lib/ssl/ssl3exthandle.c | 148 +--- lib/ssl/sslcert.c | 782 +++++++++---------- lib/ssl/sslcert.h | 41 +- lib/ssl/sslimpl.h | 42 +- lib/ssl/sslsnce.c | 469 +++++++---- lib/ssl/tls13con.c | 70 +- 16 files changed, 1008 insertions(+), 924 deletions(-) diff --git a/gtests/ssl_gtest/libssl_internals.c b/gtests/ssl_gtest/libssl_internals.c index 08af9af0ec..14b5257f8a 100644 --- a/gtests/ssl_gtest/libssl_internals.c +++ b/gtests/ssl_gtest/libssl_internals.c @@ -62,10 +62,7 @@ PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) { 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); @@ -209,7 +206,7 @@ PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType) { 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) { diff --git a/gtests/ssl_gtest/ssl_cert_ext_unittest.cc b/gtests/ssl_gtest/ssl_cert_ext_unittest.cc index 876c368819..bcd51b00e8 100644 --- a/gtests/ssl_gtest/ssl_cert_ext_unittest.cc +++ b/gtests/ssl_gtest/ssl_cert_ext_unittest.cc @@ -62,10 +62,22 @@ static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89}; static const SECItem kSctItem = {siBuffer, const_cast(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, @@ -78,13 +90,10 @@ TEST_P(TlsConnectGeneric, SignedCertificateTimestampsHandshake) { 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)); @@ -99,8 +108,8 @@ TEST_P(TlsConnectGeneric, SignedCertificateTimestampsConfig) { // 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(); @@ -141,8 +150,8 @@ static const SECItem kOcspItems[] = { {siBuffer, const_cast(kOcspValue2), sizeof(kOcspValue2)}}; static const SECItemArray kOcspResponses = {const_cast(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(); diff --git a/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc b/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc index ab10a84a03..391b4c4223 100644 --- a/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc +++ b/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc @@ -128,16 +128,22 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase { 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 diff --git a/gtests/ssl_gtest/tls_agent.cc b/gtests/ssl_gtest/tls_agent.cc index 7b81260fb5..b0e33b53e3 100644 --- a/gtests/ssl_gtest/tls_agent.cc +++ b/gtests/ssl_gtest/tls_agent.cc @@ -102,23 +102,35 @@ void TlsAgent::SetState(State 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); @@ -181,30 +193,23 @@ void TlsAgent::SetupClientAuth() { reinterpret_cast(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(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) { diff --git a/gtests/ssl_gtest/tls_agent.h b/gtests/ssl_gtest/tls_agent.h index 4b302eab59..288dda6b4f 100644 --- a/gtests/ssl_gtest/tls_agent.h +++ b/gtests/ssl_gtest/tls_agent.h @@ -18,6 +18,7 @@ #define GTEST_HAS_RTTI 0 #include "gtest/gtest.h" +#include "scoped_ptrs.h" extern bool g_ssl_gtest_verbose; @@ -115,6 +116,9 @@ class TlsAgent : public PollTarget { 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); @@ -122,8 +126,6 @@ class TlsAgent : public PollTarget { void SetupClientAuth(); void RequestClientAuth(bool requireAuth); - bool GetClientAuthCredentials(CERTCertificate** cert, - SECKEYPrivateKey** priv) const; void ConfigureSessionCache(SessionResumptionMode mode); void SetSessionTicketsEnabled(bool en); diff --git a/gtests/ssl_gtest/tls_connect.cc b/gtests/ssl_gtest/tls_connect.cc index 2b122e5cb0..dd50056db6 100644 --- a/gtests/ssl_gtest/tls_connect.cc +++ b/gtests/ssl_gtest/tls_connect.cc @@ -13,6 +13,7 @@ extern "C" { #include "databuffer.h" #include "gtest_utils.h" +#include "scoped_ptrs.h" #include "sslproto.h" extern std::string g_working_dir_path; @@ -345,6 +346,13 @@ void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, 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: @@ -390,6 +398,7 @@ void TlsConnectTestBase::ConnectExpectFailOneSide(TlsAgent::Role failing_side) { } void TlsConnectTestBase::ConfigureVersion(uint16_t version) { + version_ = version; client_->SetVersionRange(version, version); server_->SetVersionRange(version, version); } @@ -440,10 +449,16 @@ void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client, 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())); } } diff --git a/lib/ssl/ssl.def b/lib/ssl/ssl.def index 6aa8b64377..226d62dd92 100644 --- a/lib/ssl/ssl.def +++ b/lib/ssl/ssl.def @@ -221,3 +221,9 @@ SSL_SignatureSchemePrefGet; ;+ local: ;+*; ;+}; +;+NSS_3.30 { # NSS 3.30 release +;+ global: +SSL_SetSessionTicketKeyPair; +;+ local: +;+*; +;+}; diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index 8dbe7ab729..999c2640e6 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -913,6 +913,19 @@ 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 diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index 3d9258fa3b..678deb1046 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -273,10 +273,6 @@ static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = { 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. @@ -863,12 +859,10 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) 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 @@ -879,7 +873,7 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) 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; @@ -5583,8 +5577,6 @@ ssl3_HandleHelloRequest(sslSocket *ss) return rv; } -#define UNKNOWN_WRAP_MECHANISM 0x7fffffff - static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { CKM_DES3_ECB, CKM_CAST5_ECB, @@ -5600,27 +5592,58 @@ static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { 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) +static SECStatus +ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech, unsigned int *wrapMechIndex) { - const CK_MECHANISM_TYPE *pMech = wrapMechanismList; + 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 +}; - while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) { - ++pMech; +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; + } } - return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1 - : (pMech - wrapMechanismList); + /* 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) { @@ -5632,9 +5655,9 @@ ssl_UnwrapSymWrappingKey( /* 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; @@ -5642,7 +5665,7 @@ ssl_UnwrapSymWrappingKey( 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 */ @@ -5715,14 +5738,8 @@ ssl_UnwrapSymWrappingKey( 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; @@ -5750,7 +5767,7 @@ SSL3_ShutdownServerCache(void) PZ_Lock(symWrapKeysLock); /* get rid of all symWrapKeys */ for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) { - for (j = 0; j < ssl_auth_size; ++j) { + for (j = 0; j < SSL_NUM_WRAP_KEYS; ++j) { PK11SymKey **pSymWrapKey; pSymWrapKey = &symWrapKeys[i].symWrapKey[j]; if (*pSymWrapKey) { @@ -5784,7 +5801,6 @@ ssl_InitSymWrapKeysLock(void) PK11SymKey * ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, - const sslServerCert *serverCert, CK_MECHANISM_TYPE masterWrapMech, void *pwArg) { @@ -5795,7 +5811,8 @@ ssl3_GetWrappingKey(sslSocket *ss, 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; @@ -5803,6 +5820,7 @@ ssl3_GetWrappingKey(sslSocket *ss, SECKEYPublicKey *pubWrapKey = NULL; SECKEYPrivateKey *privWrapKey = NULL; ECCWrappedKeyInfo *ecWrapped; + const sslServerCert *serverCert = ss->sec.serverCert; PORT_Assert(serverCert); PORT_Assert(serverCert->serverKeyPair); @@ -5814,15 +5832,18 @@ ssl3_GetWrappingKey(sslSocket *ss, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL; /* hmm */ } - authType = serverCert->certType.authType; - svrPrivKey = serverCert->serverKeyPair->privKey; - symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech); - PORT_Assert(symWrapMechIndex >= 0); - if (symWrapMechIndex < 0) + 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. */ - pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType]; + authType = ssl_wrap_key_auth_type[wrapKeyIndex]; + svrPrivKey = serverCert->serverKeyPair->privKey; + pSymWrapKey = &symWrapKeys[wrapMechIndex].symWrapKey[wrapKeyIndex]; ssl_InitSessionCacheLocks(PR_TRUE); @@ -5841,10 +5862,11 @@ ssl3_GetWrappingKey(sslSocket *ss, /* Try to get wrapped SymWrapping key out of the (disk) cache. */ /* Following call fills in wswk on success. */ - if (ssl_GetWrappingKey(symWrapMechIndex, 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; @@ -5993,9 +6015,9 @@ ssl3_GetWrappingKey(sslSocket *ss, 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. */ @@ -6003,7 +6025,8 @@ ssl3_GetWrappingKey(sslSocket *ss, * 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. @@ -6011,7 +6034,7 @@ ssl3_GetWrappingKey(sslSocket *ss, PK11_FreeSymKey(unwrappedWrappingKey); unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType, + ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex, masterWrapMech, pwArg); } @@ -8255,19 +8278,17 @@ ssl3_SelectServerCert(sslSocket *ss) 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. */ @@ -8791,7 +8812,6 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, do { ssl3CipherSpec *pwSpec; SECItem wrappedMS; /* wrapped key */ - const sslServerCert *serverCert; if (sid->version != ss->version || sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || @@ -8799,8 +8819,13 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, 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. */ @@ -8848,7 +8873,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, 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) { @@ -8907,13 +8932,8 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, 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 && @@ -9631,34 +9651,6 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 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) { @@ -9667,8 +9659,8 @@ ssl3_SendCertificateRequest(sslSocket *ss) SECStatus rv; int length; SECItem *names; - int calen; - int nnames; + unsigned int calen; + unsigned int nnames; SECItem *name; int i; int certTypesLength; @@ -9683,7 +9675,10 @@ ssl3_SendCertificateRequest(sslSocket *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; @@ -11331,7 +11326,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) */ SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec, SSLAuthType authType) + ssl3CipherSpec *spec) { PK11SymKey *wrappingKey = NULL; PK11SlotInfo *symKeySlot; @@ -11385,8 +11380,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, 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. */ } @@ -11593,9 +11587,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) 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 && @@ -11619,8 +11611,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) 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); /*************************************/ diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c index 72c4ba56e4..96aa55dad7 100644 --- a/lib/ssl/ssl3ecc.c +++ b/lib/ssl/ssl3ecc.c @@ -440,23 +440,19 @@ ssl_GetECGroupForServerSocket(sslSocket *ss) 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; diff --git a/lib/ssl/ssl3exthandle.c b/lib/ssl/ssl3exthandle.c index 1cb3dcb868..7f0c168c3e 100644 --- a/lib/ssl/ssl3exthandle.c +++ b/lib/ssl/ssl3exthandle.c @@ -16,12 +16,6 @@ #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, @@ -29,8 +23,6 @@ static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, 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); /* @@ -76,83 +68,6 @@ ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 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. @@ -960,6 +875,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 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; @@ -975,7 +891,6 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 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", @@ -995,7 +910,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 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; @@ -1014,8 +929,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 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; @@ -1108,22 +1022,15 @@ ssl3_EncodeSessionTicket(sslSocket *ss, 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; @@ -1350,6 +1257,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *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; @@ -1387,7 +1295,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) } /* 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)); @@ -1538,24 +1446,19 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) 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. */ @@ -1682,8 +1585,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) 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) diff --git a/lib/ssl/sslcert.c b/lib/ssl/sslcert.c index ea524552da..e4c6671e8d 100644 --- a/lib/ssl/sslcert.c +++ b/lib/ssl/sslcert.c @@ -13,42 +13,91 @@ #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; @@ -61,11 +110,14 @@ 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) @@ -129,9 +181,9 @@ ssl_FreeServerCert(sslServerCert *sc) 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; @@ -139,68 +191,21 @@ ssl_FindServerCert(const sslSocket *ss, 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) @@ -232,21 +237,43 @@ ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert, 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; } @@ -281,12 +308,39 @@ ssl_PopulateSignedCertTimestamps(sslServerCert *sc, 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; @@ -294,34 +348,26 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert, 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); @@ -332,23 +378,12 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert, 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; } @@ -382,114 +417,55 @@ ssl_GetEcdhAuthType(CERTCertificate *cert) } } -/* This function examines the key usages of the given RSA-PKCS1 certificate - * and configures one or multiple server certificates based on that data. - * - * 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) -{ - 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. + * 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_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert, - sslKeyPair *keyPair, const 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; - 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; @@ -498,27 +474,33 @@ ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert, } /* Check that we successfully picked an authType */ - if (arg.authType == ssl_auth_null) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* |data->authType| has to either agree or be ssl_auth_null. */ - if (data && data->authType != ssl_auth_null && - data->authType != arg.authType) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + if (targetAuthType != ssl_auth_null) { + authTypes &= 1 << targetAuthType; } - 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) { @@ -545,20 +527,18 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey) 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, @@ -566,12 +546,12 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, 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) { @@ -591,21 +571,23 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, 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; } /*******************************************************************/ @@ -630,164 +612,147 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, * 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; +} + +/* 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 slot and unlinks it, or it makes a new +/* 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); - return SECFailure; - } - rv = ssl_PopulateKeyPair(sc, keyPair); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); goto loser; } - /* Now that we have a key pair, update the details of the slot. Many of the - * legacy functions create a slot with a namedCurve of 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); 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); + keyPair = ssl_MakeKeyPairForCert(key, cert); if (!keyPair) { - /* Note: pubKey is adopted or freed by ssl_MakeKeyPairForCert() - * depending on whether it succeeds or not. */ - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - - switch (certType) { - case ssl_kea_rsa: - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt, - cert, certChainOpt, keyPair); - if (rv != SECSuccess) { - return SECFailure; - } - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign, - cert, certChainOpt, keyPair); - break; - - case ssl_kea_dh: - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa, - cert, certChainOpt, keyPair); - break; - - 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; + rv = ssl_PopulateKeyPair(sc, keyPair); + ssl_FreeKeyPair(keyPair); + if (rv != SECSuccess) { + err = PORT_GetError(); + goto loser; } - ssl_FreeKeyPair(keyPair); - return rv; + PR_APPEND_LINK(&sc->link, &ss->serverCerts); + return SECSuccess; + +loser: + ssl_FreeServerCert(sc); + PORT_SetError(err); + return SECFailure; } /* Public deprecated function */ @@ -797,6 +762,7 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key, SSLKEAType certType) { sslSocket *ss; + sslAuthTypeMask authTypes; ss = ssl_FindSocket(fd); if (!ss) { @@ -808,52 +774,25 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, return SECFailure; } + authTypes = ssl_KeaTypeToAuthTypeMask(certType); + if (!authTypes) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (!cert) { - switch (certType) { - case ssl_kea_rsa: - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt); - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_sign); - break; - - case ssl_kea_dh: - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa); - break; - - 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; + 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 */ @@ -862,6 +801,8 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, SSLKEAType certType) { sslSocket *ss; + sslServerCert *sc; + sslAuthTypeMask authTypes; SECStatus rv; ss = ssl_FindSocket(fd); @@ -871,49 +812,28 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, 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; + 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; } -} -static SECStatus -ssl_SetSignedTimestampsInSlot(sslSocket *ss, SSLAuthType authType, - const SECItem *scts) -{ - sslServerCert *sc; - SECStatus rv; + if (!responses) { + sc = ssl_FindCertWithMask(ss, authTypes); + if (sc) { + (void)ssl_PopulateOCSPResponses(sc, NULL); + } + return SECSuccess; + } - sc = ssl_FindOrMakeCertType(ss, authType); + sc = ssl_FindOrMakeCert(ss, authTypes); if (!sc) { - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - rv = ssl_PopulateSignedCertTimestamps(sc, scts); + + rv = ssl_PopulateOCSPResponses(sc, responses); if (rv == SECSuccess) { PR_APPEND_LINK(&sc->link, &ss->serverCerts); } else { @@ -928,6 +848,8 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType certType) { sslSocket *ss; + sslServerCert *sc; + sslAuthTypeMask authTypes; SECStatus rv; ss = ssl_FindSocket(fd); @@ -937,34 +859,34 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, 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); + 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_dh: - return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts); + if (!scts) { + sc = ssl_FindCertWithMask(ss, authTypes); + if (sc) { + (void)ssl_PopulateSignedCertTimestamps(sc, NULL); + } + return SECSuccess; + } - 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); + sc = ssl_FindOrMakeCert(ss, authTypes); + if (!sc) { + return SECFailure; + } - default: - SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - 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. */ diff --git a/lib/ssl/sslcert.h b/lib/ssl/sslcert.h index 052c7d6db0..fb31d1389d 100644 --- a/lib/ssl/sslcert.h +++ b/lib/ssl/sslcert.h @@ -13,26 +13,21 @@ #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; @@ -48,12 +43,18 @@ typedef struct sslServerCertStr { 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_ */ diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index 69b461eb7a..bf7f86422f 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -125,7 +125,8 @@ typedef enum { SSLAppOpRead = 0, #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 @@ -530,10 +531,10 @@ struct sslSessionIDStr { */ 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; @@ -983,8 +984,8 @@ typedef struct SSLWrappedSymWrappingKeyStr { 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; @@ -997,7 +998,8 @@ typedef struct SessionTicketStr { 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. */ @@ -1228,7 +1230,6 @@ 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; @@ -1684,8 +1685,7 @@ extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, 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. */ @@ -1694,11 +1694,10 @@ extern void ssl3_SetSIDSessionTicket(sslSessionID *sid, 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 */ @@ -1716,8 +1715,8 @@ extern void ssl_FreePRSocket(PRFileDesc *fd); 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 @@ -1729,7 +1728,7 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType, * 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. */ @@ -1794,8 +1793,8 @@ 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); @@ -1815,7 +1814,6 @@ SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss, 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); diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c index 4a4005c2d9..ad1318c910 100644 --- a/lib/ssl/sslsnce.c +++ b/lib/ssl/sslsnce.c @@ -1,3 +1,4 @@ +/* -*- 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. * @@ -33,7 +34,7 @@ * 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 @@ -54,6 +55,7 @@ #include "base64.h" #include "keyhi.h" #include "blapit.h" +#include "nss.h" /* for NSS_RegisterShutdown */ #include "sechash.h" #include @@ -109,7 +111,7 @@ struct sidCacheEntryStr { /* 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 */ @@ -440,17 +442,12 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) 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 " @@ -526,16 +523,11 @@ ConvertToSID(sidCacheEntry *from, 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; @@ -983,7 +975,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, 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); @@ -1608,36 +1600,254 @@ StopLockPoller(cacheDesc *cache) * Code dealing with shared wrapped symmetric wrapping keys below * ************************************************************************/ -/* If now is zero, it implies that the lock is not held, and must be -** aquired here. -*/ +/* 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); @@ -1645,28 +1855,25 @@ getSvrWrappingKey(PRInt32 symWrapMechIndex, 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) { @@ -1682,13 +1889,13 @@ WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, 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) { @@ -1712,7 +1919,7 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, 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; @@ -1735,17 +1942,17 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, 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) @@ -1753,31 +1960,35 @@ GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, 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) { @@ -1810,52 +2021,52 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, 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; } @@ -1868,47 +2079,45 @@ ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey, * 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((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) - 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; + } - 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; } @@ -1946,14 +2155,13 @@ SSL_InheritMPServerSIDCache(const char *envString) 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 @@ -1965,12 +2173,11 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex, * 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 diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c index 5670fbee5f..4538fa2c51 100644 --- a/lib/ssl/tls13con.c +++ b/lib/ssl/tls13con.c @@ -628,13 +628,9 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid) 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 { @@ -937,7 +933,7 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid) * 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; } @@ -1161,6 +1157,30 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare) 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) { @@ -1184,8 +1204,7 @@ tls13_SelectServerCert(sslSocket *ss) 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; } @@ -1198,8 +1217,8 @@ tls13_SelectServerCert(sslSocket *ss) 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; } @@ -1230,8 +1249,6 @@ tls13_NegotiateAuthentication(sslSocket *ss) if (rv != SECSuccess) { return SECFailure; } - ss->ssl3.hs.kea_def_mutable.authKeyType = - ss->sec.serverCert->certType.authType; return SECSuccess; } @@ -1343,6 +1360,10 @@ tls13_HandleClientHelloPart2(sslSocket *ss, 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); @@ -1351,12 +1372,11 @@ tls13_HandleClientHelloPart2(sslSocket *ss, } 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); @@ -1617,9 +1637,9 @@ 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]; @@ -1635,7 +1655,10 @@ tls13_SendCertificateRequest(sslSocket *ss) 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; @@ -3291,16 +3314,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, /* 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. */