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 647795 bfe9b1d9ad1193b3d4b4e026d7dfbf998603f3db
parent 647794 8dfe4d26c70f4a792b429186c8ece3d1164efdc8
child 647796 c217dd347b0170650b8f90b2f4d48f683be832c6
push id74542
push usermaglione.k@gmail.com
push dateWed, 16 Aug 2017 23:10:03 +0000
reviewersmcmanus, keeler
bugs1388925
milestone57.0a1
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;
 }