Bug 535649 - Implement UI around CVE-2009-3555 and draft-rescorla-tls-renegotiation, r=rrelyea

== NSS 3.12.6 will block some renegotiation attempts on SSL sockets by default
== This patch does not yet implement new UI by default, but adds 4 new prefs to get fine grained control (blocking/allowing, displaying broken state)
== One of the prefs is a temporary pref that is supposed to go away at some point in the future
This commit is contained in:
Kai Engert 2010-02-07 13:09:51 +01:00
Родитель 2bfab230a2
Коммит 62caa75f94
5 изменённых файлов: 144 добавлений и 2 удалений

Просмотреть файл

@ -5,6 +5,11 @@ pref("security.enable_ssl3", true);
pref("security.enable_tls", true);
pref("security.enable_tls_session_tickets", true);
pref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", false);
pref("security.ssl.renego_unrestricted_hosts", "");
pref("security.ssl.treat_unsafe_negotiation_as_broken", false);
pref("security.ssl.require_safe_negotiation", false);
pref("security.ssl2.rc4_128", false);
pref("security.ssl2.rc2_128", false);
pref("security.ssl2.des_ede3_192", false);

Просмотреть файл

@ -69,6 +69,7 @@
#include "nsIWindowWatcher.h"
#include "nsIPrompt.h"
#include "nsProxyRelease.h"
#include "nsIConsoleService.h"
#include "ssl.h"
#include "cert.h"
@ -871,6 +872,28 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
nsIWebProgressListener::STATE_SECURE_LOW);
PRBool siteSupportsSafeRenego;
if (SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, &siteSupportsSafeRenego) != SECSuccess
|| !siteSupportsSafeRenego) {
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (infoObject && console) {
nsXPIDLCString hostName;
infoObject->GetHostName(getter_Copies(hostName));
nsAutoString msg;
msg.Append(NS_ConvertASCIItoUTF16(hostName));
msg.Append(NS_LITERAL_STRING(" : potentially vulnerable to CVE-2009-3555"));
console->LogStringMessage(msg.get());
}
if (nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()) {
secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
}
}
CERTCertificate *peerCert = SSL_PeerCertificate(fd);
const char* caName = nsnull; // caName is a pointer only, no ownership
char* certOrgName = CERT_GetOrgName(&peerCert->issuer);

Просмотреть файл

@ -1693,6 +1693,15 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
mPrefBranch->GetBoolPref(
"security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref",
&enabled);
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
// Disable any ciphers that NSS might have enabled by default
for (PRUint16 i = 0; i < SSL_NumImplementedCiphers; ++i)
{
@ -1853,7 +1862,18 @@ nsNSSComponent::Init()
}
nsSSLIOLayerHelpers::Init();
char *unrestricted_hosts=nsnull;
mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (unrestricted_hosts) {
nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
nsMemory::Free(unrestricted_hosts);
unrestricted_hosts=nsnull;
}
PRBool enabled = PR_FALSE;
mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
mClientAuthRememberService = new nsClientAuthRememberService;
if (mClientAuthRememberService)
mClientAuthRememberService->Init();
@ -2184,6 +2204,23 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
} else if (prefName.Equals("security.enable_tls_session_tickets")) {
mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
} else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
} else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
} else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
char *unrestricted_hosts=nsnull;
mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
if (unrestricted_hosts) {
nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
nsMemory::Free(unrestricted_hosts);
}
} else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
} else if (prefName.Equals("security.OCSP.enabled")
|| prefName.Equals("security.OCSP.require")) {
setOCSPOptions(mPrefBranch);

Просмотреть файл

@ -87,6 +87,7 @@
#include "nsIClassInfoImpl.h"
#include "nsIProgrammingLanguage.h"
#include "nsIArray.h"
#include "nsCommaSeparatedTokenizer.h"
#include "ssl.h"
#include "secerr.h"
@ -837,6 +838,11 @@ void nsSSLIOLayerHelpers::Cleanup()
mTLSTolerantSites = nsnull;
}
if (mRenegoUnrestrictedSites) {
delete mRenegoUnrestrictedSites;
mRenegoUnrestrictedSites = nsnull;
}
if (mSharedPollableEvent)
PR_DestroyPollableEvent(mSharedPollableEvent);
@ -1986,6 +1992,8 @@ PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mTLSTolerantSites = nsnull;
nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull;
nsCStringHashSet *nsSSLIOLayerHelpers::mRenegoUnrestrictedSites = nsnull;
PRBool nsSSLIOLayerHelpers::mTreatUnsafeNegotiationAsBroken = PR_FALSE;
PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
PRBool nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
@ -2204,6 +2212,14 @@ nsresult nsSSLIOLayerHelpers::Init()
// the rate of hashtable array reallocation.
mTLSTolerantSites->Init(16);
mRenegoUnrestrictedSites = new nsCStringHashSet();
if (!mRenegoUnrestrictedSites)
return NS_ERROR_OUT_OF_MEMORY;
mRenegoUnrestrictedSites->Init(1);
mTreatUnsafeNegotiationAsBroken = PR_FALSE;
mHostsWithCertErrors = new nsPSMRememberCertErrorsTable();
if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized())
return NS_ERROR_OUT_OF_MEMORY;
@ -2231,6 +2247,49 @@ PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
return mTLSIntolerantSites->Contains(str);
}
void nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString &str)
{
nsAutoLock lock(mutex);
if (mRenegoUnrestrictedSites) {
delete mRenegoUnrestrictedSites;
mRenegoUnrestrictedSites = nsnull;
}
mRenegoUnrestrictedSites = new nsCStringHashSet();
if (!mRenegoUnrestrictedSites)
return;
mRenegoUnrestrictedSites->Init(1);
nsCCommaSeparatedTokenizer toker(str);
while (toker.hasMoreTokens()) {
const nsCSubstring &host = toker.nextToken();
if (!host.IsEmpty()) {
mRenegoUnrestrictedSites->Put(host);
}
}
}
PRBool nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString &str)
{
nsAutoLock lock(mutex);
return mRenegoUnrestrictedSites->Contains(str);
}
void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(PRBool broken)
{
nsAutoLock lock(mutex);
mTreatUnsafeNegotiationAsBroken = broken;
}
PRBool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
{
nsAutoLock lock(mutex);
return mTreatUnsafeNegotiationAsBroken;
}
nsresult
nsSSLIOLayerNewSocket(PRInt32 family,
const char *host,
@ -3523,6 +3582,15 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS,
infoObject)) {
return NS_ERROR_FAILURE;
}
if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, PR_FALSE)) {
return NS_ERROR_FAILURE;
}
if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
return NS_ERROR_FAILURE;
}
}
// Set the Peer ID so that SSL proxy connections work properly.
char *peerId;

Просмотреть файл

@ -286,7 +286,13 @@ public:
static nsCStringHashSet *mTLSIntolerantSites;
static nsCStringHashSet *mTLSTolerantSites;
static nsPSMRememberCertErrorsTable* mHostsWithCertErrors;
static nsCStringHashSet *mRenegoUnrestrictedSites;
static PRBool mTreatUnsafeNegotiationAsBroken;
static void setTreatUnsafeNegotiationAsBroken(PRBool broken);
static PRBool treatUnsafeNegotiationAsBroken();
static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
static PRBool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
static void rememberTolerantSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo);
@ -294,7 +300,10 @@ public:
static void addIntolerantSite(const nsCString &str);
static void removeIntolerantSite(const nsCString &str);
static PRBool isKnownAsIntolerantSite(const nsCString &str);
static void setRenegoUnrestrictedSites(const nsCString &str);
static PRBool isRenegoUnrestrictedSite(const nsCString &str);
static PRFileDesc *mSharedPollableEvent;
static nsNSSSocketInfo *mSocketOwningPollableEvent;