Bug 1235572 - Enforce SRI if content signature is enforced r?francois draft
authorJonathan Hao <jhao@mozilla.com>
Wed, 16 Mar 2016 11:13:26 +0800
changeset 340868 8d6a126616f5128efe7c0227342aa061c8cb3250
parent 340475 7711458dcc0ee4af1aa08edfcfeca32761268582
child 340869 8774d06061b41424e6b99751cd5872b63912e90d
push id13083
push userjhao@mozilla.com
push dateWed, 16 Mar 2016 03:16:13 +0000
reviewersfrancois
bugs1235572
milestone48.0a1
Bug 1235572 - Enforce SRI if content signature is enforced r?francois * * * [mq]: sri_fix MozReview-Commit-ID: 8vY9J4j3Eog * * * [mq]: loadInfo MozReview-Commit-ID: EZ8BUfCOXO6 * * * [mq]: add-logs MozReview-Commit-ID: 1jeyTq9nvlW
dom/base/nsScriptLoader.cpp
ipc/glue/BackgroundUtils.cpp
layout/style/Loader.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsILoadInfo.idl
netwerk/ipc/NeckoChannelParams.ipdlh
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1408,30 +1408,39 @@ nsScriptLoader::OnStreamComplete(nsIIncr
                                  nsresult aSRIStatus,
                                  mozilla::Vector<char16_t> &aString,
                                  mozilla::dom::SRICheckDataVerifier* aSRIDataVerifier)
 {
   nsScriptLoadRequest* request = static_cast<nsScriptLoadRequest*>(aContext);
   NS_ASSERTION(request, "null request in stream complete handler");
   NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
 
+  nsCOMPtr<nsIRequest> channelRequest;
+  aLoader->GetRequest(getter_AddRefs(channelRequest));
+  nsCOMPtr<nsIChannel> channel;
+  channel = do_QueryInterface(channelRequest);
+
   nsresult rv = NS_OK;
   if (!request->mIntegrity.IsEmpty() &&
       NS_SUCCEEDED((rv = aSRIStatus))) {
     MOZ_ASSERT(aSRIDataVerifier);
-
-    nsCOMPtr<nsIRequest> channelRequest;
-    aLoader->GetRequest(getter_AddRefs(channelRequest));
-    nsCOMPtr<nsIChannel> channel;
-    channel = do_QueryInterface(channelRequest);
-
     if (NS_FAILED(aSRIDataVerifier->Verify(request->mIntegrity, channel,
                                            request->mCORSMode, mDocument))) {
       rv = NS_ERROR_SRI_CORRUPT;
     }
+  } else {
+    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+
+    bool enforceSRI = false;
+    loadInfo->GetEnforceSRI(&enforceSRI);
+    if (enforceSRI) {
+      MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
+             ("nsScriptLoader::OnStreamComplete, required SRI not found"));
+      rv = NS_ERROR_SRI_CORRUPT;
+    }
   }
 
   if (NS_SUCCEEDED(rv)) {
     rv = PrepareLoadedRequest(request, aLoader, aChannelStatus, aString);
   }
 
   if (NS_FAILED(rv)) {
     /*
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -240,16 +240,17 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
     LoadInfoArgs(
       requestingPrincipalInfo,
       triggeringPrincipalInfo,
       aLoadInfo->GetSecurityFlags(),
       aLoadInfo->InternalContentPolicyType(),
       static_cast<uint32_t>(aLoadInfo->GetTainting()),
       aLoadInfo->GetUpgradeInsecureRequests(),
       aLoadInfo->GetVerifySignedContent(),
+      aLoadInfo->GetEnforceSRI(),
       aLoadInfo->GetInnerWindowID(),
       aLoadInfo->GetOuterWindowID(),
       aLoadInfo->GetParentOuterWindowID(),
       aLoadInfo->GetEnforceSecurity(),
       aLoadInfo->GetInitialSecurityCheckDone(),
       aLoadInfo->GetIsInThirdPartyContext(),
       aLoadInfo->GetOriginAttributes(),
       redirectChainIncludingInternalRedirects,
@@ -300,16 +301,17 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(requestingPrincipal,
                           triggeringPrincipal,
                           loadInfoArgs.securityFlags(),
                           loadInfoArgs.contentPolicyType(),
                           static_cast<LoadTainting>(loadInfoArgs.tainting()),
                           loadInfoArgs.upgradeInsecureRequests(),
                           loadInfoArgs.verifySignedContent(),
+                          loadInfoArgs.enforceSRI(),
                           loadInfoArgs.innerWindowID(),
                           loadInfoArgs.outerWindowID(),
                           loadInfoArgs.parentOuterWindowID(),
                           loadInfoArgs.enforceSecurity(),
                           loadInfoArgs.initialSecurityCheckDone(),
                           loadInfoArgs.isInThirdPartyContext(),
                           loadInfoArgs.originAttributes(),
                           redirectChainIncludingInternalRedirects,
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -951,25 +951,39 @@ SheetLoadData::OnStreamComplete(nsIUnich
                 contentType.get()));
       mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
       return NS_OK;
     }
   }
 
   SRIMetadata sriMetadata;
   mSheet->GetIntegrity(sriMetadata);
-  if (!sriMetadata.IsEmpty() &&
-      NS_FAILED(SRICheck::VerifyIntegrity(sriMetadata, aLoader,
-                                          mSheet->GetCORSMode(), aBuffer,
-                                          mLoader->mDocument))) {
-    LOG(("  Load was blocked by SRI"));
-    MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
-            ("css::Loader::OnStreamComplete, bad metadata"));
-    mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
-    return NS_OK;
+
+  if (sriMetadata.IsEmpty()) {
+    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+    bool enforceSRI = false;
+    loadInfo->GetEnforceSRI(&enforceSRI);
+    if (enforceSRI) {
+      LOG(("  Load was blocked by SRI"));
+      MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
+              ("css::Loader::OnStreamComplete, required SRI not found"));
+      mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
+      return NS_OK;
+    }
+  } else {
+    nsresult rv = SRICheck::VerifyIntegrity(sriMetadata, aLoader,
+                                            mSheet->GetCORSMode(), aBuffer,
+                                            mLoader->mDocument);
+    if (NS_FAILED(rv)) {
+      LOG(("  Load was blocked by SRI"));
+      MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
+              ("css::Loader::OnStreamComplete, bad metadata"));
+      mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
+      return NS_OK;
+    }
   }
 
   // Enough to set the URIs on mSheet, since any sibling datas we have share
   // the same mInner as mSheet and will thus get the same URI.
   mSheet->SetURIs(channelURI, originalURI, channelURI);
 
   bool completed;
   result = mLoader->ParseSheet(aBuffer, this, completed);
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -42,16 +42,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mTriggeringPrincipal(aTriggeringPrincipal ?
                            aTriggeringPrincipal : mLoadingPrincipal.get())
   , mLoadingContext(do_GetWeakReference(aLoadingContext))
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
+  , mEnforceSRI(false)
   , mInnerWindowID(0)
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
   , mIsThirdPartyContext(true)
   , mForcePreflight(false)
   , mIsPreflight(false)
@@ -99,32 +100,42 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
 
     // if the document forces all requests to be upgraded from http to https, then
     // we should do that for all requests. If it only forces preloads to be upgraded
     // then we should enforce upgrade insecure requests only for preloads.
     mUpgradeInsecureRequests =
       aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) ||
       (nsContentUtils::IsPreloadType(mInternalContentPolicyType) &&
        aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(true));
+
+    // if owner doc has content signature, we enforce SRI
+    nsCOMPtr<nsIChannel> channel = aLoadingContext->OwnerDoc()->GetChannel();
+    if (channel) {
+      nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+      if (loadInfo) {
+        loadInfo->GetVerifySignedContent(&mEnforceSRI);
+      }
+    }
   }
 
   InheritOriginAttributes(mLoadingPrincipal, mOriginAttributes);
 }
 
 LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
                    nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsSecurityFlags aSecurityFlags)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
+  , mEnforceSRI(false)
   , mInnerWindowID(0)
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
   , mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
   , mForcePreflight(false)
   , mIsPreflight(false)
@@ -153,16 +164,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   : mLoadingPrincipal(rhs.mLoadingPrincipal)
   , mTriggeringPrincipal(rhs.mTriggeringPrincipal)
   , mLoadingContext(rhs.mLoadingContext)
   , mSecurityFlags(rhs.mSecurityFlags)
   , mInternalContentPolicyType(rhs.mInternalContentPolicyType)
   , mTainting(rhs.mTainting)
   , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests)
   , mVerifySignedContent(rhs.mVerifySignedContent)
+  , mEnforceSRI(rhs.mEnforceSRI)
   , mInnerWindowID(rhs.mInnerWindowID)
   , mOuterWindowID(rhs.mOuterWindowID)
   , mParentOuterWindowID(rhs.mParentOuterWindowID)
   , mEnforceSecurity(rhs.mEnforceSecurity)
   , mInitialSecurityCheckDone(rhs.mInitialSecurityCheckDone)
   , mIsThirdPartyContext(rhs.mIsThirdPartyContext)
   , mOriginAttributes(rhs.mOriginAttributes)
   , mRedirectChainIncludingInternalRedirects(
@@ -176,16 +188,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType,
                    LoadTainting aTainting,
                    bool aUpgradeInsecureRequests,
                    bool aVerifySignedContent,
+                   bool aEnforceSRI,
                    uint64_t aInnerWindowID,
                    uint64_t aOuterWindowID,
                    uint64_t aParentOuterWindowID,
                    bool aEnforceSecurity,
                    bool aInitialSecurityCheckDone,
                    bool aIsThirdPartyContext,
                    const NeckoOriginAttributes& aOriginAttributes,
                    nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
@@ -195,16 +208,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    bool aIsPreflight)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(aTainting)
   , mUpgradeInsecureRequests(aUpgradeInsecureRequests)
   , mVerifySignedContent(aVerifySignedContent)
+  , mEnforceSRI(aEnforceSRI)
   , mInnerWindowID(aInnerWindowID)
   , mOuterWindowID(aOuterWindowID)
   , mParentOuterWindowID(aParentOuterWindowID)
   , mEnforceSecurity(aEnforceSecurity)
   , mInitialSecurityCheckDone(aInitialSecurityCheckDone)
   , mIsThirdPartyContext(aIsThirdPartyContext)
   , mOriginAttributes(aOriginAttributes)
   , mCorsUnsafeHeaders(aCorsUnsafeHeaders)
@@ -444,16 +458,30 @@ LoadInfo::SetVerifySignedContent(bool aV
 NS_IMETHODIMP
 LoadInfo::GetVerifySignedContent(bool* aResult)
 {
   *aResult = mVerifySignedContent;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::SetEnforceSRI(bool aEnforceSRI)
+{
+  mEnforceSRI = aEnforceSRI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetEnforceSRI(bool* aResult)
+{
+  *aResult = mEnforceSRI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 LoadInfo::GetInnerWindowID(uint64_t* aResult)
 {
   *aResult = mInnerWindowID;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LoadInfo::GetOuterWindowID(uint64_t* aResult)
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -76,16 +76,17 @@ private:
   // Please note that aRedirectChain uses swapElements.
   LoadInfo(nsIPrincipal* aLoadingPrincipal,
            nsIPrincipal* aTriggeringPrincipal,
            nsSecurityFlags aSecurityFlags,
            nsContentPolicyType aContentPolicyType,
            LoadTainting aTainting,
            bool aUpgradeInsecureRequests,
            bool aVerifySignedContent,
+           bool aEnforceSRI,
            uint64_t aInnerWindowID,
            uint64_t aOuterWindowID,
            uint64_t aParentOuterWindowID,
            bool aEnforceSecurity,
            bool aInitialSecurityCheckDone,
            bool aIsThirdPartyRequest,
            const NeckoOriginAttributes& aOriginAttributes,
            nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
@@ -114,16 +115,17 @@ private:
   nsCOMPtr<nsIPrincipal>           mLoadingPrincipal;
   nsCOMPtr<nsIPrincipal>           mTriggeringPrincipal;
   nsWeakPtr                        mLoadingContext;
   nsSecurityFlags                  mSecurityFlags;
   nsContentPolicyType              mInternalContentPolicyType;
   LoadTainting                     mTainting;
   bool                             mUpgradeInsecureRequests;
   bool                             mVerifySignedContent;
+  bool                             mEnforceSRI;
   uint64_t                         mInnerWindowID;
   uint64_t                         mOuterWindowID;
   uint64_t                         mParentOuterWindowID;
   bool                             mEnforceSecurity;
   bool                             mInitialSecurityCheckDone;
   bool                             mIsThirdPartyContext;
   NeckoOriginAttributes            mOriginAttributes;
   nsTArray<nsCOMPtr<nsIPrincipal>> mRedirectChainIncludingInternalRedirects;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -343,16 +343,21 @@ interface nsILoadInfo : nsISupports
    * can not start until all of the content is fetched from the
    * netwerk.
    *
    * Only use that in combination with TYPE_DOCUMENT.
    */
   [infallible] attribute boolean verifySignedContent;
 
   /**
+   * If true, this load will fail if it has no SRI integrity
+   */
+  [infallible] attribute boolean enforceSRI;
+
+  /**
    * Typically these are the window IDs of the window in which the element being
    * loaded lives. However, if the element being loaded is <frame
    * src="foo.html"> (or, more generally, if the element QIs to
    * nsIFrameLoaderOwner) then the window IDs are for the window containing the
    * foo.html document. In this case, parentOuterWindowID is the window ID of
    * the window containing the <frame> element.
    *
    * Note that these window IDs can be 0 if the window is not
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -29,16 +29,17 @@ struct LoadInfoArgs
 {
   PrincipalInfo    requestingPrincipalInfo;
   PrincipalInfo    triggeringPrincipalInfo;
   uint32_t         securityFlags;
   uint32_t         contentPolicyType;
   uint32_t         tainting;
   bool             upgradeInsecureRequests;
   bool             verifySignedContent;
+  bool             enforceSRI;
   uint64_t         innerWindowID;
   uint64_t         outerWindowID;
   uint64_t         parentOuterWindowID;
   bool             enforceSecurity;
   bool             initialSecurityCheckDone;
   bool             isInThirdPartyContext;
   NeckoOriginAttributes originAttributes;
   PrincipalInfo[]  redirectChainIncludingInternalRedirects;