/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PolicyContainer.h" #include "mozilla/dom/IntegrityPolicy.h" #include "mozilla/dom/IntegrityPolicyWAICT.h" #include "mozilla/dom/nsCSPContext.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "nsIClassInfoImpl.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" using namespace mozilla; using namespace mozilla::dom; PolicyContainer::PolicyContainer() = default; PolicyContainer::~PolicyContainer() = default; constexpr static uint32_t kPolicyContainerSerializationVersion = 1; NS_IMETHODIMP PolicyContainer::Read(nsIObjectInputStream* aStream) { // Currently, we don't care about the version, but we might in the future. uint32_t version = 0; MOZ_TRY(aStream->Read32(&version)); if (version != kPolicyContainerSerializationVersion) { return NS_ERROR_FAILURE; } auto ReadOptionalCSPObject = [aStream](nsISupports** aOutCSP) -> nsresult { bool nonnull = false; MOZ_TRY(aStream->ReadBoolean(&nonnull)); if (nonnull) { nsCID cid; MOZ_TRY(aStream->ReadID(&cid)); MOZ_ASSERT(cid.Equals(nsCSPContext::GetCID()), "Expected nsCSPContext CID"); nsIID iid; MOZ_TRY(aStream->ReadID(&iid)); MOZ_ASSERT(iid.Equals(NS_GET_IID(nsIContentSecurityPolicy)), "Expected nsIContentSecurityPolicy IID"); RefPtr csp = new nsCSPContext(); MOZ_TRY(csp->PolicyContainerRead(aStream)); csp.forget(aOutCSP); } return NS_OK; }; nsCOMPtr csp; MOZ_TRY(ReadOptionalCSPObject(getter_AddRefs(csp))); mCSP = do_QueryInterface(csp); nsCOMPtr integrityPolicy; MOZ_TRY( NS_ReadOptionalObject(aStream, true, getter_AddRefs(integrityPolicy))); mIntegrityPolicy = do_QueryInterface(integrityPolicy); return NS_OK; } NS_IMETHODIMP PolicyContainer::Write(nsIObjectOutputStream* aStream) { MOZ_TRY(aStream->Write32(kPolicyContainerSerializationVersion)); MOZ_TRY(NS_WriteOptionalCompoundObject( aStream, mCSP, NS_GET_IID(nsIContentSecurityPolicy), true)); MOZ_TRY(NS_WriteOptionalCompoundObject(aStream, mIntegrityPolicy, NS_GET_IID(nsIIntegrityPolicy), true)); // TODO(Bug 2017654): (De)Serialize the WAICT state as part of the // Policy-Container return NS_OK; } void PolicyContainer::ToArgs(const PolicyContainer* aPolicy, mozilla::ipc::PolicyContainerArgs& aArgs) { if (!aPolicy) { return; } if (aPolicy->mCSP) { mozilla::ipc::CSPInfo cspInfo; mozilla::ipc::CSPToCSPInfo(aPolicy->mCSP, &cspInfo); aArgs.csp() = Some(cspInfo); } if (aPolicy->mIntegrityPolicy) { mozilla::ipc::IntegrityPolicyArgs integrityPolicyArgs; IntegrityPolicy::ToArgs(IntegrityPolicy::Cast(aPolicy->mIntegrityPolicy), integrityPolicyArgs); aArgs.integrityPolicy() = Some(integrityPolicyArgs); } } void PolicyContainer::FromArgs(const mozilla::ipc::PolicyContainerArgs& aArgs, mozilla::dom::Document* aRequestingDocument, PolicyContainer** aPolicy) { RefPtr policy = new PolicyContainer(); if (aArgs.csp().isSome()) { nsCOMPtr csp = mozilla::ipc::CSPInfoToCSP(*aArgs.csp(), aRequestingDocument); policy->SetCSP(nsCSPContext::Cast(csp)); } if (aArgs.integrityPolicy().isSome()) { RefPtr integrityPolicy = new dom::IntegrityPolicy(); IntegrityPolicy::FromArgs(*aArgs.integrityPolicy(), getter_AddRefs(integrityPolicy)); policy->SetIntegrityPolicy(integrityPolicy); } policy.forget(aPolicy); } void PolicyContainer::InitFromOther(PolicyContainer* aOther) { if (!aOther) { return; } if (aOther->mCSP) { RefPtr csp = new nsCSPContext(); csp = new nsCSPContext(); csp->InitFromOther(nsCSPContext::Cast(aOther->mCSP)); mCSP = csp; } if (aOther->mIntegrityPolicy) { RefPtr integrityPolicy = new dom::IntegrityPolicy(); integrityPolicy->InitFromOther( IntegrityPolicy::Cast(aOther->mIntegrityPolicy)); mIntegrityPolicy = integrityPolicy; } } NS_IMETHODIMP PolicyContainer::InitFromCSP(nsIContentSecurityPolicy* aCSP) { SetCSP(aCSP); return NS_OK; } bool PolicyContainer::Equals(const PolicyContainer* aContainer, const PolicyContainer* aOtherContainer) { // Do a quick pointer check first, also checks if both are null. if (aContainer == aOtherContainer) { return true; } // We checked if they were null above, so make sure one of them is not null. if (!aContainer || !aOtherContainer) { return false; } if (!nsCSPContext::Equals(aContainer->mCSP, aOtherContainer->mCSP)) { return false; } if (!IntegrityPolicy::Equals( IntegrityPolicy::Cast(aContainer->mIntegrityPolicy), IntegrityPolicy::Cast(aOtherContainer->mIntegrityPolicy))) { return false; } // TODO(Bug 2017654): Handle equality for WAICT. return true; } // == CSP == void PolicyContainer::SetCSP(nsIContentSecurityPolicy* aPolicy) { mCSP = aPolicy; } nsIContentSecurityPolicy* PolicyContainer::GetCSP() const { return mCSP; } nsIContentSecurityPolicy* PolicyContainer::GetCSP( const nsIPolicyContainer* aPolicyContainer) { if (!aPolicyContainer) { return nullptr; } return PolicyContainer::Cast(aPolicyContainer)->GetCSP(); } // == Integrity Policy == void PolicyContainer::SetIntegrityPolicy(nsIIntegrityPolicy* aPolicy) { mIntegrityPolicy = aPolicy; } nsIIntegrityPolicy* PolicyContainer::GetIntegrityPolicy() const { return mIntegrityPolicy; } nsIIntegrityPolicy* PolicyContainer::GetIntegrityPolicy( const nsIPolicyContainer* aPolicyContainer) { if (!aPolicyContainer) { return nullptr; } return PolicyContainer::Cast(aPolicyContainer)->GetIntegrityPolicy(); } // == WAICT Integrity Policy == void PolicyContainer::SetIntegrityPolicyWAICT(IntegrityPolicyWAICT* aPolicy) { mIntegrityPolicyWAICT = aPolicy; } IntegrityPolicyWAICT* PolicyContainer::GetIntegrityPolicyWAICT() const { return mIntegrityPolicyWAICT; } IntegrityPolicyWAICT* PolicyContainer::GetIntegrityPolicyWAICT( const nsIPolicyContainer* aPolicyContainer) { if (!aPolicyContainer) { return nullptr; } return PolicyContainer::Cast(aPolicyContainer)->GetIntegrityPolicyWAICT(); } NS_IMETHODIMP PolicyContainer::GetCsp(nsIContentSecurityPolicy** aCsp) { nsCOMPtr csp = mCSP; csp.forget(aCsp); return NS_OK; } NS_IMPL_CLASSINFO(PolicyContainer, nullptr, 0, NS_IPOLICYCONTAINER_IID) NS_IMPL_ISUPPORTS_CI(PolicyContainer, nsIPolicyContainer, nsISerializable)