diff --git a/browser/components/search/content/search.xml b/browser/components/search/content/search.xml index 0da1d1fec5f4..81816b51fe97 100644 --- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -498,12 +498,15 @@ var connector = Services.io.QueryInterface(Components.interfaces.nsISpeculativeConnect); var searchURI = engine.getSubmission("dummy").uri; - connector.speculativeConnect(searchURI, null); + let callbacks = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.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); } ]]> diff --git a/content/base/test/test_websocket.html b/content/base/test/test_websocket.html index 0491722a6943..d05156107e50 100644 --- a/content/base/test/test_websocket.html +++ b/content/base/test/test_websocket.html @@ -1233,7 +1233,13 @@ function test41() 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); } } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 66aff328a786..d096fa0f3783 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -114,6 +114,7 @@ #include "nsIObserver.h" #include "nsINestedURI.h" #include "nsITransportSecurityInfo.h" +#include "nsISSLSocketControl.h" #include "nsINSSErrorsService.h" #include "nsIApplicationCache.h" #include "nsIApplicationCacheChannel.h" @@ -4174,9 +4175,14 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, nsCOMPtr stss = do_GetService(NS_STSSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - + uint32_t flags = 0; + nsCOMPtr 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; diff --git a/netwerk/base/public/nsISocketTransport.idl b/netwerk/base/public/nsISocketTransport.idl index 8faf476967bd..2a848a352d97 100644 --- a/netwerk/base/public/nsISocketTransport.idl +++ b/netwerk/base/public/nsISocketTransport.idl @@ -150,6 +150,16 @@ interface nsISocketTransport : nsITransport */ 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 diff --git a/netwerk/base/public/nsIStrictTransportSecurityService.idl b/netwerk/base/public/nsIStrictTransportSecurityService.idl index b65ace8797d7..d7ea728f1c6c 100644 --- a/netwerk/base/public/nsIStrictTransportSecurityService.idl +++ b/netwerk/base/public/nsIStrictTransportSecurityService.idl @@ -8,7 +8,7 @@ interface nsIURI; interface nsIObserver; interface nsIHttpChannel; -[scriptable, uuid(aee925d1-2bc9-469e-9582-b27b1d6b5192)] +[scriptable, uuid(c6138514-f212-4747-98c2-7abfce3be293)] interface nsIStrictTransportSecurityService : nsISupports { /** @@ -20,6 +20,8 @@ interface nsIStrictTransportSecurityService : nsISupports * * @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 @@ -29,6 +31,7 @@ interface nsIStrictTransportSecurityService : nsISupports */ void processStsHeader(in nsIURI aSourceURI, in string aHeader, + in uint32_t aFlags, [optional] out unsigned long long aMaxAge, [optional] out boolean aIncludeSubdomains); @@ -36,8 +39,12 @@ interface nsIStrictTransportSecurityService : nsISupports * 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 @@ -51,8 +58,10 @@ interface nsIStrictTransportSecurityService : nsISupports * 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. @@ -63,8 +72,10 @@ interface nsIStrictTransportSecurityService : nsISupports * 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); }; diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp index 33ac94c94644..8e0b45efa7be 100644 --- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -977,6 +977,9 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us if (mConnectionFlags & nsISocketTransport::ANONYMOUS_CONNECT) proxyFlags |= nsISocketProvider::ANONYMOUS_CONNECT; + if (mConnectionFlags & nsISocketTransport::NO_PERMANENT_STORAGE) + proxyFlags |= nsISocketProvider::NO_PERMANENT_STORAGE; + nsCOMPtr secinfo; if (i == 0) { // if this is the first type, we'll want the diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 03d059228dce..0a7bb0793465 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -370,7 +370,8 @@ nsHttpChannel::Connect() 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. @@ -1112,7 +1113,9 @@ nsHttpChannel::ProcessSTSHeader() // 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); @@ -1140,7 +1143,7 @@ nsHttpChannel::ProcessSTSHeader() // 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; diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 7f4848e5349e..b4b14f26aa25 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2457,6 +2457,9 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport, 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 diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index babff35f94b8..ef3a2b87d349 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -1620,8 +1620,12 @@ nsHttpHandler::SpeculativeConnect(nsIURI *aURI, if (!stss) return NS_OK; + nsCOMPtr loadContext = do_GetInterface(aCallbacks); + uint32_t flags = 0; + if (loadContext && loadContext->UsePrivateBrowsing()) + flags |= nsISocketProvider::NO_PERMANENT_STORAGE; nsCOMPtr 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(); diff --git a/netwerk/socket/nsISSLSocketControl.idl b/netwerk/socket/nsISSLSocketControl.idl index 345c86dad6c7..b01dbe70c1e5 100644 --- a/netwerk/socket/nsISSLSocketControl.idl +++ b/netwerk/socket/nsISSLSocketControl.idl @@ -14,7 +14,7 @@ class nsCString; %} [ref] native nsCStringTArrayRef(nsTArray); -[scriptable, uuid(753f0f13-681d-4de3-a6c6-11aa7e0b3afd)] +[scriptable, uuid(bb2bb490-3ba4-4254-b8f5-8b43c7b714ea)] interface nsISSLSocketControl : nsISupports { attribute nsIInterfaceRequestor notificationCallbacks; @@ -49,6 +49,10 @@ interface nsISSLSocketControl : nsISupports { 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; }; diff --git a/netwerk/socket/nsISocketProvider.idl b/netwerk/socket/nsISocketProvider.idl index 469b9bfbf5af..57f6c4d7060a 100644 --- a/netwerk/socket/nsISocketProvider.idl +++ b/netwerk/socket/nsISocketProvider.idl @@ -81,7 +81,16 @@ interface nsISocketProvider : nsISupports * 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++ diff --git a/netwerk/socket/nsSOCKSSocketProvider.cpp b/netwerk/socket/nsSOCKSSocketProvider.cpp index bd56f369cd2f..63ed38ceb547 100644 --- a/netwerk/socket/nsSOCKSSocketProvider.cpp +++ b/netwerk/socket/nsSOCKSSocketProvider.cpp @@ -47,7 +47,7 @@ nsSOCKSSocketProvider::NewSocket(int32_t family, const char *proxyHost, int32_t proxyPort, uint32_t flags, - PRFileDesc **result, + PRFileDesc **result, nsISupports **socksInfo) { PRFileDesc *sock; @@ -80,7 +80,7 @@ nsSOCKSSocketProvider::AddToSocket(int32_t family, const char *proxyHost, int32_t proxyPort, uint32_t flags, - PRFileDesc *sock, + PRFileDesc *sock, nsISupports **socksInfo) { nsresult rv = nsSOCKSIOLayerAddToSocket(family, diff --git a/netwerk/test/TestSTSParser.cpp b/netwerk/test/TestSTSParser.cpp index 0f8469aec47b..960abe4647b1 100644 --- a/netwerk/test/TestSTSParser.cpp +++ b/netwerk/test/TestSTSParser.cpp @@ -49,7 +49,7 @@ TestSuccess(const char* hdr, bool extraTokens, 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"); @@ -74,7 +74,7 @@ bool TestFailure(const char* hdr, 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; diff --git a/security/manager/boot/src/nsStrictTransportSecurityService.cpp b/security/manager/boot/src/nsStrictTransportSecurityService.cpp index da6c36e81832..a874f79848e9 100644 --- a/security/manager/boot/src/nsStrictTransportSecurityService.cpp +++ b/security/manager/boot/src/nsStrictTransportSecurityService.cpp @@ -7,7 +7,6 @@ #include "prprf.h" #include "nsCRTGlue.h" #include "nsIPermissionManager.h" -#include "nsIPrivateBrowsingService.h" #include "nsISSLStatus.h" #include "nsISSLStatusProvider.h" #include "nsStrictTransportSecurityService.h" @@ -16,6 +15,7 @@ #include "nsThreadUtils.h" #include "nsStringGlue.h" #include "nsIScriptSecurityManager.h" +#include "nsISocketProvider.h" #include "mozilla/Preferences.h" // A note about the preload list: @@ -75,7 +75,7 @@ nsSTSHostEntry::nsSTSHostEntry(const nsSTSHostEntry& toCopy) nsStrictTransportSecurityService::nsStrictTransportSecurityService() - : mInPrivateMode(false), mUsePreloadList(true) + : mUsePreloadList(true) { } @@ -95,20 +95,13 @@ nsStrictTransportSecurityService::Init() mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - // figure out if we're starting in private browsing mode - nsCOMPtr 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; } @@ -153,25 +146,30 @@ nsStrictTransportSecurityService::GetPrincipalForURI(nsIURI* aURI, 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) { @@ -181,7 +179,8 @@ nsStrictTransportSecurityService::SetStsState(nsIURI* 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; @@ -189,14 +188,14 @@ nsStrictTransportSecurityService::SetStsState(nsIURI* aSourceURI, 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. @@ -206,11 +205,13 @@ nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI) 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")); @@ -220,6 +221,7 @@ nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI) NS_IMETHODIMP nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI, const char* aHeader, + uint32_t aFlags, uint64_t *aMaxAge, bool *aIncludeSubdomains) { @@ -237,8 +239,8 @@ nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI, 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; } @@ -246,6 +248,7 @@ nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI, nsresult nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI, char* aHeader, + uint32_t aFlags, uint64_t *aMaxAge, bool *aIncludeSubdomains) { @@ -338,7 +341,7 @@ nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI, ("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; @@ -354,7 +357,7 @@ nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI, } 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. @@ -365,7 +368,7 @@ nsStrictTransportSecurityService::IsStsHost(const char* aHost, bool* aResult) 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) @@ -401,7 +404,7 @@ nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost) } 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. @@ -417,7 +420,8 @@ nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, bool* aResult) const nsSTSPreload *preload = nullptr; nsSTSHostEntry *pbEntry = nullptr; - if (mInPrivateMode) { + bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE; + if (isPrivate) { pbEntry = mPrivateModeHostTable.GetEntry(host.get()); } @@ -479,7 +483,7 @@ nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, bool* aResult) break; } - if (mInPrivateMode) { + if (isPrivate) { pbEntry = mPrivateModeHostTable.GetEntry(subdomain); } @@ -580,20 +584,8 @@ 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); @@ -611,11 +603,12 @@ 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 principal; nsresult rv = GetPrincipalForURI(aURI, getter_AddRefs(principal)); @@ -667,7 +660,8 @@ nsStrictTransportSecurityService::AddPermission(nsIURI *aURI, 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:// @@ -680,7 +674,7 @@ nsStrictTransportSecurityService::RemovePermission(const nsCString &aHost, 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). diff --git a/security/manager/boot/src/nsStrictTransportSecurityService.h b/security/manager/boot/src/nsStrictTransportSecurityService.h index 216c08768995..e4eba1ed4bae 100644 --- a/security/manager/boot/src/nsStrictTransportSecurityService.h +++ b/security/manager/boot/src/nsStrictTransportSecurityService.h @@ -135,8 +135,8 @@ public: 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); @@ -145,15 +145,16 @@ private: 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 mPermMgr; nsCOMPtr mObserverService; - bool mInPrivateMode; nsTHashtable mPrivateModeHostTable; bool mUsePreloadList; }; diff --git a/security/manager/ssl/src/SSLServerCertVerification.cpp b/security/manager/ssl/src/SSLServerCertVerification.cpp index e3cc1e36ee69..ac543fda3bcd 100644 --- a/security/manager/ssl/src/SSLServerCertVerification.cpp +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp @@ -293,7 +293,14 @@ CertErrorRunnable::CheckCertOverrides() nsCOMPtr stss = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv); if (NS_SUCCEEDED(nsrv)) { + nsCOMPtr 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)) { diff --git a/security/manager/ssl/src/TransportSecurityInfo.h b/security/manager/ssl/src/TransportSecurityInfo.h index 3d7a7cb69699..b38145bac297 100644 --- a/security/manager/ssl/src/TransportSecurityInfo.h +++ b/security/manager/ssl/src/TransportSecurityInfo.h @@ -17,6 +17,7 @@ #include "nsIAssociatedContentSecurity.h" #include "nsNSSShutDown.h" #include "nsDataHashtable.h" +#include "nsISocketTransport.h" namespace mozilla { namespace psm { diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index e2208d969e57..353f71194976 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -61,7 +61,7 @@ typedef enum {ASK, AUTO} SSM_UserCertChoice; extern PRLogModuleInfo* gPIPNSSLog; #endif -nsNSSSocketInfo::nsNSSSocketInfo() +nsNSSSocketInfo::nsNSSSocketInfo(uint32_t providerFlags) : mFd(nullptr), mCertVerificationState(before_cert_verification), mForSTARTTLS(false), @@ -77,7 +77,8 @@ nsNSSSocketInfo::nsNSSSocketInfo() mNPNCompleted(false), mHandshakeCompleted(false), mJoined(false), - mSentClientCert(false) + mSentClientCert(false), + mProviderFlags(providerFlags) { } @@ -85,6 +86,13 @@ 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) { @@ -1312,14 +1320,14 @@ nsSSLIOLayerNewSocket(int32_t family, 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; @@ -2309,8 +2317,7 @@ done: static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc *fd, nsNSSSocketInfo *infoObject, - const char *host, - bool anonymousLoad) + const char *host) { nsNSSShutDownPreventionLock locker; PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd); @@ -2322,7 +2329,9 @@ nsSSLIOLayerImportFD(PRFileDesc *fd, 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, @@ -2428,14 +2437,14 @@ nsSSLIOLayerAddToSocket(int32_t family, 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); @@ -2443,7 +2452,8 @@ nsSSLIOLayerAddToSocket(int32_t family, 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; diff --git a/security/manager/ssl/src/nsNSSIOLayer.h b/security/manager/ssl/src/nsNSSIOLayer.h index 4467c375bce1..40fe5214e3db 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.h +++ b/security/manager/ssl/src/nsNSSIOLayer.h @@ -13,13 +13,14 @@ #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 @@ -72,7 +73,7 @@ public: { return mCertVerificationState == waiting_for_cert_verification; } - + bool IsSSL3Enabled() const { return mSSL3Enabled; } void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; } bool IsTLSEnabled() const { return mTLSEnabled; } @@ -100,6 +101,8 @@ private: bool mHandshakeCompleted; bool mJoined; bool mSentClientCert; + + uint32_t mProviderFlags; }; class nsSSLIOLayerHelpers @@ -146,7 +149,7 @@ nsresult nsSSLIOLayerNewSocket(int32_t family, PRFileDesc **fd, nsISupports **securityInfo, bool forSTARTTLS, - bool anonymousLoad); + uint32_t flags); nsresult nsSSLIOLayerAddToSocket(int32_t family, const char *host, @@ -156,7 +159,7 @@ nsresult nsSSLIOLayerAddToSocket(int32_t family, PRFileDesc *fd, nsISupports **securityInfo, bool forSTARTTLS, - bool anonymousLoad); + uint32_t flags); nsresult nsSSLIOLayerFreeTLSIntolerantSites(); nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo *infoObject, int error); diff --git a/security/manager/ssl/src/nsSSLSocketProvider.cpp b/security/manager/ssl/src/nsSSLSocketProvider.cpp index 5700c5812cb2..ce0402728699 100644 --- a/security/manager/ssl/src/nsSSLSocketProvider.cpp +++ b/security/manager/ssl/src/nsSSLSocketProvider.cpp @@ -36,7 +36,7 @@ nsSSLSocketProvider::NewSocket(int32_t family, _result, securityInfo, false, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } @@ -59,7 +59,7 @@ nsSSLSocketProvider::AddToSocket(int32_t family, aSocket, securityInfo, false, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } diff --git a/security/manager/ssl/src/nsTLSSocketProvider.cpp b/security/manager/ssl/src/nsTLSSocketProvider.cpp index 06c6cdbcd7d4..99634801992e 100644 --- a/security/manager/ssl/src/nsTLSSocketProvider.cpp +++ b/security/manager/ssl/src/nsTLSSocketProvider.cpp @@ -36,7 +36,7 @@ nsTLSSocketProvider::NewSocket(int32_t family, _result, securityInfo, true, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } @@ -60,7 +60,7 @@ nsTLSSocketProvider::AddToSocket(int32_t family, aSocket, securityInfo, true, - flags & ANONYMOUS_CONNECT); + flags); return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; } diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html index 33b13feba53f..803d9a23d6dc 100644 --- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html +++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html @@ -54,7 +54,7 @@ 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) { diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html index 89cbd4023afa..90067cbb4735 100644 --- a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html +++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing.html @@ -171,7 +171,12 @@ 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); } @@ -180,7 +185,12 @@ 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. diff --git a/security/manager/ssl/tests/unit/test_bug627234.js b/security/manager/ssl/tests/unit/test_bug627234.js index d79ddf3eeca9..0558db6391fb 100644 --- a/security/manager/ssl/tests/unit/test_bug627234.js +++ b/security/manager/ssl/tests/unit/test_bug627234.js @@ -3,73 +3,62 @@ 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; - Services.obs.addObserver(gObserver, "private-browsing-transition-complete", false); - Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true); - pb.privateBrowsingEnabled = true; - } + gNextTest = test_part1; + enterPB(); +} + +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(); } diff --git a/security/manager/ssl/tests/unit/test_sts_preloadlist.js b/security/manager/ssl/tests/unit/test_sts_preloadlist.js index af9104035679..8fec91622c37 100644 --- a/security/manager/ssl/tests/unit/test_sts_preloadlist.js +++ b/security/manager/ssl/tests/unit/test_sts_preloadlist.js @@ -46,7 +46,7 @@ function cleanup() { for (var host of hosts) { var uri = Services.io.newURI(host, null, null); - gSTSService.removeStsState(uri); + gSTSService.removeStsState(uri, 0); } } @@ -66,65 +66,65 @@ function run_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 @@ -134,19 +134,19 @@ function test_part1() { // |-- 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 @@ -159,26 +159,28 @@ function test_part1() { } } +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 @@ -189,12 +191,12 @@ function test_private_browsing1() { // 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; @@ -202,13 +204,13 @@ function test_private_browsing1() { 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(); } diff --git a/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js b/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js index 72845c6bf9af..047803c4a15f 100644 --- a/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js +++ b/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js @@ -9,16 +9,16 @@ function run_test() { .getService(Ci.nsIStrictTransportSecurityService); // check that a host on the preload list is identified as an sts host - do_check_true(STSService.isStsHost("alpha.irccloud.com")); + do_check_true(STSService.isStsHost("alpha.irccloud.com", 0)); // now simulate that it's 19 weeks later than it actually is let offsetSeconds = 19 * 7 * 24 * 60 * 60; Services.prefs.setIntPref("test.currentTimeOffsetSeconds", offsetSeconds); // check that the preloaded host is no longer considered sts - do_check_false(STSService.isStsHost("alpha.irccloud.com")); + do_check_false(STSService.isStsHost("alpha.irccloud.com", 0)); // just make sure we can get everything back to normal Services.prefs.clearUserPref("test.currentTimeOffsetSeconds"); - do_check_true(STSService.isStsHost("alpha.irccloud.com")); + do_check_true(STSService.isStsHost("alpha.irccloud.com", 0)); }