author | Josh Matthews <josh@joshmatthews.net> |
Sat, 30 Jun 2012 07:34:17 -0700 | |
changeset 113492 | 7c2c9c988869363cf5755a36360af41124ffbee9 |
parent 113491 | 7a0fe388a24b7df6fb1d6efeab09ed3f1d1a102b |
child 113493 | 326ed6f1dc9e0495809b1007b2d8cad6dbc8df40 |
push id | 23872 |
push user | emorley@mozilla.com |
push date | Fri, 16 Nov 2012 17:06:27 +0000 |
treeherder | mozilla-central@a7ed19f7d21a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bsmith, biesi |
bugs | 722979 |
milestone | 19.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -493,22 +493,25 @@ // Speculatively connect to the current engine's search URI (and // suggest URI, if different) to reduce request latency const SUGGEST_TYPE = "application/x-suggestions+json"; var engine = this.currentEngine; var connector = Services.io.QueryInterface(Components.interfaces.nsISpeculativeConnect); var searchURI = engine.getSubmission("dummy").uri; - connector.speculativeConnect(searchURI, null); + let callbacks = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsILoadContext); + connector.speculativeConnect(searchURI, callbacks); if (engine.supportsResponseType(SUGGEST_TYPE)) { var suggestURI = engine.getSubmission("dummy", SUGGEST_TYPE).uri; if (suggestURI.prePath != searchURI.prePath) - connector.speculativeConnect(suggestURI, null); + connector.speculativeConnect(suggestURI, callbacks); } ]]></handler> </handlers> </binding> <binding id="searchbar-textbox" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete"> <implementation implements="nsIObserver">
--- a/content/base/test/test_websocket.html +++ b/content/base/test/test_websocket.html @@ -1228,17 +1228,23 @@ function test41() // clean up the STS state netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); const Cc = Components.classes; const Ci = Components.interfaces; var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var thehost = ios.newURI("http://example.com", null, null); var stss = Cc["@mozilla.org/stsservice;1"].getService(Ci.nsIStrictTransportSecurityService); - stss.removeStsState(thehost); + var loadContext = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsILoadContext); + var flags = 0; + if (loadContext.usePrivateBrowsing) + flags |= Ci.nsISocketProvider.NO_PERMANENT_STORAGE; + stss.removeStsState(thehost, flags); doTest(42); } } } } function test42() {
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -109,16 +109,17 @@ #include "nsIFileURL.h" #include "nsIHistoryEntry.h" #include "nsISHistoryListener.h" #include "nsIWindowWatcher.h" #include "nsIPromptFactory.h" #include "nsIObserver.h" #include "nsINestedURI.h" #include "nsITransportSecurityInfo.h" +#include "nsISSLSocketControl.h" #include "nsINSSErrorsService.h" #include "nsIApplicationCache.h" #include "nsIApplicationCacheChannel.h" #include "nsIApplicationCacheContainer.h" #include "nsIPermissionManager.h" #include "nsStreamUtils.h" #include "nsIController.h" #include "nsPICommandUpdater.h" @@ -4169,19 +4170,24 @@ nsDocShell::DisplayLoadError(nsresult aE if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) { error.AssignLiteral("nssBadCert"); // if this is a Strict-Transport-Security host and the cert // is bad, don't allow overrides (STS Spec section 7.3). nsCOMPtr<nsIStrictTransportSecurityService> stss = do_GetService(NS_STSSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - + uint32_t flags = 0; + nsCOMPtr<nsISSLSocketControl> socketControl = do_QueryInterface(tsi); + if (socketControl) { + socketControl->GetProviderFlags(&flags); + } + bool isStsHost = false; - rv = stss->IsStsURI(aURI, &isStsHost); + rv = stss->IsStsURI(aURI, flags, &isStsHost); NS_ENSURE_SUCCESS(rv, rv); uint32_t bucketId; if (isStsHost) { cssClass.AssignLiteral("badStsCert"); //measuring STS separately allows us to measure click through //rates easily bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_STS;
--- a/netwerk/base/public/nsISocketTransport.idl +++ b/netwerk/base/public/nsISocketTransport.idl @@ -146,16 +146,26 @@ interface nsISocketTransport : nsITransp /** * If set, we will skip all IPv6 addresses the host may have and only * connect to IPv4 ones. */ const unsigned long DISABLE_IPV6 = (1 << 2); /** + * If set, indicates that the connection was initiated from a source + * defined as being private in the sense of Private Browsing. Generally, + * there should be no state shared between connections that are private + * and those that are not; it is OK for multiple private connections + * to share state with each other, and it is OK for multiple non-private + * connections to share state with each other. + */ + const unsigned long NO_PERMANENT_STORAGE = (1 << 3); + + /** * Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or * IPTOS_CLASS_CSx (or IPTOS_DSCP_EF, but currently no supported * services require expedited-forwarding). * Not setting this value will leave the socket with the default * ToS value, which on most systems if IPTOS_CLASS_CS0 (formerly * IPTOS_PREC_ROUTINE). */ attribute octet QoSBits;
--- a/netwerk/base/public/nsIStrictTransportSecurityService.idl +++ b/netwerk/base/public/nsIStrictTransportSecurityService.idl @@ -3,73 +3,84 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" interface nsIURI; interface nsIObserver; interface nsIHttpChannel; -[scriptable, uuid(aee925d1-2bc9-469e-9582-b27b1d6b5192)] +[scriptable, uuid(c6138514-f212-4747-98c2-7abfce3be293)] interface nsIStrictTransportSecurityService : nsISupports { /** * Parses a given HTTP header and records the results internally. * The format of the STS header is defined by the STS specification: * http://tools.ietf.org/html/draft-hodges-strict-transport-sec * and allows a host to specify that future requests on port 80 should be * upgraded to HTTPS. * * @param aSourceURI the URI of the resource with the HTTP header. * @param aHeader the HTTP response header specifying STS data. + * @param aFlags options for this request as defined in nsISocketProvider: + * NO_PERMANENT_STORAGE * @param aMaxAge the parsed max-age directive of the header. * @param aIncludeSubdomains the parsed includeSubdomains directive. * @return NS_OK if it succeeds * NS_ERROR_FAILURE if it can't be parsed * NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA * if there are unrecognized tokens in the header. */ void processStsHeader(in nsIURI aSourceURI, in string aHeader, + in uint32_t aFlags, [optional] out unsigned long long aMaxAge, [optional] out boolean aIncludeSubdomains); /** * Removes the STS state of a host, including the includeSubdomains state * that would affect subdomains. This essentially removes STS state for * the domain tree rooted at this host. + * @param aURI the URI of the target host + * @param aFlags options for this request as defined in nsISocketProvider: + * NO_PERMANENT_STORAGE */ - void removeStsState(in nsIURI aURI); + void removeStsState(in nsIURI aURI, + in uint32_t aFlags); /** * Checks if the given security info is for an STS host with a broken * transport layer (certificate errors like invalid CN). */ boolean shouldIgnoreStsHeader(in nsISupports aSecurityInfo); /** * Checks whether or not the given hostname has STS state set. * The host is an STS host if either it has the STS permission, or one of * its super-domains has an STS "includeSubdomains" permission set. * * @param aHost the hostname (punycode) to query for STS state. + * @param aFlags options for this request as defined in nsISocketProvider: + * NO_PERMANENT_STORAGE */ - boolean isStsHost(in string aHost); + boolean isStsHost(in string aHost, in uint32_t aFlags); /** * Checks whether or not the URI's hostname has STS state set. * The URI is an STS URI if either the host has the STS permission, or one * of its super-domains has an STS "includeSubdomains" permission set. * NOTE: this function makes decisions based only on the scheme and * host contained in the URI, and disregards other portions of the URI * such as path and port. * * @param aURI the URI to query for STS state. + * @param aFlags options for this request as defined in nsISocketProvider: + * NO_PERMANENT_STORAGE */ - boolean isStsURI(in nsIURI aURI); + boolean isStsURI(in nsIURI aURI, in uint32_t aFlags); }; %{C++ #define NS_STSSERVICE_CONTRACTID "@mozilla.org/stsservice;1" #define NS_STSSERVICE_CLASSNAME "stsservice" #define STS_PERMISSION "sts/use"
--- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -972,16 +972,19 @@ nsSocketTransport::BuildSocket(PRFileDes break; if (mProxyTransparentResolvesHost) proxyFlags |= nsISocketProvider::PROXY_RESOLVES_HOST; if (mConnectionFlags & nsISocketTransport::ANONYMOUS_CONNECT) proxyFlags |= nsISocketProvider::ANONYMOUS_CONNECT; + if (mConnectionFlags & nsISocketTransport::NO_PERMANENT_STORAGE) + proxyFlags |= nsISocketProvider::NO_PERMANENT_STORAGE; + nsCOMPtr<nsISupports> secinfo; if (i == 0) { // if this is the first type, we'll want the // service to allocate a new socket rv = provider->NewSocket(mNetAddr.raw.family, host, port, proxyHost, proxyPort, proxyFlags, &fd, getter_AddRefs(secinfo));
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -365,17 +365,18 @@ nsHttpChannel::Connect() NS_ENSURE_SUCCESS(rv,rv); if (!usingSSL) { // enforce Strict-Transport-Security nsIStrictTransportSecurityService* stss = gHttpHandler->GetSTSService(); NS_ENSURE_TRUE(stss, NS_ERROR_OUT_OF_MEMORY); bool isStsHost = false; - rv = stss->IsStsURI(mURI, &isStsHost); + uint32_t flags = mPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; + rv = stss->IsStsURI(mURI, flags, &isStsHost); // if STS fails, there's no reason to cancel the load, but it's // worrisome. NS_ASSERTION(NS_SUCCEEDED(rv), "Something is wrong with STS: IsStsURI failed."); if (NS_SUCCEEDED(rv) && isStsHost) { LOG(("nsHttpChannel::Connect() STS permissions found\n")); @@ -1107,17 +1108,19 @@ nsHttpChannel::ProcessSTSHeader() NS_ENSURE_SUCCESS(rv, NS_OK); // If this was already an STS host, the connection should have been aborted // by the bad cert handler in the case of cert errors. If it didn't abort the connection, // there's probably something funny going on. // If this wasn't an STS host, errors are allowed, but no more STS processing // will happen during the session. bool wasAlreadySTSHost; - rv = stss->IsStsURI(mURI, &wasAlreadySTSHost); + uint32_t flags = + NS_UsePrivateBrowsing(this) ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; + rv = stss->IsStsURI(mURI, flags, &wasAlreadySTSHost); // Failure here means STS is broken. Don't prevent the load, but this // shouldn't fail. NS_ENSURE_SUCCESS(rv, NS_OK); NS_ASSERTION(!(wasAlreadySTSHost && tlsIsBroken), "connection should have been aborted by nss-bad-cert-handler"); // Any STS header is ignored if the channel is not trusted due to // certificate errors (STS Spec 7.1) -- there is nothing else to do, and @@ -1135,17 +1138,17 @@ nsHttpChannel::ProcessSTSHeader() rv = mResponseHead->GetHeader(atom, stsHeader); if (rv == NS_ERROR_NOT_AVAILABLE) { LOG(("STS: No STS header, continuing load.\n")); return NS_OK; } // All other failures are fatal. NS_ENSURE_SUCCESS(rv, rv); - rv = stss->ProcessStsHeader(mURI, stsHeader.get(), NULL, NULL); + rv = stss->ProcessStsHeader(mURI, stsHeader.get(), flags, NULL, NULL); if (NS_FAILED(rv)) { LOG(("STS: Failed to parse STS header, continuing load.\n")); return NS_OK; } return NS_OK; }
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2452,16 +2452,19 @@ nsHalfOpenSocket::SetupStreams(nsISocket uint32_t tmpFlags = 0; if (mCaps & NS_HTTP_REFRESH_DNS) tmpFlags = nsISocketTransport::BYPASS_CACHE; if (mCaps & NS_HTTP_LOAD_ANONYMOUS) tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT; + if (mEnt->mConnInfo->GetPrivate()) + tmpFlags |= nsISocketTransport::NO_PERMANENT_STORAGE; + // For backup connections, we disable IPv6. That's because some users have // broken IPv6 connectivity (leading to very long timeouts), and disabling // IPv6 on the backup connection gives them a much better user experience // with dual-stack hosts, though they still pay the 250ms delay for each new // connection. This strategy is also known as "happy eyeballs". if (isBackup && gHttpHandler->FastFallbackToIPv4()) tmpFlags |= nsISocketTransport::DISABLE_IPV6;
--- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -1615,18 +1615,22 @@ NS_IMETHODIMP nsHttpHandler::SpeculativeConnect(nsIURI *aURI, nsIInterfaceRequestor *aCallbacks) { nsIStrictTransportSecurityService* stss = gHttpHandler->GetSTSService(); bool isStsHost = false; if (!stss) return NS_OK; + nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks); + uint32_t flags = 0; + if (loadContext && loadContext->UsePrivateBrowsing()) + flags |= nsISocketProvider::NO_PERMANENT_STORAGE; nsCOMPtr<nsIURI> clone; - if (NS_SUCCEEDED(stss->IsStsURI(aURI, &isStsHost)) && isStsHost) { + if (NS_SUCCEEDED(stss->IsStsURI(aURI, flags, &isStsHost)) && isStsHost) { if (NS_SUCCEEDED(aURI->Clone(getter_AddRefs(clone)))) { clone->SetScheme(NS_LITERAL_CSTRING("https")); aURI = clone.get(); } } nsAutoCString scheme; nsresult rv = aURI->GetScheme(scheme);
--- a/netwerk/socket/nsISSLSocketControl.idl +++ b/netwerk/socket/nsISSLSocketControl.idl @@ -44,11 +44,15 @@ interface nsISSLSocketControl : nsISuppo /* Determine if a potential SSL connection to hostname:port with * a desired NPN negotiated protocol of npnProtocol can use the socket * associated with this object instead of making a new one. */ boolean joinConnection( in ACString npnProtocol, /* e.g. "spdy/2" */ in ACString hostname, in long port); - + + /* + * The original flags from the socket provider. + */ + readonly attribute uint32_t providerFlags; };
--- a/netwerk/socket/nsISocketProvider.idl +++ b/netwerk/socket/nsISocketProvider.idl @@ -76,17 +76,26 @@ interface nsISocketProvider : nsISupport /** * When setting this flag, the socket will not apply any * credentials when establishing a connection. For example, * an SSL connection would not send any client-certificates * if this flag is set. */ const long ANONYMOUS_CONNECT = 1 << 1; - + + /** + * If set, indicates that the connection was initiated from a source + * defined as being private in the sense of Private Browsing. Generally, + * there should be no state shared between connections that are private + * and those that are not; it is OK for multiple private connections + * to share state with each other, and it is OK for multiple non-private + * connections to share state with each other. + */ + const unsigned long NO_PERMANENT_STORAGE = 1 << 2; }; %{C++ /** * nsISocketProvider implementations should be registered with XPCOM under a * contract ID of the form: "@mozilla.org/network/socket;2?type=foo" */ #define NS_NETWORK_SOCKET_CONTRACTID_PREFIX \
--- a/netwerk/socket/nsSOCKSSocketProvider.cpp +++ b/netwerk/socket/nsSOCKSSocketProvider.cpp @@ -42,17 +42,17 @@ nsSOCKSSocketProvider::CreateV5(nsISuppo NS_IMETHODIMP nsSOCKSSocketProvider::NewSocket(int32_t family, const char *host, int32_t port, const char *proxyHost, int32_t proxyPort, uint32_t flags, - PRFileDesc **result, + PRFileDesc **result, nsISupports **socksInfo) { PRFileDesc *sock; sock = PR_OpenTCPSocket(family); if (!sock) return NS_ERROR_OUT_OF_MEMORY; @@ -75,17 +75,17 @@ nsSOCKSSocketProvider::NewSocket(int32_t NS_IMETHODIMP nsSOCKSSocketProvider::AddToSocket(int32_t family, const char *host, int32_t port, const char *proxyHost, int32_t proxyPort, uint32_t flags, - PRFileDesc *sock, + PRFileDesc *sock, nsISupports **socksInfo) { nsresult rv = nsSOCKSIOLayerAddToSocket(family, host, port, proxyHost, proxyPort, mVersion,
--- a/netwerk/test/TestSTSParser.cpp +++ b/netwerk/test/TestSTSParser.cpp @@ -44,17 +44,17 @@ TestSuccess(const char* hdr, bool extraT nsIPermissionManager* pm) { nsCOMPtr<nsIURI> dummyUri; nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html"); EXPECT_SUCCESS(rv, "Failed to create URI"); uint64_t maxAge = 0; bool includeSubdomains = false; - rv = stss->ProcessStsHeader(dummyUri, hdr, &maxAge, &includeSubdomains); + rv = stss->ProcessStsHeader(dummyUri, hdr, 0, &maxAge, &includeSubdomains); EXPECT_SUCCESS(rv, "Failed to process valid header: %s", hdr); REQUIRE_EQUAL(maxAge, expectedMaxAge, "Did not correctly parse maxAge"); REQUIRE_EQUAL(includeSubdomains, expectedIncludeSubdomains, "Did not correctly parse presence/absence of includeSubdomains"); if (extraTokens) { REQUIRE_EQUAL(rv, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA, "Extra tokens were expected when parsing, but were not encountered."); @@ -69,17 +69,17 @@ TestSuccess(const char* hdr, bool extraT bool TestFailure(const char* hdr, nsIStrictTransportSecurityService* stss, nsIPermissionManager* pm) { nsCOMPtr<nsIURI> dummyUri; nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html"); EXPECT_SUCCESS(rv, "Failed to create URI"); - rv = stss->ProcessStsHeader(dummyUri, hdr, NULL, NULL); + rv = stss->ProcessStsHeader(dummyUri, hdr, 0, NULL, NULL); EXPECT_FAILURE(rv, "Parsed invalid header: %s", hdr); passed(hdr); return true; } int main(int32_t argc, char *argv[])
--- a/security/manager/boot/src/nsStrictTransportSecurityService.cpp +++ b/security/manager/boot/src/nsStrictTransportSecurityService.cpp @@ -2,25 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "plstr.h" #include "prlog.h" #include "prprf.h" #include "nsCRTGlue.h" #include "nsIPermissionManager.h" -#include "nsIPrivateBrowsingService.h" #include "nsISSLStatus.h" #include "nsISSLStatusProvider.h" #include "nsStrictTransportSecurityService.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsThreadUtils.h" #include "nsStringGlue.h" #include "nsIScriptSecurityManager.h" +#include "nsISocketProvider.h" #include "mozilla/Preferences.h" // A note about the preload list: // When a site specifically disables sts by sending a header with // 'max-age: 0', we keep a "knockout" value that means "we have no information // regarding the sts state of this host" (any ancestor of "this host" can still // influence its sts status via include subdomains, however). // This prevents the preload list from overriding the site's current @@ -70,17 +70,17 @@ nsSTSHostEntry::nsSTSHostEntry(const nsS , mIncludeSubdomains(toCopy.mIncludeSubdomains) { } //////////////////////////////////////////////////////////////////////////////// nsStrictTransportSecurityService::nsStrictTransportSecurityService() - : mInPrivateMode(false), mUsePreloadList(true) + : mUsePreloadList(true) { } nsStrictTransportSecurityService::~nsStrictTransportSecurityService() { } NS_IMPL_THREADSAFE_ISUPPORTS2(nsStrictTransportSecurityService, @@ -90,30 +90,23 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsStrictTr nsresult nsStrictTransportSecurityService::Init() { nsresult rv; mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - // figure out if we're starting in private browsing mode - nsCOMPtr<nsIPrivateBrowsingService> pbs = - do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID); - if (pbs) - pbs->GetPrivateBrowsingEnabled(&mInPrivateMode); - mUsePreloadList = mozilla::Preferences::GetBool("network.stricttransportsecurity.preloadlist", true); mozilla::Preferences::AddStrongObserver(this, "network.stricttransportsecurity.preloadlist"); mObserverService = mozilla::services::GetObserverService(); if (mObserverService) - mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false); + mObserverService->AddObserver(this, "last-pb-context-exited", false); - if (mInPrivateMode) - mPrivateModeHostTable.Init(); + mPrivateModeHostTable.Init(); return NS_OK; } nsresult nsStrictTransportSecurityService::GetHost(nsIURI *aURI, nsACString &aResult) { nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); @@ -148,83 +141,92 @@ nsStrictTransportSecurityService::GetPri // We want all apps to share HSTS state, so this is one of the few places // where we do not silo persistent state by extended origin. return securityManager->GetNoAppCodebasePrincipal(uri, aPrincipal); } nsresult nsStrictTransportSecurityService::SetStsState(nsIURI* aSourceURI, int64_t maxage, - bool includeSubdomains) + bool includeSubdomains, + uint32_t flags) { // If max-age is zero, that's an indication to immediately remove the // permissions, so here's a shortcut. - if (!maxage) - return RemoveStsState(aSourceURI); + if (!maxage) { + return RemoveStsState(aSourceURI, flags); + } // Expire time is millis from now. Since STS max-age is in seconds, and // PR_Now() is in micros, must equalize the units at milliseconds. int64_t expiretime = (PR_Now() / PR_USEC_PER_MSEC) + (maxage * PR_MSEC_PER_SEC); + bool isPrivate = flags & nsISocketProvider::NO_PERMANENT_STORAGE; + // record entry for this host with max-age in the permissions manager STSLOG(("STS: maxage permission SET, adding permission\n")); nsresult rv = AddPermission(aSourceURI, STS_PERMISSION, (uint32_t) STS_SET, (uint32_t) nsIPermissionManager::EXPIRE_TIME, - expiretime); + expiretime, + isPrivate); NS_ENSURE_SUCCESS(rv, rv); if (includeSubdomains) { // record entry for this host with include subdomains in the permissions manager STSLOG(("STS: subdomains permission SET, adding permission\n")); rv = AddPermission(aSourceURI, STS_SUBDOMAIN_PERMISSION, (uint32_t) STS_SET, (uint32_t) nsIPermissionManager::EXPIRE_TIME, - expiretime); + expiretime, + isPrivate); NS_ENSURE_SUCCESS(rv, rv); } else { // !includeSubdomains nsAutoCString hostname; rv = GetHost(aSourceURI, hostname); NS_ENSURE_SUCCESS(rv, rv); STSLOG(("STS: subdomains permission UNSET, removing any existing ones\n")); - rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION); + rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION, isPrivate); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; } NS_IMETHODIMP -nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI) +nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI, uint32_t aFlags) { // Should be called on the main thread (or via proxy) since the permission // manager is used and it's not threadsafe. NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED); nsAutoCString hostname; nsresult rv = GetHost(aURI, hostname); NS_ENSURE_SUCCESS(rv, rv); - rv = RemovePermission(hostname, STS_PERMISSION); + bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE; + + rv = RemovePermission(hostname, STS_PERMISSION, isPrivate); NS_ENSURE_SUCCESS(rv, rv); STSLOG(("STS: deleted maxage permission\n")); - rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION); + rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION, isPrivate); NS_ENSURE_SUCCESS(rv, rv); STSLOG(("STS: deleted subdomains permission\n")); return NS_OK; } NS_IMETHODIMP nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI, const char* aHeader, + uint32_t aFlags, uint64_t *aMaxAge, bool *aIncludeSubdomains) { // Should be called on the main thread (or via proxy) since the permission // manager is used and it's not threadsafe. NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED); if (aMaxAge != nullptr) { @@ -232,25 +234,26 @@ nsStrictTransportSecurityService::Proces } if (aIncludeSubdomains != nullptr) { *aIncludeSubdomains = false; } char * header = NS_strdup(aHeader); if (!header) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = ProcessStsHeaderMutating(aSourceURI, header, aMaxAge, - aIncludeSubdomains); + nsresult rv = ProcessStsHeaderMutating(aSourceURI, header, aFlags, + aMaxAge, aIncludeSubdomains); NS_Free(header); return rv; } nsresult nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader, + uint32_t aFlags, uint64_t *aMaxAge, bool *aIncludeSubdomains) { STSLOG(("STS: ProcessStrictTransportHeader(%s)\n", aHeader)); // "Strict-Transport-Security" ":" OWS // STS-d *( OWS ";" OWS STS-d OWS) // @@ -333,44 +336,44 @@ nsStrictTransportSecurityService::Proces } // after processing all the directives, make sure we came across max-age // somewhere. STS_PARSER_FAIL_IF(!foundMaxAge, ("Parse ERROR: couldn't locate max-age token\n")); // record the successfully parsed header data. - SetStsState(aSourceURI, maxAge, includeSubdomains); + SetStsState(aSourceURI, maxAge, includeSubdomains, aFlags); if (aMaxAge != nullptr) { *aMaxAge = (uint64_t)maxAge; } if (aIncludeSubdomains != nullptr) { *aIncludeSubdomains = includeSubdomains; } return foundUnrecognizedTokens ? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA : NS_OK; } NS_IMETHODIMP -nsStrictTransportSecurityService::IsStsHost(const char* aHost, bool* aResult) +nsStrictTransportSecurityService::IsStsHost(const char* aHost, uint32_t aFlags, bool* aResult) { // Should be called on the main thread (or via proxy) since the permission // manager is used and it's not threadsafe. NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED); nsCOMPtr<nsIURI> uri; nsDependentCString hostString(aHost); nsresult rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostString); NS_ENSURE_SUCCESS(rv, rv); - return IsStsURI(uri, aResult); + return IsStsURI(uri, aFlags, aResult); } int STSPreloadCompare(const void *key, const void *entry) { const char *keyStr = (const char *)key; const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry; return strcmp(keyStr, preloadEntry->mHost); } @@ -396,33 +399,34 @@ nsStrictTransportSecurityService::GetPre sizeof(nsSTSPreload), STSPreloadCompare); } return nullptr; } NS_IMETHODIMP -nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, bool* aResult) +nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, uint32_t aFlags, bool* aResult) { // Should be called on the main thread (or via proxy) since the permission // manager is used and it's not threadsafe. NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED); // set default in case if we can't find any STS information *aResult = false; nsAutoCString host; nsresult rv = GetHost(aURI, host); NS_ENSURE_SUCCESS(rv, rv); const nsSTSPreload *preload = nullptr; nsSTSHostEntry *pbEntry = nullptr; - if (mInPrivateMode) { + bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE; + if (isPrivate) { pbEntry = mPrivateModeHostTable.GetEntry(host.get()); } nsCOMPtr<nsIPrincipal> principal; rv = GetPrincipalForURI(aURI, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); uint32_t permMgrPermission; @@ -474,17 +478,17 @@ nsStrictTransportSecurityService::IsStsU subdomain = host.get() + offset; // If we get an empty string, don't continue. if (strlen(subdomain) < 1) { break; } - if (mInPrivateMode) { + if (isPrivate) { pbEntry = mPrivateModeHostTable.GetEntry(subdomain); } // normalize all URIs with https:// rv = NS_NewURI(getter_AddRefs(domainWalkURI), NS_LITERAL_CSTRING("https://") + Substring(host, offset)); NS_ENSURE_SUCCESS(rv, rv); @@ -575,30 +579,18 @@ nsStrictTransportSecurityService::Should // nsStrictTransportSecurityService::nsIObserver //------------------------------------------------------------ NS_IMETHODIMP nsStrictTransportSecurityService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data) { - if (strcmp(topic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) { - if(NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(data)) { - // Indication to start recording stuff locally and not writing changes - // out to the permission manager. - - if (!mPrivateModeHostTable.IsInitialized()) { - mPrivateModeHostTable.Init(); - } - mInPrivateMode = true; - } - else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(data)) { - mPrivateModeHostTable.Clear(); - mInPrivateMode = false; - } + if (strcmp(topic, "last-pb-context-exited") == 0) { + mPrivateModeHostTable.Clear(); } else if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { mUsePreloadList = mozilla::Preferences::GetBool("network.stricttransportsecurity.preloadlist", true); } return NS_OK; } @@ -606,21 +598,22 @@ nsStrictTransportSecurityService::Observ // Functions to overlay the permission manager calls in case // we're in private browsing mode. //------------------------------------------------------------ nsresult nsStrictTransportSecurityService::AddPermission(nsIURI *aURI, const char *aType, uint32_t aPermission, uint32_t aExpireType, - int64_t aExpireTime) + int64_t aExpireTime, + bool aIsPrivate) { // Private mode doesn't address user-set (EXPIRE_NEVER) permissions: let // those be stored persistently. - if (!mInPrivateMode || aExpireType == nsIPermissionManager::EXPIRE_NEVER) { + if (!aIsPrivate || aExpireType == nsIPermissionManager::EXPIRE_NEVER) { // Not in private mode, or manually-set permission nsCOMPtr<nsIPrincipal> principal; nsresult rv = GetPrincipalForURI(aURI, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); return mPermMgr->AddFromPrincipal(principal, aType, aPermission, aExpireType, aExpireTime); } @@ -662,30 +655,31 @@ nsStrictTransportSecurityService::AddPer // Also refresh the expiration time. entry->SetExpireTime(aExpireTime); return NS_OK; } nsresult nsStrictTransportSecurityService::RemovePermission(const nsCString &aHost, - const char *aType) + const char *aType, + bool aIsPrivate) { // Build up a principal for use with the permission manager. // normalize all URIs with https:// nsCOMPtr<nsIURI> uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + aHost); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIPrincipal> principal; rv = GetPrincipalForURI(uri, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); - if (!mInPrivateMode) { + if (!aIsPrivate) { // Not in private mode: remove permissions persistently. // This means setting the permission to STS_KNOCKOUT in case // this host is on the preload list (so we can override it). return mPermMgr->AddFromPrincipal(principal, aType, STS_KNOCKOUT, nsIPermissionManager::EXPIRE_NEVER, 0); }
--- a/security/manager/boot/src/nsStrictTransportSecurityService.h +++ b/security/manager/boot/src/nsStrictTransportSecurityService.h @@ -130,32 +130,33 @@ public: nsStrictTransportSecurityService(); nsresult Init(); virtual ~nsStrictTransportSecurityService(); private: nsresult GetHost(nsIURI *aURI, nsACString &aResult); nsresult GetPrincipalForURI(nsIURI *aURI, nsIPrincipal **aPrincipal); - nsresult SetStsState(nsIURI* aSourceURI, int64_t maxage, bool includeSubdomains); - nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader, + nsresult SetStsState(nsIURI* aSourceURI, int64_t maxage, bool includeSubdomains, uint32_t flags); + nsresult ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader, uint32_t flags, uint64_t *aMaxAge, bool *aIncludeSubdomains); const nsSTSPreload *GetPreloadListEntry(const char *aHost); // private-mode-preserving permission manager overlay functions nsresult AddPermission(nsIURI *aURI, const char *aType, uint32_t aPermission, uint32_t aExpireType, - int64_t aExpireTime); + int64_t aExpireTime, + bool aIsPrivate); nsresult RemovePermission(const nsCString &aHost, - const char *aType); + const char *aType, + bool aIsPrivate); // cached services nsCOMPtr<nsIPermissionManager> mPermMgr; nsCOMPtr<nsIObserverService> mObserverService; - bool mInPrivateMode; nsTHashtable<nsSTSHostEntry> mPrivateModeHostTable; bool mUsePreloadList; }; #endif // __nsStrictTransportSecurityService_h__
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp @@ -288,17 +288,24 @@ CertErrorRunnable::CheckCertOverrides() // Enforce Strict-Transport-Security for hosts that are "STS" hosts: // connections must be dropped when there are any certificate errors // (STS Spec section 7.3). bool strictTransportSecurityEnabled = false; nsCOMPtr<nsIStrictTransportSecurityService> stss = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv); if (NS_SUCCEEDED(nsrv)) { + nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface( + NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject)); + uint32_t flags = 0; + if (sslSocketControl) { + sslSocketControl->GetProviderFlags(&flags); + } nsrv = stss->IsStsHost(mInfoObject->GetHostName(), + flags, &strictTransportSecurityEnabled); } if (NS_FAILED(nsrv)) { return new SSLServerCertVerificationResult(mInfoObject, mDefaultErrorCodeToReport); } if (!strictTransportSecurityEnabled) {
--- a/security/manager/ssl/src/TransportSecurityInfo.h +++ b/security/manager/ssl/src/TransportSecurityInfo.h @@ -12,16 +12,17 @@ #include "mozilla/RefPtr.h" #include "nsIInterfaceRequestor.h" #include "nsITransportSecurityInfo.h" #include "nsSSLStatus.h" #include "nsISSLStatusProvider.h" #include "nsIAssociatedContentSecurity.h" #include "nsNSSShutDown.h" #include "nsDataHashtable.h" +#include "nsISocketTransport.h" namespace mozilla { namespace psm { enum SSLErrorMessageType { OverridableCertErrorMessage = 1, // for *overridable* certificate errors PlainErrorMessage = 2 // all other errors (or "no error") };
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -56,40 +56,48 @@ static NS_DEFINE_CID(kNSSComponentCID, N typedef enum {ASK, AUTO} SSM_UserCertChoice; } // unnamed namespace #ifdef PR_LOGGING extern PRLogModuleInfo* gPIPNSSLog; #endif -nsNSSSocketInfo::nsNSSSocketInfo() +nsNSSSocketInfo::nsNSSSocketInfo(uint32_t providerFlags) : mFd(nullptr), mCertVerificationState(before_cert_verification), mForSTARTTLS(false), mSSL3Enabled(false), mTLSEnabled(false), mHandshakePending(true), mHasCleartextPhase(false), mHandshakeInProgress(false), mAllowTLSIntoleranceTimeout(true), mRememberClientAuthCertificate(false), mHandshakeStartTime(0), mFirstServerHelloReceived(false), mNPNCompleted(false), mHandshakeCompleted(false), mJoined(false), - mSentClientCert(false) + mSentClientCert(false), + mProviderFlags(providerFlags) { } NS_IMPL_ISUPPORTS_INHERITED2(nsNSSSocketInfo, TransportSecurityInfo, nsISSLSocketControl, nsIClientAuthUserDecision) +NS_IMETHODIMP +nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags) +{ + *aProviderFlags = mProviderFlags; + return NS_OK; +} + nsresult nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending) { *aHandshakePending = mHandshakePending; return NS_OK; } nsresult @@ -1307,24 +1315,24 @@ nsresult nsSSLIOLayerNewSocket(int32_t family, const char *host, int32_t port, const char *proxyHost, int32_t proxyPort, PRFileDesc **fd, nsISupports** info, bool forSTARTTLS, - bool anonymousLoad) + uint32_t flags) { PRFileDesc* sock = PR_OpenTCPSocket(family); if (!sock) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort, - sock, info, forSTARTTLS, anonymousLoad); + sock, info, forSTARTTLS, flags); if (NS_FAILED(rv)) { PR_Close(sock); return rv; } *fd = sock; return NS_OK; } @@ -2304,30 +2312,31 @@ done: if (mRV == SECFailure) { mErrorCodeToReport = error; } } static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc *fd, nsNSSSocketInfo *infoObject, - const char *host, - bool anonymousLoad) + const char *host) { nsNSSShutDownPreventionLock locker; PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd); if (!sslSock) { NS_ASSERTION(false, "NSS: Error importing socket"); return nullptr; } SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject); SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject); // Disable this hook if we connect anonymously. See bug 466080. - if (anonymousLoad) { + uint32_t flags = 0; + infoObject->GetProviderFlags(&flags); + if (flags & nsISocketTransport::ANONYMOUS_CONNECT) { SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject); } else { SSL_GetClientAuthDataHook(sslSock, (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData, infoObject); } if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook, infoObject)) { @@ -2423,32 +2432,33 @@ nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port, const char* proxyHost, int32_t proxyPort, PRFileDesc* fd, nsISupports** info, bool forSTARTTLS, - bool anonymousLoad) + uint32_t providerFlags) { nsNSSShutDownPreventionLock locker; PRFileDesc* layer = nullptr; nsresult rv; PRStatus stat; - nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(); + nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(providerFlags); if (!infoObject) return NS_ERROR_FAILURE; NS_ADDREF(infoObject); infoObject->SetForSTARTTLS(forSTARTTLS); infoObject->SetHostName(host); infoObject->SetPort(port); - PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host, anonymousLoad); + bool anonymousLoad = providerFlags & nsISocketProvider::ANONYMOUS_CONNECT; + PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host); if (!sslSock) { NS_ASSERTION(false, "NSS: Error importing socket"); goto loser; } infoObject->SetFileDescPtr(sslSock); rv = nsSSLIOLayerSetOptions(sslSock,
--- a/security/manager/ssl/src/nsNSSIOLayer.h +++ b/security/manager/ssl/src/nsNSSIOLayer.h @@ -8,23 +8,24 @@ #define _NSNSSIOLAYER_H #include "TransportSecurityInfo.h" #include "nsISSLSocketControl.h" #include "nsIClientAuthDialogs.h" #include "nsNSSCertificate.h" #include "nsDataHashtable.h" #include "nsTHashtable.h" +#include "nsISocketTransport.h" class nsNSSSocketInfo : public mozilla::psm::TransportSecurityInfo, public nsISSLSocketControl, public nsIClientAuthUserDecision { public: - nsNSSSocketInfo(); + nsNSSSocketInfo(uint32_t providerFlags); NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSISSLSOCKETCONTROL NS_DECL_NSICLIENTAUTHUSERDECISION nsresult SetForSTARTTLS(bool aForSTARTTLS); nsresult GetForSTARTTLS(bool *aForSTARTTLS); @@ -67,17 +68,17 @@ public: void SetCertVerificationResult(PRErrorCode errorCode, ::mozilla::psm::SSLErrorMessageType errorMessageType); // for logging only PRBool IsWaitingForCertVerification() const { return mCertVerificationState == waiting_for_cert_verification; } - + bool IsSSL3Enabled() const { return mSSL3Enabled; } void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; } bool IsTLSEnabled() const { return mTLSEnabled; } void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; } private: PRFileDesc* mFd; CertVerificationState mCertVerificationState; @@ -95,16 +96,18 @@ private: nsresult ActivateSSL(); nsCString mNegotiatedNPN; bool mNPNCompleted; bool mHandshakeCompleted; bool mJoined; bool mSentClientCert; + + uint32_t mProviderFlags; }; class nsSSLIOLayerHelpers { public: static nsresult Init(); static void Cleanup(); @@ -141,24 +144,24 @@ public: nsresult nsSSLIOLayerNewSocket(int32_t family, const char *host, int32_t port, const char *proxyHost, int32_t proxyPort, PRFileDesc **fd, nsISupports **securityInfo, bool forSTARTTLS, - bool anonymousLoad); + uint32_t flags); nsresult nsSSLIOLayerAddToSocket(int32_t family, const char *host, int32_t port, const char *proxyHost, int32_t proxyPort, PRFileDesc *fd, nsISupports **securityInfo, bool forSTARTTLS, - bool anonymousLoad); + uint32_t flags); nsresult nsSSLIOLayerFreeTLSIntolerantSites(); nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo *infoObject, int error); #endif /* _NSNSSIOLAYER_H */
--- a/security/manager/ssl/src/nsSSLSocketProvider.cpp +++ b/security/manager/ssl/src/nsSSLSocketProvider.cpp @@ -31,17 +31,17 @@ nsSSLSocketProvider::NewSocket(int32_t f nsresult rv = nsSSLIOLayerNewSocket(family, host, port, proxyHost, proxyPort, _result, securityInfo, false, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } // Add the SSL IO layer to an existing socket NS_IMETHODIMP nsSSLSocketProvider::AddToSocket(int32_t family, const char *host, int32_t port, @@ -54,12 +54,12 @@ nsSSLSocketProvider::AddToSocket(int32_t nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort, aSocket, securityInfo, false, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; }
--- a/security/manager/ssl/src/nsTLSSocketProvider.cpp +++ b/security/manager/ssl/src/nsTLSSocketProvider.cpp @@ -31,17 +31,17 @@ nsTLSSocketProvider::NewSocket(int32_t f nsresult rv = nsSSLIOLayerNewSocket(family, host, port, proxyHost, proxyPort, _result, securityInfo, true, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } // Add the SSL IO layer to an existing socket NS_IMETHODIMP nsTLSSocketProvider::AddToSocket(int32_t family, const char *host, @@ -55,12 +55,12 @@ nsTLSSocketProvider::AddToSocket(int32_t nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort, aSocket, securityInfo, true, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; }
--- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html +++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html @@ -49,17 +49,17 @@ // clean up the STS state netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); const Cc = Components.classes; const Ci = Components.interfaces; var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var thehost = ios.newURI("http://example.com", null, null); var stss = Cc["@mozilla.org/stsservice;1"].getService(Ci.nsIStrictTransportSecurityService); - stss.removeStsState(thehost); + stss.removeStsState(thehost, 0); } function loadVerifyFrames(round) { for (var test in testframes) { var frame = document.createElement("iframe"); frame.setAttribute('id', 'ifr_' + test); frame.setAttribute('src', testframes[test].url + '?id=' + test); document.body.appendChild(frame);
--- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html +++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html @@ -166,26 +166,36 @@ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); const Cc = Components.classes; const Ci = Components.interfaces; var ios = Cc["@mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService); var thehost = ios.newURI("http://example.com", null, null); var stss = Cc["@mozilla.org/stsservice;1"] .getService(Ci.nsIStrictTransportSecurityService); - stss.removeStsState(thehost); + var loadContext = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsILoadContext); + var flags = loadContext.usePrivateBrowsing ? + Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0 + stss.removeStsState(thehost, flags); dump_STSState(); SimpleTest.executeSoon(nextTest); } function dump_STSState() { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var stss = Components.classes["@mozilla.org/stsservice;1"] .getService(Components.interfaces.nsIStrictTransportSecurityService); - SimpleTest.info("State of example.com: " + stss.isStsHost("example.com")); + var loadContext = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsILoadContext); + var flags = loadContext.usePrivateBrowsing ? + Components.interfaces.nsISocketProvider.NO_PERMANENT_STORAGE : 0 + SimpleTest.info("State of example.com: " + stss.isStsHost("example.com", flags)); } // these are executed in the order presented. // 0. test that STS works before entering private browsing mode. // (load sts-bootstrapped "plain" tests) // ... clear any STS data ... var tests = [ test_sts_before_private_mode,
--- a/security/manager/ssl/tests/unit/test_bug627234.js +++ b/security/manager/ssl/tests/unit/test_bug627234.js @@ -1,75 +1,64 @@ var Cc = Components.classes; var Ci = Components.interfaces; Components.utils.import("resource://gre/modules/Services.jsm"); -var _PBSvc = null; -function get_PBSvc() { - if (_PBSvc) - return _PBSvc; - - try { - _PBSvc = Cc["@mozilla.org/privatebrowsing;1"] - .getService(Ci.nsIPrivateBrowsingService); - return _PBSvc; - } catch (e) {} - return null; -} - var gSTSService = Cc["@mozilla.org/stsservice;1"] .getService(Ci.nsIStrictTransportSecurityService); -function Observer() {} -Observer.prototype = { - observe: function(subject, topic, data) { - do_execute_soon(gNextTest); - } -}; - -var gObserver = new Observer(); var gNextTest = null; function cleanup() { - Services.obs.removeObserver(gObserver, "private-browsing-transition-complete"); - get_PBSvc().privateBrowsingEnabled = false; + leavePB(); // (we have to remove any state added to the sts service so as to not muck // with other tests). var uri = Services.io.newURI("http://localhost", null, null); - gSTSService.removeStsState(uri); + gSTSService.removeStsState(uri, privacyFlags()); } function run_test() { - let pb = get_PBSvc(); - if (pb) { - do_test_pending(); - do_register_cleanup(cleanup); + do_test_pending(); + do_register_cleanup(cleanup); + + gNextTest = test_part1; + enterPB(); +} - gNextTest = test_part1; - Services.obs.addObserver(gObserver, "private-browsing-transition-complete", false); - Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true); - pb.privateBrowsingEnabled = true; - } +var gInPrivate = false; +function enterPB() { + gInPrivate = true; + do_execute_soon(gNextTest); +} + +function leavePB() { + gInPrivate = false; + Services.obs.notifyObservers(null, "last-pb-context-exited", null); + do_execute_soon(gNextTest); +} + +function privacyFlags() { + return gInPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0; } function test_part1() { var uri = Services.io.newURI("https://localhost/img.png", null, null); - gSTSService.processStsHeader(uri, "max-age=1000"); - do_check_true(gSTSService.isStsHost("localhost")); + gSTSService.processStsHeader(uri, "max-age=1000", privacyFlags()); + do_check_true(gSTSService.isStsHost("localhost", privacyFlags())); gNextTest = test_part2; - get_PBSvc().privateBrowsingEnabled = false; + leavePB(); } function test_part2() { var uri = Services.io.newURI("https://localhost/img.png", null, null); - gSTSService.processStsHeader(uri, "max-age=1000"); - do_check_true(gSTSService.isStsHost("localhost")); + gSTSService.processStsHeader(uri, "max-age=1000", privacyFlags()); + do_check_true(gSTSService.isStsHost("localhost", privacyFlags())); gNextTest = test_part3; - get_PBSvc().privateBrowsingEnabled = true; + enterPB(); } function test_part3() { var uri = Services.io.newURI("https://localhost/img.png", null, null); - gSTSService.processStsHeader(uri, "max-age=1000"); - do_check_true(gSTSService.isStsHost("localhost")); + gSTSService.processStsHeader(uri, "max-age=1000", privacyFlags()); + do_check_true(gSTSService.isStsHost("localhost", privacyFlags())); do_test_finished(); }
--- a/security/manager/ssl/tests/unit/test_sts_preloadlist.js +++ b/security/manager/ssl/tests/unit/test_sts_preloadlist.js @@ -41,17 +41,17 @@ var hosts = ["http://keyerror.com", "htt function cleanup() { Services.obs.removeObserver(gObserver, "private-browsing-transition-complete"); if (getPBSvc()) getPBSvc().privateBrowsingEnabled = false; for (var host of hosts) { var uri = Services.io.newURI(host, null, null); - gSTSService.removeStsState(uri); + gSTSService.removeStsState(uri, 0); } } function run_test() { do_register_cleanup(cleanup); Services.obs.addObserver(gObserver, "private-browsing-transition-complete", false); Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true); @@ -61,154 +61,156 @@ function run_test() { add_test(test_private_browsing2); } run_next_test(); } function test_part1() { // check that a host not in the list is not identified as an sts host - do_check_false(gSTSService.isStsHost("nonexistent.mozilla.com")); + do_check_false(gSTSService.isStsHost("nonexistent.mozilla.com", 0)); // check that an ancestor domain is not identified as an sts host - do_check_false(gSTSService.isStsHost("com")); + do_check_false(gSTSService.isStsHost("com", 0)); // Note: the following were taken from the STS preload list // as of Sept. 2012. If the list changes, this test will need to be modified. // check that the pref to toggle using the preload list works Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false); - do_check_false(gSTSService.isStsHost("factor.cc")); + do_check_false(gSTSService.isStsHost("factor.cc", 0)); Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", true); - do_check_true(gSTSService.isStsHost("factor.cc")); + do_check_true(gSTSService.isStsHost("factor.cc", 0)); // check that an entry at the beginning of the list is an sts host - do_check_true(gSTSService.isStsHost("arivo.com.br")); + do_check_true(gSTSService.isStsHost("arivo.com.br", 0)); // check that a subdomain is an sts host (includeSubdomains is set) - do_check_true(gSTSService.isStsHost("subdomain.arivo.com.br")); + do_check_true(gSTSService.isStsHost("subdomain.arivo.com.br", 0)); // check that another subdomain is an sts host (includeSubdomains is set) - do_check_true(gSTSService.isStsHost("a.b.c.subdomain.arivo.com.br")); + do_check_true(gSTSService.isStsHost("a.b.c.subdomain.arivo.com.br", 0)); // check that an entry in the middle of the list is an sts host - do_check_true(gSTSService.isStsHost("neg9.org")); + do_check_true(gSTSService.isStsHost("neg9.org", 0)); // check that a subdomain is not an sts host (includeSubdomains is not set) - do_check_false(gSTSService.isStsHost("subdomain.neg9.org")); + do_check_false(gSTSService.isStsHost("subdomain.neg9.org", 0)); // check that an entry at the end of the list is an sts host - do_check_true(gSTSService.isStsHost("www.noisebridge.net")); + do_check_true(gSTSService.isStsHost("www.noisebridge.net", 0)); // check that a subdomain is not an sts host (includeSubdomains is not set) - do_check_false(gSTSService.isStsHost("a.subdomain.www.noisebridge.net")); + do_check_false(gSTSService.isStsHost("a.subdomain.www.noisebridge.net", 0)); // check that a host with a dot on the end won't break anything - do_check_false(gSTSService.isStsHost("notsts.nonexistent.mozilla.com.")); + do_check_false(gSTSService.isStsHost("notsts.nonexistent.mozilla.com.", 0)); // check that processing a header with max-age: 0 will remove a preloaded // site from the list var uri = Services.io.newURI("http://keyerror.com", null, null); - gSTSService.processStsHeader(uri, "max-age=0"); - do_check_false(gSTSService.isStsHost("keyerror.com")); - do_check_false(gSTSService.isStsHost("subdomain.keyerror.com")); + gSTSService.processStsHeader(uri, "max-age=0", 0); + do_check_false(gSTSService.isStsHost("keyerror.com", 0)); + do_check_false(gSTSService.isStsHost("subdomain.keyerror.com", 0)); // check that processing another header (with max-age non-zero) will // re-enable a site's sts status - gSTSService.processStsHeader(uri, "max-age=1000"); - do_check_true(gSTSService.isStsHost("keyerror.com")); + gSTSService.processStsHeader(uri, "max-age=1000", 0); + do_check_true(gSTSService.isStsHost("keyerror.com", 0)); // but this time include subdomains was not set, so test for that - do_check_false(gSTSService.isStsHost("subdomain.keyerror.com")); + do_check_false(gSTSService.isStsHost("subdomain.keyerror.com", 0)); // check that processing a header with max-age: 0 from a subdomain of a site // will not remove that (ancestor) site from the list var uri = Services.io.newURI("http://subdomain.intercom.io", null, null); - gSTSService.processStsHeader(uri, "max-age=0"); - do_check_true(gSTSService.isStsHost("intercom.io")); - do_check_false(gSTSService.isStsHost("subdomain.intercom.io")); + gSTSService.processStsHeader(uri, "max-age=0", 0); + do_check_true(gSTSService.isStsHost("intercom.io", 0)); + do_check_false(gSTSService.isStsHost("subdomain.intercom.io", 0)); var uri = Services.io.newURI("http://subdomain.pixi.me", null, null); - gSTSService.processStsHeader(uri, "max-age=0"); + gSTSService.processStsHeader(uri, "max-age=0", 0); // we received a header with "max-age=0", so we have "no information" // regarding the sts state of subdomain.pixi.me specifically, but // it is actually still an STS host, because of the preloaded pixi.me // including subdomains. // Here's a drawing: // |-- pixi.me (in preload list, includes subdomains) IS sts host // |-- subdomain.pixi.me IS sts host // | `-- another.subdomain.pixi.me IS sts host // `-- sibling.pixi.me IS sts host - do_check_true(gSTSService.isStsHost("subdomain.pixi.me")); - do_check_true(gSTSService.isStsHost("sibling.pixi.me")); - do_check_true(gSTSService.isStsHost("another.subdomain.pixi.me")); + do_check_true(gSTSService.isStsHost("subdomain.pixi.me", 0)); + do_check_true(gSTSService.isStsHost("sibling.pixi.me", 0)); + do_check_true(gSTSService.isStsHost("another.subdomain.pixi.me", 0)); - gSTSService.processStsHeader(uri, "max-age=1000"); + gSTSService.processStsHeader(uri, "max-age=1000", 0); // Here's what we have now: // |-- pixi.me (in preload list, includes subdomains) IS sts host // |-- subdomain.pixi.me (include subdomains is false) IS sts host // | `-- another.subdomain.pixi.me IS NOT sts host // `-- sibling.pixi.me IS sts host - do_check_true(gSTSService.isStsHost("subdomain.pixi.me")); - do_check_true(gSTSService.isStsHost("sibling.pixi.me")); - do_check_false(gSTSService.isStsHost("another.subdomain.pixi.me")); + do_check_true(gSTSService.isStsHost("subdomain.pixi.me", 0)); + do_check_true(gSTSService.isStsHost("sibling.pixi.me", 0)); + do_check_false(gSTSService.isStsHost("another.subdomain.pixi.me", 0)); // Test private browsing correctly interacts with removing preloaded sites. // If we don't have the private browsing service, don't run those tests // (which means we have to manually call run_next_test() instead of relying // on our observer to call it). if (getPBSvc()) { getPBSvc().privateBrowsingEnabled = true; } else { run_next_test(); } } +const IS_PRIVATE = Ci.nsISocketProvider.NO_PERMANENT_STORAGE; + function test_private_browsing1() { // sanity - crypto.cat is preloaded, includeSubdomains set - do_check_true(gSTSService.isStsHost("crypto.cat")); - do_check_true(gSTSService.isStsHost("a.b.c.subdomain.crypto.cat")); + do_check_true(gSTSService.isStsHost("crypto.cat", IS_PRIVATE)); + do_check_true(gSTSService.isStsHost("a.b.c.subdomain.crypto.cat", IS_PRIVATE)); var uri = Services.io.newURI("http://crypto.cat", null, null); - gSTSService.processStsHeader(uri, "max-age=0"); - do_check_false(gSTSService.isStsHost("crypto.cat")); - do_check_false(gSTSService.isStsHost("a.b.subdomain.crypto.cat")); + gSTSService.processStsHeader(uri, "max-age=0", IS_PRIVATE); + do_check_false(gSTSService.isStsHost("crypto.cat", IS_PRIVATE)); + do_check_false(gSTSService.isStsHost("a.b.subdomain.crypto.cat", IS_PRIVATE)); // check adding it back in - gSTSService.processStsHeader(uri, "max-age=1000"); - do_check_true(gSTSService.isStsHost("crypto.cat")); + gSTSService.processStsHeader(uri, "max-age=1000", IS_PRIVATE); + do_check_true(gSTSService.isStsHost("crypto.cat", IS_PRIVATE)); // but no includeSubdomains this time - do_check_false(gSTSService.isStsHost("b.subdomain.crypto.cat")); + do_check_false(gSTSService.isStsHost("b.subdomain.crypto.cat", IS_PRIVATE)); // do the hokey-pokey... - gSTSService.processStsHeader(uri, "max-age=0"); - do_check_false(gSTSService.isStsHost("crypto.cat")); - do_check_false(gSTSService.isStsHost("subdomain.crypto.cat")); + gSTSService.processStsHeader(uri, "max-age=0", IS_PRIVATE); + do_check_false(gSTSService.isStsHost("crypto.cat", IS_PRIVATE)); + do_check_false(gSTSService.isStsHost("subdomain.crypto.cat", IS_PRIVATE)); // TODO unfortunately we don't have a good way to know when an entry // has expired in the permission manager, so we can't yet extend this test // to that case. // Test that an expired private browsing entry results in correctly // identifying a host that is on the preload list as no longer sts. // (This happens when we're in private browsing mode, we get a header from // a site on the preload list, and that header later expires. We need to // then treat that host as no longer an sts host.) // (sanity check first - this should be in the preload list) - do_check_true(gSTSService.isStsHost("logentries.com")); + do_check_true(gSTSService.isStsHost("logentries.com", IS_PRIVATE)); var uri = Services.io.newURI("http://logentries.com", null, null); // according to the rfc, max-age can't be negative, but this is a great // way to test an expired entry - gSTSService.processStsHeader(uri, "max-age=-1000"); - do_check_false(gSTSService.isStsHost("logentries.com")); + gSTSService.processStsHeader(uri, "max-age=-1000", IS_PRIVATE); + do_check_false(gSTSService.isStsHost("logentries.com", IS_PRIVATE)); // if this test gets this far, it means there's a private browsing service getPBSvc().privateBrowsingEnabled = false; } function test_private_browsing2() { // if this test gets this far, it means there's a private browsing service - do_check_true(gSTSService.isStsHost("crypto.cat")); + do_check_true(gSTSService.isStsHost("crypto.cat", 0)); // the crypto.cat entry has includeSubdomains set - do_check_true(gSTSService.isStsHost("subdomain.crypto.cat")); + do_check_true(gSTSService.isStsHost("subdomain.crypto.cat", 0)); // Now that we're out of private browsing mode, we need to make sure // we've "forgotten" that we "forgot" this site's sts status. - do_check_true(gSTSService.isStsHost("logentries.com")); + do_check_true(gSTSService.isStsHost("logentries.com", 0)); run_next_test(); }