Bug 1388925 - Add an opaque flags to have a fine-grained control over TLS configurations. r=mcmanus, r=keeler
authorSajjad Arshad <sarshad@mozilla.com>
Wed, 16 Aug 2017 12:41:16 -0700
changeset 375100 bfe9b1d9ad1193b3d4b4e026d7dfbf998603f3db
parent 375099 8dfe4d26c70f4a792b429186c8ece3d1164efdc8
child 375101 c217dd347b0170650b8f90b2f4d48f683be832c6
push id93833
push userryanvm@gmail.com
push dateWed, 16 Aug 2017 22:14:15 +0000
treeherdermozilla-inbound@c217dd347b01 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, keeler
bugs1388925
milestone57.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
Bug 1388925 - Add an opaque flags to have a fine-grained control over TLS configurations. r=mcmanus, r=keeler This flags is added in the http channel interface by which developers can control the TLS connections from JavaScript code (e.g. Add-ons). Basically, all the changes accounted for plumbing this TLS flags from JavaScript level to C++ code responsible for calling NSS module. We also added a unit test to make sure that separate connections are created if we use different tlsFlags. Basically we used a concrete set of flag values that covers the edge cases and check the hashkey generated in the connection info.
netwerk/base/nsISocketTransport.idl
netwerk/base/nsSocketTransport2.cpp
netwerk/base/nsSocketTransport2.h
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/TunnelUtils.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnectionInfo.cpp
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsIHttpChannelInternal.idl
netwerk/socket/nsISSLSocketControl.idl
netwerk/socket/nsISocketProvider.idl
netwerk/socket/nsSOCKSIOLayer.cpp
netwerk/socket/nsSOCKSIOLayer.h
netwerk/socket/nsSOCKSSocketProvider.cpp
netwerk/socket/nsUDPSocketProvider.cpp
netwerk/test/unit/test_tls_flags_separate_connections.js
netwerk/test/unit/xpcshell.ini
security/manager/ssl/nsNSSIOLayer.cpp
security/manager/ssl/nsNSSIOLayer.h
security/manager/ssl/nsSSLSocketProvider.cpp
security/manager/ssl/nsTLSSocketProvider.cpp
--- a/netwerk/base/nsISocketTransport.idl
+++ b/netwerk/base/nsISocketTransport.idl
@@ -233,16 +233,23 @@ interface nsISocketTransport : nsITransp
     /**
      * If set, do not use newer protocol features that might have interop problems
      * on the Internet. Intended only for use with critical infra like the updater.
      * default is false.
      */
     const unsigned long BE_CONSERVATIVE = (1 << 7);
 
     /**
+     * An opaque flags for non-standard behavior of the TLS system.
+     * It is unlikely this will need to be set outside of telemetry studies
+     * relating to the TLS implementation.
+     */
+    attribute unsigned long tlsFlags;
+
+    /**
      * 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/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -770,16 +770,17 @@ nsSocketTransport::nsSocketTransport()
     , mTypeCount(0)
     , mPort(0)
     , mProxyPort(0)
     , mOriginPort(0)
     , mProxyTransparent(false)
     , mProxyTransparentResolvesHost(false)
     , mHttpsProxy(false)
     , mConnectionFlags(0)
+    , mTlsFlags(0)
     , mReuseAddrPort(false)
     , mState(STATE_CLOSED)
     , mAttached(false)
     , mInputClosed(true)
     , mOutputClosed(true)
     , mResolving(false)
     , mNetAddrIsSet(false)
     , mSelfAddrIsSet(false)
@@ -1220,31 +1221,31 @@ nsSocketTransport::BuildSocket(PRFileDes
 
                 // when https proxying we want to just connect to the proxy as if
                 // it were the end host (i.e. expect the proxy's cert)
 
                 rv = provider->NewSocket(mNetAddr.raw.family,
                                          mHttpsProxy ? mProxyHost.get() : host,
                                          mHttpsProxy ? mProxyPort : port,
                                          proxyInfo, mOriginAttributes,
-                                         controlFlags, &fd,
+                                         controlFlags, mTlsFlags, &fd,
                                          getter_AddRefs(secinfo));
 
                 if (NS_SUCCEEDED(rv) && !fd) {
                     NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
                     rv = NS_ERROR_UNEXPECTED;
                 }
             }
             else {
                 // the socket has already been allocated,
                 // so we just want the service to add itself
                 // to the stack (such as pushing an io layer)
                 rv = provider->AddToSocket(mNetAddr.raw.family,
                                            host, port, proxyInfo,
-                                           mOriginAttributes, controlFlags, fd,
+                                           mOriginAttributes, controlFlags, mTlsFlags, fd,
                                            getter_AddRefs(secinfo));
             }
 
             // controlFlags = 0; not used below this point...
             if (NS_FAILED(rv))
                 break;
 
             // if the service was ssl or starttls, we want to hold onto the socket info
@@ -2991,16 +2992,30 @@ nsSocketTransport::GetConnectionFlags(ui
 NS_IMETHODIMP
 nsSocketTransport::SetConnectionFlags(uint32_t value)
 {
     mConnectionFlags = value;
     mIsPrivate = value & nsISocketTransport::NO_PERMANENT_STORAGE;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSocketTransport::GetTlsFlags(uint32_t *value)
+{
+    *value = mTlsFlags;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSocketTransport::SetTlsFlags(uint32_t value)
+{
+    mTlsFlags = value;
+    return NS_OK;
+}
+
 void
 nsSocketTransport::OnKeepaliveEnabledPrefChange(bool aEnabled)
 {
     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
 
     // The global pref toggles keepalive as a system feature; it only affects
     // an individual socket if keepalive has been specifically enabled for it.
     // So, ensure keepalive is configured correctly if previously enabled.
--- a/netwerk/base/nsSocketTransport2.h
+++ b/netwerk/base/nsSocketTransport2.h
@@ -303,16 +303,17 @@ private:
     uint16_t     mPort;
     nsCOMPtr<nsIProxyInfo> mProxyInfo;
     uint16_t     mProxyPort;
     uint16_t     mOriginPort;
     bool mProxyTransparent;
     bool mProxyTransparentResolvesHost;
     bool mHttpsProxy;
     uint32_t     mConnectionFlags;
+    uint32_t     mTlsFlags;
     bool mReuseAddrPort;
 
     // The origin attributes are used to create sockets.  The first party domain
     // will eventually be used to isolate OCSP cache and is only non-empty when
     // "privacy.firstparty.isolate" is enabled.  Setting this is the only way to
     // carry origin attributes down to NSPR layers which are final consumers.
     // It must be set before the socket transport is built.
     OriginAttributes mOriginAttributes;
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -123,16 +123,17 @@ struct HttpChannelOpenArgs
   bool                        resumeAt;
   uint64_t                    startPos;
   nsCString                   entityID;
   bool                        chooseApplicationCache;
   nsCString                   appCacheClientID;
   bool                        allowSpdy;
   bool                        allowAltSvc;
   bool                        beConservative;
+  uint32_t                    tlsFlags;
   OptionalLoadInfoArgs        loadInfo;
   OptionalHttpResponseHead    synthesizedResponseHead;
   nsCString                   synthesizedSecurityInfoSerialization;
   uint32_t                    cacheKey;
   uint64_t                    requestContextID;
   OptionalCorsPreflightArgs   preflightArgs;
   uint32_t                    initialRwin;
   bool                        blockAuthPrompt;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -178,16 +178,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mAllowAltSvc(true)
   , mBeConservative(false)
   , mResponseTimeoutEnabled(true)
   , mAllRedirectsSameOrigin(true)
   , mAllRedirectsPassTimingAllowCheck(true)
   , mResponseCouldBeSynthesized(false)
   , mBlockAuthPrompt(false)
   , mAllowStaleCacheContent(false)
+  , mTlsFlags(0)
   , mSuspendCount(0)
   , mInitialRwin(0)
   , mProxyResolveFlags(0)
   , mContentDispositionHint(UINT32_MAX)
   , mHttpHandler(gHttpHandler)
   , mReferrerPolicy(NS_GetDefaultReferrerPolicy())
   , mRedirectCount(0)
   , mForcePending(false)
@@ -2609,16 +2610,32 @@ HttpBaseChannel::GetBeConservative(bool 
 NS_IMETHODIMP
 HttpBaseChannel::SetBeConservative(bool aBeConservative)
 {
   mBeConservative = aBeConservative;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::GetTlsFlags(uint32_t *aTlsFlags)
+{
+  NS_ENSURE_ARG_POINTER(aTlsFlags);
+
+  *aTlsFlags = mTlsFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetTlsFlags(uint32_t aTlsFlags)
+{
+  mTlsFlags = aTlsFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
   NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3415,16 +3432,18 @@ HttpBaseChannel::SetupReplacementChannel
     rv = httpInternal->SetThirdPartyFlags(mThirdPartyFlags);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     rv = httpInternal->SetAllowSpdy(mAllowSpdy);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     rv = httpInternal->SetAllowAltSvc(mAllowAltSvc);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     rv = httpInternal->SetBeConservative(mBeConservative);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
+    rv = httpInternal->SetTlsFlags(mTlsFlags);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     RefPtr<nsHttpChannel> realChannel;
     CallQueryInterface(newChannel, realChannel.StartAssignment());
     if (realChannel) {
       rv = realChannel->SetTopWindowURI(mTopWindowURI);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
 
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -230,16 +230,18 @@ public:
   NS_IMETHOD GetRemoteAddress(nsACString& addr) override;
   NS_IMETHOD GetRemotePort(int32_t* port) override;
   NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy) override;
   NS_IMETHOD SetAllowSpdy(bool aAllowSpdy) override;
   NS_IMETHOD GetAllowAltSvc(bool *aAllowAltSvc) override;
   NS_IMETHOD SetAllowAltSvc(bool aAllowAltSvc) override;
   NS_IMETHOD GetBeConservative(bool *aBeConservative) override;
   NS_IMETHOD SetBeConservative(bool aBeConservative) override;
+  NS_IMETHOD GetTlsFlags(uint32_t *aTlsFlags) override;
+  NS_IMETHOD SetTlsFlags(uint32_t aTlsFlags) override;
   NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI) override;
   virtual MOZ_MUST_USE nsresult AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory);
   NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages) override;
   NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable) override;
   NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable) override;
   NS_IMETHOD GetInitialRwin(uint32_t* aRwin) override;
   NS_IMETHOD SetInitialRwin(uint32_t aRwin) override;
   NS_IMETHOD GetNetworkInterfaceId(nsACString& aNetworkInterfaceId) override;
@@ -536,16 +538,21 @@ protected:
   uint32_t                          mResponseCouldBeSynthesized : 1;
 
   uint32_t                          mBlockAuthPrompt : 1;
 
   // If true, we behave as if the LOAD_FROM_CACHE flag has been set.
   // Used to enforce that flag's behavior but not expose it externally.
   uint32_t                          mAllowStaleCacheContent : 1;
 
+  // An opaque flags for non-standard behavior of the TLS system.
+  // It is unlikely this will need to be set outside of telemetry studies
+  // relating to the TLS implementation.
+  uint32_t                          mTlsFlags;
+
   // Current suspension depth for this channel object
   uint32_t                          mSuspendCount;
 
   // Per channel transport window override (0 means no override)
   uint32_t                          mInitialRwin;
 
   nsAutoPtr<nsTArray<nsCString> >   mRedirectedCachekeys;
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2558,16 +2558,17 @@ HttpChannelChild::ContinueAsyncOpen()
   openArgs.resumeAt() = mSendResumeAt;
   openArgs.startPos() = mStartPos;
   openArgs.entityID() = mEntityID;
   openArgs.chooseApplicationCache() = mChooseApplicationCache;
   openArgs.appCacheClientID() = appCacheClientId;
   openArgs.allowSpdy() = mAllowSpdy;
   openArgs.allowAltSvc() = mAllowAltSvc;
   openArgs.beConservative() = mBeConservative;
+  openArgs.tlsFlags() = mTlsFlags;
   openArgs.initialRwin() = mInitialRwin;
 
   uint32_t cacheKey = 0;
   if (mCacheKey) {
     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(mCacheKey);
     if (!container) {
       return NS_ERROR_ILLEGAL_VALUE;
     }
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -131,17 +131,17 @@ HttpChannelParent::Init(const HttpChanne
                        a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
                        a.loadFlags(), a.requestHeaders(),
                        a.requestMethod(), a.uploadStream(),
                        a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
                        a.redirectionLimit(), a.allowSTS(),
                        a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
                        a.entityID(), a.chooseApplicationCache(),
                        a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.beConservative(),
-                       a.loadInfo(), a.synthesizedResponseHead(),
+                       a.tlsFlags(), a.loadInfo(), a.synthesizedResponseHead(),
                        a.synthesizedSecurityInfoSerialization(),
                        a.cacheKey(), a.requestContextID(), a.preflightArgs(),
                        a.initialRwin(), a.blockAuthPrompt(),
                        a.suspendAfterSynthesizeResponse(),
                        a.allowStaleCacheContent(), a.contentTypeHint(),
                        a.channelId(), a.contentWindowId(), a.preferredAlternativeType(),
                        a.topLevelOuterContentWindowId(),
                        a.launchServiceWorkerStart(),
@@ -452,16 +452,17 @@ HttpChannelParent::DoAsyncOpen(  const U
                                  const bool&                doResumeAt,
                                  const uint64_t&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
                                  const nsCString&           appCacheClientID,
                                  const bool&                allowSpdy,
                                  const bool&                allowAltSvc,
                                  const bool&                beConservative,
+                                 const uint32_t&            tlsFlags,
                                  const OptionalLoadInfoArgs& aLoadInfoArgs,
                                  const OptionalHttpResponseHead& aSynthesizedResponseHead,
                                  const nsCString&           aSecurityInfoSerialization,
                                  const uint32_t&            aCacheKey,
                                  const uint64_t&            aRequestContextID,
                                  const OptionalCorsPreflightArgs& aCorsPreflightArgs,
                                  const uint32_t&            aInitialRwin,
                                  const bool&                aBlockAuthPrompt,
@@ -678,16 +679,17 @@ HttpChannelParent::DoAsyncOpen(  const U
     httpChannel->SetClassFlags(classOfService);
   }
   httpChannel->SetRedirectionLimit(redirectionLimit);
   httpChannel->SetAllowSTS(allowSTS);
   httpChannel->SetThirdPartyFlags(thirdPartyFlags);
   httpChannel->SetAllowSpdy(allowSpdy);
   httpChannel->SetAllowAltSvc(allowAltSvc);
   httpChannel->SetBeConservative(beConservative);
+  httpChannel->SetTlsFlags(tlsFlags);
   httpChannel->SetInitialRwin(aInitialRwin);
   httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
 
   httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
   httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
   httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
   httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
   httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -146,16 +146,17 @@ protected:
               const bool&                doResumeAt,
               const uint64_t&            startPos,
               const nsCString&           entityID,
               const bool&                chooseApplicationCache,
               const nsCString&           appCacheClientID,
               const bool&                allowSpdy,
               const bool&                allowAltSvc,
               const bool&                beConservative,
+              const uint32_t&            tlsFlags,
               const OptionalLoadInfoArgs& aLoadInfoArgs,
               const OptionalHttpResponseHead& aSynthesizedResponseHead,
               const nsCString&           aSecurityInfoSerialization,
               const uint32_t&            aCacheKey,
               const uint64_t&            aRequestContextID,
               const OptionalCorsPreflightArgs& aCorsPreflightArgs,
               const uint32_t&            aInitialRwin,
               const bool&                aBlockAuthPrompt,
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -75,17 +75,17 @@ TLSFilterTransaction::TLSFilterTransacti
     sLayerMethodsPtr = &sLayerMethods;
   }
 
   mFD = PR_CreateIOLayerStub(sLayerIdentity, &sLayerMethods);
 
   if (provider && mFD) {
     mFD->secret = reinterpret_cast<PRFilePrivate *>(this);
     provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr,
-                          OriginAttributes(), 0, mFD,
+                          OriginAttributes(), 0, 0, mFD,
                           getter_AddRefs(mSecInfo));
   }
 
   if (mTransaction) {
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
     mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
     nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo));
     if (secCtrl) {
@@ -1542,16 +1542,18 @@ FWD_TS_PTR(GetPeerAddr, mozilla::net::Ne
 FWD_TS_PTR(GetSelfAddr, mozilla::net::NetAddr);
 FWD_TS_ADDREF(GetScriptablePeerAddr, nsINetAddr);
 FWD_TS_ADDREF(GetScriptableSelfAddr, nsINetAddr);
 FWD_TS_ADDREF(GetSecurityInfo, nsISupports);
 FWD_TS_ADDREF(GetSecurityCallbacks, nsIInterfaceRequestor);
 FWD_TS_PTR(IsAlive, bool);
 FWD_TS_PTR(GetConnectionFlags, uint32_t);
 FWD_TS(SetConnectionFlags, uint32_t);
+FWD_TS_PTR(GetTlsFlags, uint32_t);
+FWD_TS(SetTlsFlags, uint32_t);
 FWD_TS_PTR(GetRecvBufferSize, uint32_t);
 FWD_TS(SetRecvBufferSize, uint32_t);
 
 nsresult
 SocketTransportShim::GetOriginAttributes(mozilla::OriginAttributes* aOriginAttributes)
 {
   return mWrapped->GetOriginAttributes(aOriginAttributes);
 }
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -492,16 +492,17 @@ nsHttpChannel::Connect()
         mCaps |=  NS_HTTP_DISALLOW_SPDY;
     }
 
     // Finalize ConnectionInfo flags before SpeculativeConnect
     mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
     mConnectionInfo->SetPrivate(mPrivateBrowsing);
     mConnectionInfo->SetNoSpdy(mCaps & NS_HTTP_DISALLOW_SPDY);
     mConnectionInfo->SetBeConservative((mCaps & NS_HTTP_BE_CONSERVATIVE) || mBeConservative);
+    mConnectionInfo->SetTlsFlags(mTlsFlags);
 
     // Consider opening a TCP connection right away.
     SpeculativeConnect();
 
     // Don't allow resuming when cache must be used
     if (mResuming && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
         LOG(("Resuming from cache is not supported yet"));
         return NS_ERROR_DOCUMENT_NOT_CACHED;
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -87,16 +87,17 @@ nsHttpConnectionInfo::Init(const nsACStr
     LOG(("Init nsHttpConnectionInfo @%p\n", this));
 
     mUsername = username;
     mProxyInfo = proxyInfo;
     mEndToEndSSL = e2eSSL;
     mUsingConnect = false;
     mNPNToken = npnToken;
     mOriginAttributes = originAttributes;
+    mTlsFlags = 0x0;
 
     mUsingHttpsProxy = (proxyInfo && proxyInfo->IsHTTPS());
     mUsingHttpProxy = mUsingHttpsProxy || (proxyInfo && proxyInfo->IsHTTP());
 
     if (mUsingHttpProxy) {
         mUsingConnect = mEndToEndSSL;  // SSL always uses CONNECT
         uint32_t resolveFlags = 0;
         if (NS_SUCCEEDED(mProxyInfo->GetResolveFlags(&resolveFlags)) &&
@@ -142,17 +143,18 @@ void nsHttpConnectionInfo::BuildHashKey(
     // byte 0 is P/T/. {P,T} for Plaintext/TLS Proxy over HTTP
     // byte 1 is S/. S is for end to end ssl such as https:// uris
     // byte 2 is A/. A is for an anonymous channel (no cookies, etc..)
     // byte 3 is P/. P is for a private browising channel
     // byte 4 is I/. I is for insecure scheme on TLS for http:// uris
     // byte 5 is X/. X is for disallow_spdy flag
     // byte 6 is C/. C is for be Conservative
 
-    mHashKey.AssignLiteral(".......");
+    mHashKey.AssignLiteral(".......[tlsflags0x00000000]");
+
     mHashKey.Append(keyHost);
     if (!mNetworkInterfaceId.IsEmpty()) {
         mHashKey.Append('(');
         mHashKey.Append(mNetworkInterfaceId);
         mHashKey.Append(')');
     }
     mHashKey.Append(':');
     mHashKey.AppendInt(keyPort);
@@ -254,16 +256,17 @@ nsHttpConnectionInfo::Clone() const
     }
 
     // Make sure the anonymous, insecure-scheme, and private flags are transferred
     clone->SetAnonymous(GetAnonymous());
     clone->SetPrivate(GetPrivate());
     clone->SetInsecureScheme(GetInsecureScheme());
     clone->SetNoSpdy(GetNoSpdy());
     clone->SetBeConservative(GetBeConservative());
+    clone->SetTlsFlags(GetTlsFlags());
     MOZ_ASSERT(clone->Equals(this));
 
     return clone;
 }
 
 void
 nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo **outCI)
 {
@@ -277,16 +280,17 @@ nsHttpConnectionInfo::CloneAsDirectRoute
                                  EmptyCString(), mUsername, mProxyInfo,
                                  mOriginAttributes, mEndToEndSSL);
     // Make sure the anonymous, insecure-scheme, and private flags are transferred
     clone->SetAnonymous(GetAnonymous());
     clone->SetPrivate(GetPrivate());
     clone->SetInsecureScheme(GetInsecureScheme());
     clone->SetNoSpdy(GetNoSpdy());
     clone->SetBeConservative(GetBeConservative());
+    clone->SetTlsFlags(GetTlsFlags());
     if (!mNetworkInterfaceId.IsEmpty()) {
         clone->SetNetworkInterfaceId(mNetworkInterfaceId);
     }
     clone.forget(outCI);
 }
 
 nsresult
 nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo **outParam)
@@ -305,16 +309,23 @@ nsHttpConnectionInfo::CreateWildCard(nsH
                                      mOriginAttributes, true);
     // Make sure the anonymous and private flags are transferred!
     clone->SetAnonymous(GetAnonymous());
     clone->SetPrivate(GetPrivate());
     clone.forget(outParam);
     return NS_OK;
 }
 
+void
+nsHttpConnectionInfo::SetTlsFlags(uint32_t aTlsFlags) {
+    mTlsFlags = aTlsFlags;
+
+    mHashKey.Replace(18, 8, nsPrintfCString("%08x", mTlsFlags));
+}
+
 bool
 nsHttpConnectionInfo::UsingProxy()
 {
     if (!mProxyInfo)
         return false;
     return !mProxyInfo->IsDirect();
 }
 
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -117,16 +117,19 @@ public:
     void          SetNoSpdy(bool aNoSpdy)
                                        { mHashKey.SetCharAt(aNoSpdy ? 'X' : '.', 5); }
     bool          GetNoSpdy() const    { return mHashKey.CharAt(5) == 'X'; }
 
     void          SetBeConservative(bool aBeConservative)
                                             { mHashKey.SetCharAt(aBeConservative ? 'C' : '.', 6); }
     bool          GetBeConservative() const { return mHashKey.CharAt(6) == 'C'; }
 
+    void          SetTlsFlags(uint32_t aTlsFlags);
+    uint32_t      GetTlsFlags() const { return mTlsFlags; }
+
     const nsCString &GetNetworkInterfaceId() const { return mNetworkInterfaceId; }
 
     const nsCString &GetNPNToken() { return mNPNToken; }
     const nsCString &GetUsername() { return mUsername; }
 
     const OriginAttributes &GetOriginAttributes() { return mOriginAttributes; }
 
     // Returns true for any kind of proxy (http, socks, https, etc..)
@@ -171,16 +174,18 @@ private:
     nsCOMPtr<nsProxyInfo>  mProxyInfo;
     bool                   mUsingHttpProxy;
     bool                   mUsingHttpsProxy;
     bool                   mEndToEndSSL;
     bool                   mUsingConnect;  // if will use CONNECT with http proxy
     nsCString              mNPNToken;
     OriginAttributes       mOriginAttributes;
 
+    uint32_t               mTlsFlags;
+
 // for RefPtr
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo)
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // nsHttpConnectionInfo_h__
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3848,16 +3848,17 @@ nsHalfOpenSocket::SetupStreams(nsISocket
         tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
     }
 
     if (!isBackup && mEnt->mUseFastOpen) {
         socketTransport->SetFastOpenCallback(this);
     }
 
     socketTransport->SetConnectionFlags(tmpFlags);
+    socketTransport->SetTlsFlags(ci->GetTlsFlags());
 
     const OriginAttributes& originAttributes = mEnt->mConnInfo->GetOriginAttributes();
     if (originAttributes != OriginAttributes()) {
         socketTransport->SetOriginAttributes(originAttributes);
     }
 
     socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());
 
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -211,16 +211,23 @@ interface nsIHttpChannelInternal : nsISu
 
     /**
      * If true, do not use newer protocol features that might have interop problems
      * on the Internet. Intended only for use with critical infra like the updater.
      * default is false.
      */
     [must_use] attribute boolean beConservative;
 
+    /**
+     * An opaque flags for non-standard behavior of the TLS system.
+     * It is unlikely this will need to be set outside of telemetry studies
+     * relating to the TLS implementation.
+     */
+    [must_use] attribute unsigned long tlsFlags;
+
     [must_use] readonly attribute PRTime lastModifiedTime;
 
     /**
      * Force a channel that has not been AsyncOpen'ed to skip any check for possible
      * interception and proceed immediately to open a previously-synthesized cache
      * entry using the provided ID.
      */
     [must_use] void forceIntercepted(in uint64_t aInterceptionID);
--- a/netwerk/socket/nsISSLSocketControl.idl
+++ b/netwerk/socket/nsISSLSocketControl.idl
@@ -97,16 +97,21 @@ interface nsISSLSocketControl : nsISuppo
 
     const short KEY_EXCHANGE_UNKNOWN = -1;
 
     /*
      * The original flags from the socket provider.
      */
     readonly attribute uint32_t providerFlags;
 
+    /*
+     * The original TLS flags from the socket provider.
+     */
+    readonly attribute uint32_t providerTlsFlags;
+
     /* These values are defined by TLS. */
     const short SSL_VERSION_3   = 0x0300;
     const short TLS_VERSION_1   = 0x0301;
     const short TLS_VERSION_1_1 = 0x0302;
     const short TLS_VERSION_1_2 = 0x0303;
     const short TLS_VERSION_1_3 = 0x0304;
     const short SSL_VERSION_UNKNOWN = -1;
 
--- a/netwerk/socket/nsISocketProvider.idl
+++ b/netwerk/socket/nsISocketProvider.idl
@@ -30,29 +30,34 @@ interface nsISocketProvider : nsISupport
      * @param aPort
      *        The origin port for this connection.
      * @param aProxyHost
      *        If non-null, the proxy hostname for this connection.
      * @param aProxyPort
      *        The proxy port for this connection.
      * @param aFlags
      *        Control flags that govern this connection (see below.)
+     * @param aTlsFlags
+     *        An opaque flags for non-standard behavior of the TLS system.
+     *        It is unlikely this will need to be set outside of telemetry
+     *        studies relating to the TLS implementation.
      * @param aFileDesc
      *        The resulting PRFileDesc.
      * @param aSecurityInfo
      *        Any security info that should be associated with aFileDesc.  This
      *        object typically implements nsITransportSecurityInfo.
      */
     [noscript]
     void newSocket(in long                      aFamily,
                    in string                    aHost, 
                    in long                      aPort,
                    in nsIProxyInfo              aProxy,
                    in const_OriginAttributesRef aOriginAttributes,
                    in unsigned long             aFlags,
+                   in unsigned long             aTlsFlags,
                    out PRFileDescStar           aFileDesc, 
                    out nsISupports              aSecurityInfo);
 
     /**
      * addToSocket
      *
      * This function is called to allow the socket provider to layer a
      * PRFileDesc on top of another PRFileDesc.  For example, SSL via a SOCKS
@@ -63,16 +68,17 @@ interface nsISocketProvider : nsISupport
      */
     [noscript]
     void addToSocket(in long                      aFamily,
                      in string                    aHost, 
                      in long                      aPort,
                      in nsIProxyInfo              aProxy,
                      in const_OriginAttributesRef aOriginAttributes,
                      in unsigned long             aFlags,
+                     in unsigned long             aTlsFlags,
                      in PRFileDescStar            aFileDesc, 
                      out nsISupports              aSecurityInfo);
 
     /**
      * PROXY_RESOLVES_HOST
      *
      * This flag is set if the proxy is to perform hostname resolution instead
      * of the client.  When set, the hostname parameter passed when in this
--- a/netwerk/socket/nsSOCKSIOLayer.cpp
+++ b/netwerk/socket/nsSOCKSIOLayer.cpp
@@ -73,17 +73,18 @@ public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSISOCKSSOCKETINFO
     NS_DECL_NSIDNSLISTENER
 
     void Init(int32_t version,
               int32_t family,
               nsIProxyInfo *proxy,
               const char *destinationHost,
-              uint32_t flags);
+              uint32_t flags,
+              uint32_t tlsFlags);
 
     void SetConnectTimeout(PRIntervalTime to);
     PRStatus DoHandshake(PRFileDesc *fd, int16_t oflags = -1);
     int16_t GetPollFlags() const;
     bool IsConnected() const { return mState == SOCKS_CONNECTED; }
     void ForgetFD() { mFD = nullptr; }
     void SetNamedPipeFD(PRFileDesc *fd) { mFD = fd; }
 
@@ -211,32 +212,34 @@ private:
     nsresult                mLookupStatus;
     PRFileDesc             *mFD;
 
     nsCString mDestinationHost;
     nsCOMPtr<nsIProxyInfo> mProxy;
     int32_t   mVersion;   // SOCKS version 4 or 5
     int32_t   mDestinationFamily;
     uint32_t  mFlags;
+    uint32_t  mTlsFlags;
     NetAddr   mInternalProxyAddr;
     NetAddr   mExternalProxyAddr;
     NetAddr   mDestinationAddr;
     PRIntervalTime mTimeout;
     nsCString mProxyUsername; // Cache, from mProxy
 };
 
 nsSOCKSSocketInfo::nsSOCKSSocketInfo()
     : mState(SOCKS_INITIAL)
     , mDataIoPtr(nullptr)
     , mDataLength(0)
     , mReadOffset(0)
     , mAmountToRead(0)
     , mVersion(-1)
     , mDestinationFamily(AF_INET)
     , mFlags(0)
+    , mTlsFlags(0)
     , mTimeout(PR_INTERVAL_NO_TIMEOUT)
 {
     mData = new uint8_t[BUFFER_SIZE];
 
     mInternalProxyAddr.raw.family = AF_INET;
     mInternalProxyAddr.inet.ip = htonl(INADDR_ANY);
     mInternalProxyAddr.inet.port = htons(0);
 
@@ -354,23 +357,24 @@ private:
   }
 
   uint8_t* mBuf;
   size_t mLength;
 };
 
 
 void
-nsSOCKSSocketInfo::Init(int32_t version, int32_t family, nsIProxyInfo *proxy, const char *host, uint32_t flags)
+nsSOCKSSocketInfo::Init(int32_t version, int32_t family, nsIProxyInfo *proxy, const char *host, uint32_t flags, uint32_t tlsFlags)
 {
     mVersion         = version;
     mDestinationFamily = family;
     mProxy           = proxy;
     mDestinationHost = host;
     mFlags           = flags;
+    mTlsFlags        = tlsFlags;
     mProxy->GetUsername(mProxyUsername); // cache
 }
 
 NS_IMPL_ISUPPORTS(nsSOCKSSocketInfo, nsISOCKSSocketInfo, nsIDNSListener)
 
 NS_IMETHODIMP
 nsSOCKSSocketInfo::GetExternalProxyAddr(NetAddr * *aExternalProxyAddr)
 {
@@ -1513,16 +1517,17 @@ nsSOCKSIOLayerListen(PRFileDesc *fd, int
 // add SOCKS IO layer to an existing socket
 nsresult
 nsSOCKSIOLayerAddToSocket(int32_t family,
                           const char *host,
                           int32_t port,
                           nsIProxyInfo *proxy,
                           int32_t socksVersion,
                           uint32_t flags,
+                          uint32_t tlsFlags,
                           PRFileDesc *fd,
                           nsISupports** info)
 {
     NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), NS_ERROR_NOT_INITIALIZED);
 
 
     if (firstTime)
     {
@@ -1572,17 +1577,17 @@ nsSOCKSIOLayerAddToSocket(int32_t family
     {
         // clean up IOLayerStub
         LOGERROR(("Failed to create nsSOCKSSocketInfo()."));
         PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
         return NS_ERROR_FAILURE;
     }
 
     NS_ADDREF(infoObject);
-    infoObject->Init(socksVersion, family, proxy, host, flags);
+    infoObject->Init(socksVersion, family, proxy, host, flags, tlsFlags);
     layer->secret = (PRFilePrivate*) infoObject;
 
     PRDescIdentity fdIdentity = PR_GetLayersIdentity(fd);
 #if defined(XP_WIN)
     if (fdIdentity == mozilla::net::nsNamedPipeLayerIdentity) {
         // remember named pipe fd on the info object so that we can switch
         // blocking and non-blocking mode on the pipe later.
         infoObject->SetNamedPipeFD(fd);
--- a/netwerk/socket/nsSOCKSIOLayer.h
+++ b/netwerk/socket/nsSOCKSIOLayer.h
@@ -12,14 +12,15 @@
 #include "nsIProxyInfo.h"
 
 nsresult nsSOCKSIOLayerAddToSocket(int32_t       family,
                                    const char   *host,
                                    int32_t       port,
                                    nsIProxyInfo *proxyInfo,
                                    int32_t       socksVersion,
                                    uint32_t      flags,
+                                   uint32_t      tlsFlags,
                                    PRFileDesc   *fd,
                                    nsISupports **info);
 
 bool IsHostLocalTarget(const nsACString& aHost);
 
 #endif /* nsSOCKSIOLayer_h__ */
--- a/netwerk/socket/nsSOCKSSocketProvider.cpp
+++ b/netwerk/socket/nsSOCKSSocketProvider.cpp
@@ -45,16 +45,17 @@ nsSOCKSSocketProvider::CreateV5(nsISuppo
 
 NS_IMETHODIMP
 nsSOCKSSocketProvider::NewSocket(int32_t family,
                                  const char *host,
                                  int32_t port,
                                  nsIProxyInfo *proxy,
                                  const OriginAttributes &originAttributes,
                                  uint32_t flags,
+                                 uint32_t tlsFlags,
                                  PRFileDesc **result,
                                  nsISupports **socksInfo)
 {
     PRFileDesc *sock;
 
 #if defined(XP_WIN)
     nsAutoCString proxyHost;
     proxy->GetHost(proxyHost);
@@ -70,16 +71,17 @@ nsSOCKSSocketProvider::NewSocket(int32_t
     }
 
     nsresult rv = nsSOCKSIOLayerAddToSocket(family,
                                             host,
                                             port,
                                             proxy,
                                             mVersion,
                                             flags,
+                                            tlsFlags,
                                             sock,
                                             socksInfo);
     if (NS_SUCCEEDED(rv)) {
         *result = sock;
         return NS_OK;
     }
 
     return NS_ERROR_SOCKET_CREATE_FAILED;
@@ -87,24 +89,26 @@ nsSOCKSSocketProvider::NewSocket(int32_t
 
 NS_IMETHODIMP
 nsSOCKSSocketProvider::AddToSocket(int32_t family,
                                    const char *host,
                                    int32_t port,
                                    nsIProxyInfo *proxy,
                                    const OriginAttributes &originAttributes,
                                    uint32_t flags,
+                                   uint32_t tlsFlags,
                                    PRFileDesc *sock,
                                    nsISupports **socksInfo)
 {
     nsresult rv = nsSOCKSIOLayerAddToSocket(family,
                                             host,
                                             port,
                                             proxy,
                                             mVersion,
                                             flags,
+                                            tlsFlags,
                                             sock,
                                             socksInfo);
 
     if (NS_FAILED(rv))
         rv = NS_ERROR_SOCKET_CREATE_FAILED;
     return rv;
 }
--- a/netwerk/socket/nsUDPSocketProvider.cpp
+++ b/netwerk/socket/nsUDPSocketProvider.cpp
@@ -16,16 +16,17 @@ nsUDPSocketProvider::~nsUDPSocketProvide
 
 NS_IMETHODIMP
 nsUDPSocketProvider::NewSocket(int32_t aFamily,
                                const char *aHost,
                                int32_t aPort,
                                nsIProxyInfo *aProxy,
                                const OriginAttributes &originAttributes,
                                uint32_t aFlags,
+                               uint32_t aTlsFlags,
                                PRFileDesc * *aFileDesc,
                                nsISupports **aSecurityInfo)
 {
     NS_ENSURE_ARG_POINTER(aFileDesc);
 
     PRFileDesc* udpFD = PR_OpenUDPSocket(aFamily);
     if (!udpFD)
         return NS_ERROR_FAILURE;
@@ -36,15 +37,16 @@ nsUDPSocketProvider::NewSocket(int32_t a
 
 NS_IMETHODIMP
 nsUDPSocketProvider::AddToSocket(int32_t aFamily,
                                  const char *aHost,
                                  int32_t aPort,
                                  nsIProxyInfo *aProxy,
                                  const OriginAttributes &originAttributes,
                                  uint32_t aFlags,
+                                 uint32_t aTlsFlags,
                                  struct PRFileDesc * aFileDesc,
                                  nsISupports **aSecurityInfo)
 {
     // does not make sense to strap a UDP socket onto an existing socket
     NS_NOTREACHED("Cannot layer UDP socket on an existing socket");
     return NS_ERROR_UNEXPECTED;
 }
copy from netwerk/test/unit/test_separate_connections.js
copy to netwerk/test/unit/test_tls_flags_separate_connections.js
--- a/netwerk/test/unit/test_separate_connections.js
+++ b/netwerk/test/unit/test_tls_flags_separate_connections.js
@@ -1,94 +1,114 @@
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "URL", function() {
   return "http://localhost:" + httpserv.identity.primaryPort;
 });
 
-// This unit test ensures each container has its own connection pool.
-// We verify this behavior by opening channels with different userContextId,
-// and their connection info's hash keys should be different.
+// This unit test ensures connections with different tlsFlags have their own
+// connection pool. We verify this behavior by opening channels with different
+// tlsFlags, and their connection info's hash keys should be different.
 
-// In the first round of this test, we record the hash key in each container.
-// In the second round, we check if each container's hash key is consistent
-// and different from other container's hash key.
+// In the first round of this test, we record the hash key for each connection.
+// In the second round, we check if each connection's hash key is consistent
+// and different from other connection's hash key.
 
 let httpserv = null;
 let gSecondRoundStarted = false;
 
+let randomFlagValues = [
+    0x00000000,
+
+    0xFFFFFFFF,
+
+    0x12345678,
+    0x12345678,
+
+    0x11111111,
+    0x22222222,
+
+    0xAAAAAAAA,
+    0x77777777,
+
+    0xBBBBBBBB,
+    0xCCCCCCCC
+];
+
 function handler(metadata, response) {
   response.setHeader("Content-Type", "text/plain", false);
   response.setHeader("Cache-Control", "no-cache", false);
   response.setStatusLine(metadata.httpVersion, 200, "OK");
   let body = "0123456789";
   response.bodyOutputStream.write(body, body.length);
 }
 
-function makeChan(url, userContextId) {
+function makeChan(url, tlsFlags) {
   let chan = NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true });
-  chan.loadInfo.originAttributes = { userContextId: userContextId };
+  chan.QueryInterface(Ci.nsIHttpChannelInternal);
+  chan.tlsFlags = tlsFlags;
+
   return chan;
 }
 
-let previousHashKeys = [];
+let previousHashKeys = {};
 
-function Listener(userContextId) {
-  this.userContextId = userContextId;
+function Listener(tlsFlags) {
+  this.tlsFlags = tlsFlags;
 }
 
 let gTestsRun = 0;
 Listener.prototype = {
   onStartRequest: function(request, context) {
     request.QueryInterface(Ci.nsIHttpChannel)
            .QueryInterface(Ci.nsIHttpChannelInternal);
 
-    do_check_eq(request.loadInfo.originAttributes.userContextId, this.userContextId);
+    do_check_eq(request.tlsFlags, this.tlsFlags);
 
     let hashKey = request.connectionInfoHashKey;
     if (gSecondRoundStarted) {
       // Compare the hash keys with the previous set ones.
-      // Hash keys should match if and only if their userContextId are the same.
-      for (let userContextId = 0; userContextId < 3; userContextId++) {
-        if (userContextId == this.userContextId) {
-          do_check_eq(hashKey, previousHashKeys[userContextId]);
+      // Hash keys should match if and only if their tlsFlags are the same.
+      for (let tlsFlags of randomFlagValues) {
+        if (tlsFlags == this.tlsFlags) {
+          do_check_eq(hashKey, previousHashKeys[tlsFlags]);
         } else {
-          do_check_neq(hashKey, previousHashKeys[userContextId]);
+          do_check_neq(hashKey, previousHashKeys[tlsFlags]);
         }
       }
     } else {
       // Set the hash keys in the first round.
-      previousHashKeys[this.userContextId] = hashKey;
+      previousHashKeys[this.tlsFlags] = hashKey;
     }
   },
   onDataAvailable: function(request, ctx, stream, off, cnt) {
     read_stream(stream, cnt);
   },
   onStopRequest: function() {
     gTestsRun++;
-    if (gTestsRun == 3) {
+    if (gTestsRun == randomFlagValues.length) {
       gTestsRun = 0;
       if (gSecondRoundStarted) {
         // The second round finishes.
         httpserv.stop(do_test_finished);
       } else {
         // The first round finishes. Do the second round.
         gSecondRoundStarted = true;
         doTest();
       }
     }
   },
 };
 
 function doTest() {
-  for (let userContextId = 0; userContextId < 3; userContextId++) {
-    let chan = makeChan(URL, userContextId);
-    let listener = new Listener(userContextId);
+  for (let tlsFlags of randomFlagValues) {
+    let chan = makeChan(URL, tlsFlags);
+    let listener = new Listener(tlsFlags);
     chan.asyncOpen2(listener);
   }
 }
 
 function run_test() {
   do_test_pending();
   httpserv = new HttpServer();
   httpserv.registerPathHandler("/", handler);
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -391,8 +391,9 @@ skip-if = os == "android"
 [test_trackingProtection_annotateChannels.js]
 [test_race_cache_with_network.js]
 [test_channel_priority.js]
 [test_bug1312774_http1.js]
 [test_1351443-missing-NewChannel2.js]
 [test_bug1312782_http1.js]
 [test_bug1355539_http1.js]
 [test_bug1378385_http1.js]
+[test_tls_flags_separate_connections.js]
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -70,17 +70,18 @@ getSiteKey(const nsACString& hostName, u
   key.AppendASCII(":");
   key.AppendInt(port);
 }
 
 } // unnamed namespace
 
 extern LazyLogModule gPIPNSSLog;
 
-nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
+nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags,
+                                 uint32_t providerTlsFlags)
   : mFd(nullptr),
     mCertVerificationState(before_cert_verification),
     mSharedState(aState),
     mForSTARTTLS(false),
     mHandshakePending(true),
     mRememberClientAuthCertificate(false),
     mPreliminaryHandshakeDone(false),
     mNPNCompleted(false),
@@ -94,16 +95,17 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedS
     mNotedTimeUntilReady(false),
     mFailedVerification(false),
     mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
     mKEAKeyBits(0),
     mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
     mMACAlgorithmUsed(nsISSLSocketControl::SSL_MAC_UNKNOWN),
     mBypassAuthentication(false),
     mProviderFlags(providerFlags),
+    mProviderTlsFlags(providerTlsFlags),
     mSocketCreationTimestamp(TimeStamp::Now()),
     mPlaintextBytesRead(0),
     mClientCert(nullptr)
 {
   mTLSVersionRange.min = 0;
   mTLSVersionRange.max = 0;
 }
 
@@ -118,16 +120,23 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketI
 NS_IMETHODIMP
 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
 {
   *aProviderFlags = mProviderFlags;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNSSSocketInfo::GetProviderTlsFlags(uint32_t* aProviderTlsFlags)
+{
+  *aProviderTlsFlags = mProviderTlsFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsNSSSocketInfo::GetKEAUsed(int16_t* aKea)
 {
   *aKea = mKEAUsed;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSSocketInfo::GetKEAKeyBits(uint32_t* aKeyBits)
@@ -1808,25 +1817,26 @@ nsresult
 nsSSLIOLayerNewSocket(int32_t family,
                       const char* host,
                       int32_t port,
                       nsIProxyInfo *proxy,
                       const OriginAttributes& originAttributes,
                       PRFileDesc** fd,
                       nsISupports** info,
                       bool forSTARTTLS,
-                      uint32_t flags)
+                      uint32_t flags,
+                      uint32_t tlsFlags)
 {
 
   PRFileDesc* sock = PR_OpenTCPSocket(family);
   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
 
   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxy,
                                         originAttributes, sock, info,
-                                        forSTARTTLS, flags);
+                                        forSTARTTLS, flags, tlsFlags);
   if (NS_FAILED(rv)) {
     PR_Close(sock);
     return rv;
   }
 
   *fd = sock;
   return NS_OK;
 }
@@ -2420,16 +2430,18 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
     }
   }
 
   SSLVersionRange range;
   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
 
+  // Use infoObject->GetProviderTlsFlags() to get the TLS flags
+
   if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
       (range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
             ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to BE_CONSERVATIVE flag\n",
              fd));
     range.max = SSL_LIBRARY_VERSION_TLS_1_2;
   }
 
@@ -2517,16 +2529,19 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
     peerId.AppendLiteral("private:");
   }
   if (flags & nsISocketProvider::MITM_OK) {
     peerId.AppendLiteral("bypassAuth:");
   }
   if (flags & nsISocketProvider::BE_CONSERVATIVE) {
     peerId.AppendLiteral("beConservative:");
   }
+
+  peerId.AppendPrintf("tlsflags0x%08x:", infoObject->GetProviderTlsFlags());
+
   peerId.Append(host);
   peerId.Append(':');
   peerId.AppendInt(port);
   nsAutoCString suffix;
   infoObject->GetOriginAttributes().CreateSuffix(suffix);
   peerId.Append(suffix);
   if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
     return NS_ERROR_FAILURE;
@@ -2539,27 +2554,28 @@ nsresult
 nsSSLIOLayerAddToSocket(int32_t family,
                         const char* host,
                         int32_t port,
                         nsIProxyInfo* proxy,
                         const OriginAttributes& originAttributes,
                         PRFileDesc* fd,
                         nsISupports** info,
                         bool forSTARTTLS,
-                        uint32_t providerFlags)
+                        uint32_t providerFlags,
+                        uint32_t providerTlsFlags)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* layer = nullptr;
   PRFileDesc* plaintextLayer = nullptr;
   nsresult rv;
   PRStatus stat;
 
   SharedSSLState* sharedState =
     providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
-  nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
+  nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags, providerTlsFlags);
   if (!infoObject) return NS_ERROR_FAILURE;
 
   NS_ADDREF(infoObject);
   infoObject->SetForSTARTTLS(forSTARTTLS);
   infoObject->SetHostName(host);
   infoObject->SetPort(port);
   infoObject->SetOriginAttributes(originAttributes);
 
--- a/security/manager/ssl/nsNSSIOLayer.h
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -30,17 +30,18 @@ using mozilla::OriginAttributes;
 
 class nsIObserver;
 
 class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo,
                               public nsISSLSocketControl,
                               public nsIClientAuthUserDecision
 {
 public:
-  nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags);
+  nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags,
+                  uint32_t providerTlsFlags);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSISSLSOCKETCONTROL
   NS_DECL_NSICLIENTAUTHUSERDECISION
 
   void SetForSTARTTLS(bool aForSTARTTLS);
   bool GetForSTARTTLS();
 
@@ -70,16 +71,17 @@ public:
   // it gets reset back to false.
   void SetFullHandshake() { mIsFullHandshake = true; }
   bool IsFullHandshake() const { return mIsFullHandshake; }
 
   bool GetJoined() { return mJoined; }
   void SetSentClientCert() { mSentClientCert = true; }
 
   uint32_t GetProviderFlags() const { return mProviderFlags; }
+  uint32_t GetProviderTlsFlags() const { return mProviderTlsFlags; }
 
   mozilla::psm::SharedSSLState& SharedState();
 
   // XXX: These are only used on for diagnostic purposes
   enum CertVerificationState {
     before_cert_verification,
     waiting_for_cert_verification,
     after_cert_verification
@@ -151,16 +153,17 @@ private:
   // Values are from nsISSLSocketControl
   int16_t mKEAUsed;
   uint32_t mKEAKeyBits;
   int16_t mSSLVersionUsed;
   int16_t mMACAlgorithmUsed;
   bool    mBypassAuthentication;
 
   uint32_t mProviderFlags;
+  uint32_t mProviderTlsFlags;
   mozilla::TimeStamp mSocketCreationTimestamp;
   uint64_t mPlaintextBytesRead;
 
   nsCOMPtr<nsIX509Cert> mClientCert;
 };
 
 class nsSSLIOLayerHelpers
 {
@@ -228,24 +231,26 @@ private:
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char* host,
                                int32_t port,
                                nsIProxyInfo *proxy,
                                const OriginAttributes& originAttributes,
                                PRFileDesc** fd,
                                nsISupports** securityInfo,
                                bool forSTARTTLS,
-                               uint32_t flags);
+                               uint32_t flags,
+                               uint32_t tlsFlags);
 
 nsresult nsSSLIOLayerAddToSocket(int32_t family,
                                  const char* host,
                                  int32_t port,
                                  nsIProxyInfo *proxy,
                                  const OriginAttributes& originAttributes,
                                  PRFileDesc* fd,
                                  nsISupports** securityInfo,
                                  bool forSTARTTLS,
-                                 uint32_t flags);
+                                 uint32_t flags,
+                                 uint32_t tlsFlags);
 
 nsresult nsSSLIOLayerFreeTLSIntolerantSites();
 nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo* infoObject, int error);
 
 #endif // nsNSSIOLayer_h
--- a/security/manager/ssl/nsSSLSocketProvider.cpp
+++ b/security/manager/ssl/nsSSLSocketProvider.cpp
@@ -23,46 +23,50 @@ NS_IMPL_ISUPPORTS(nsSSLSocketProvider, n
 
 NS_IMETHODIMP
 nsSSLSocketProvider::NewSocket(int32_t family,
                                const char *host,
                                int32_t port,
                                nsIProxyInfo *proxy,
                                const OriginAttributes &originAttributes,
                                uint32_t flags,
+                               uint32_t tlsFlags,
                                PRFileDesc **_result,
                                nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
                                       proxy,
                                       originAttributes,
                                       _result,
                                       securityInfo,
                                       false,
-                                      flags);
+                                      flags,
+                                      tlsFlags);
   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,
                                  nsIProxyInfo *proxy,
                                  const OriginAttributes &originAttributes,
                                  uint32_t flags,
+                                 uint32_t tlsFlags,
                                  PRFileDesc *aSocket,
                                  nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
                                         proxy,
                                         originAttributes,
                                         aSocket,
                                         securityInfo,
                                         false,
-                                        flags);
+                                        flags,
+                                        tlsFlags);
 
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }
--- a/security/manager/ssl/nsTLSSocketProvider.cpp
+++ b/security/manager/ssl/nsTLSSocketProvider.cpp
@@ -23,47 +23,51 @@ NS_IMPL_ISUPPORTS(nsTLSSocketProvider, n
 
 NS_IMETHODIMP
 nsTLSSocketProvider::NewSocket(int32_t family,
                                const char *host,
                                int32_t port,
                                nsIProxyInfo *proxy,
                                const OriginAttributes &originAttributes,
                                uint32_t flags,
+                               uint32_t tlsFlags,
                                PRFileDesc **_result,
                                nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerNewSocket(family,
                                       host,
                                       port,
                                       proxy,
                                       originAttributes,
                                       _result,
                                       securityInfo,
                                       true,
-                                      flags);
+                                      flags,
+                                      tlsFlags);
 
   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,
                                  int32_t port,
                                  nsIProxyInfo *proxy,
                                  const OriginAttributes &originAttributes,
                                  uint32_t flags,
+                                 uint32_t tlsFlags,
                                  PRFileDesc *aSocket,
                                  nsISupports **securityInfo)
 {
   nsresult rv = nsSSLIOLayerAddToSocket(family,
                                         host,
                                         port,
                                         proxy,
                                         originAttributes,
                                         aSocket,
                                         securityInfo,
                                         true,
-                                        flags);
+                                        flags,
+                                        tlsFlags);
 
   return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK;
 }