/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 "nsSecureBrowserUI.h" #include "mozilla/Assertions.h" #include "mozilla/Logging.h" #include "mozilla/Unused.h" #include "mozilla/dom/Document.h" #include "nsContentUtils.h" #include "nsIChannel.h" #include "nsDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsIInterfaceRequestorUtils.h" #include "nsITransportSecurityInfo.h" #include "nsIWebProgress.h" #include "nsNetUtil.h" #include "mozilla/dom/CanonicalBrowsingContext.h" #include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/dom/Element.h" #include "nsIBrowser.h" using namespace mozilla; using namespace mozilla::dom; LazyLogModule gSecureBrowserUILog("nsSecureBrowserUI"); nsSecureBrowserUI::nsSecureBrowserUI(CanonicalBrowsingContext* aBrowsingContext) : mState(0) { MOZ_ASSERT(NS_IsMainThread()); // The BrowsingContext will own the SecureBrowserUI object, we keep a weak // ref. mBrowsingContextId = aBrowsingContext->Id(); } NS_IMPL_ISUPPORTS(nsSecureBrowserUI, nsISecureBrowserUI, nsISupportsWeakReference) NS_IMETHODIMP nsSecureBrowserUI::GetState(uint32_t* aState) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_ARG(aState); MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("GetState %p mState: %x", this, mState)); *aState = mState; return NS_OK; } void nsSecureBrowserUI::RecomputeSecurityFlags() { // Our BrowsingContext either has a new WindowGlobalParent, or the // existing one has mutated its security state. // Recompute our security state and fire notifications to listeners RefPtr win = GetCurrentWindow(); mState = nsIWebProgressListener::STATE_IS_INSECURE; // Only https is considered secure (it is possible to have e.g. an http URI // with a channel that has a securityInfo that indicates the connection is // secure - e.g. h2/alt-svc or by visiting an http URI over an https proxy). nsCOMPtr securityInfo; if (win && win->GetIsSecure()) { securityInfo = win->GetSecurityInfo(); if (securityInfo) { MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, (" we have a security info %p", securityInfo.get())); nsresult rv = securityInfo->GetSecurityState(&mState); // If the security state is STATE_IS_INSECURE, the TLS handshake never // completed. Don't set any further state. if (NS_SUCCEEDED(rv) && mState != nsIWebProgressListener::STATE_IS_INSECURE) { MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, (" set mTopLevelSecurityInfo")); bool isEV; rv = securityInfo->GetIsExtendedValidation(&isEV); if (NS_SUCCEEDED(rv) && isEV) { MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, (" is EV")); mState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL; } } } } // Add upgraded-state flags when request has been // upgraded with HTTPS-Only Mode if (win) { // Check if top-level load has been upgraded uint32_t httpsOnlyStatus = win->HttpsOnlyStatus(); if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) && !(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT)) { mState |= nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED; } if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST) { if (win->GetDocumentURI()->SchemeIs("https")) { mState |= nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED_FIRST; } else { mState |= nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED; } } // Add the secruity flags from the window mState |= win->GetSecurityFlags(); } // If we have loaded mixed content and this is a secure page, // then clear secure flags and add broken instead. static const uint32_t kLoadedMixedContentFlags = nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT; if (win && win->GetIsSecure() && (mState & kLoadedMixedContentFlags)) { // reset state security flag mState = mState >> 4 << 4; // set state security flag to broken, since there is mixed content mState |= nsIWebProgressListener::STATE_IS_BROKEN; } RefPtr ctx = CanonicalBrowsingContext::Get(mBrowsingContextId); if (!ctx) { return; } if (ctx->GetDocShell()) { nsDocShell* nativeDocShell = nsDocShell::Cast(ctx->GetDocShell()); nativeDocShell->nsDocLoader::OnSecurityChange(nullptr, mState); } else if (ctx->GetWebProgress()) { ctx->GetWebProgress()->OnSecurityChange(nullptr, nullptr, mState); } } NS_IMETHODIMP nsSecureBrowserUI::GetIsSecureContext(bool* aIsSecureContext) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_ARG(aIsSecureContext); if (WindowGlobalParent* parent = GetCurrentWindow()) { *aIsSecureContext = parent->GetIsSecureContext(); } else { *aIsSecureContext = false; } return NS_OK; } NS_IMETHODIMP nsSecureBrowserUI::GetSecInfo(nsITransportSecurityInfo** result) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_ARG_POINTER(result); if (WindowGlobalParent* parent = GetCurrentWindow()) { *result = parent->GetSecurityInfo(); } NS_IF_ADDREF(*result); return NS_OK; } WindowGlobalParent* nsSecureBrowserUI::GetCurrentWindow() { RefPtr ctx = CanonicalBrowsingContext::Get(mBrowsingContextId); if (!ctx) { return nullptr; } return ctx->GetCurrentWindowGlobal(); }