1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsSecureBrowserUI.h"
7 
8 #include "mozilla/Assertions.h"
9 #include "mozilla/Logging.h"
10 #include "mozilla/Unused.h"
11 #include "mozilla/dom/Document.h"
12 #include "nsContentUtils.h"
13 #include "nsIChannel.h"
14 #include "nsDocShell.h"
15 #include "nsIDocShellTreeItem.h"
16 #include "nsGlobalWindow.h"
17 #include "nsIInterfaceRequestorUtils.h"
18 #include "nsITransportSecurityInfo.h"
19 #include "nsIWebProgress.h"
20 #include "nsNetUtil.h"
21 #include "mozilla/dom/CanonicalBrowsingContext.h"
22 #include "mozilla/dom/WindowGlobalParent.h"
23 #include "mozilla/dom/Element.h"
24 #include "nsIBrowser.h"
25 
26 using namespace mozilla;
27 using namespace mozilla::dom;
28 
29 LazyLogModule gSecureBrowserUILog("nsSecureBrowserUI");
30 
nsSecureBrowserUI(CanonicalBrowsingContext * aBrowsingContext)31 nsSecureBrowserUI::nsSecureBrowserUI(CanonicalBrowsingContext* aBrowsingContext)
32     : mState(0) {
33   MOZ_ASSERT(NS_IsMainThread());
34 
35   // The BrowsingContext will own the SecureBrowserUI object, we keep a weak
36   // ref.
37   mBrowsingContextId = aBrowsingContext->Id();
38 }
39 
NS_IMPL_ISUPPORTS(nsSecureBrowserUI,nsISecureBrowserUI,nsISupportsWeakReference)40 NS_IMPL_ISUPPORTS(nsSecureBrowserUI, nsISecureBrowserUI,
41                   nsISupportsWeakReference)
42 
43 NS_IMETHODIMP
44 nsSecureBrowserUI::GetState(uint32_t* aState) {
45   MOZ_ASSERT(NS_IsMainThread());
46   NS_ENSURE_ARG(aState);
47 
48   MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
49           ("GetState %p mState: %x", this, mState));
50   *aState = mState;
51   return NS_OK;
52 }
53 
RecomputeSecurityFlags()54 void nsSecureBrowserUI::RecomputeSecurityFlags() {
55   // Our BrowsingContext either has a new WindowGlobalParent, or the
56   // existing one has mutated its security state.
57   // Recompute our security state and fire notifications to listeners
58 
59   RefPtr<WindowGlobalParent> win = GetCurrentWindow();
60   mState = nsIWebProgressListener::STATE_IS_INSECURE;
61 
62   // Only https is considered secure (it is possible to have e.g. an http URI
63   // with a channel that has a securityInfo that indicates the connection is
64   // secure - e.g. h2/alt-svc or by visiting an http URI over an https proxy).
65   nsCOMPtr<nsITransportSecurityInfo> securityInfo;
66   if (win && win->GetIsSecure()) {
67     securityInfo = win->GetSecurityInfo();
68     if (securityInfo) {
69       MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
70               ("  we have a security info %p", securityInfo.get()));
71 
72       nsresult rv = securityInfo->GetSecurityState(&mState);
73 
74       // If the security state is STATE_IS_INSECURE, the TLS handshake never
75       // completed. Don't set any further state.
76       if (NS_SUCCEEDED(rv) &&
77           mState != nsIWebProgressListener::STATE_IS_INSECURE) {
78         MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
79                 ("  set mTopLevelSecurityInfo"));
80         bool isEV;
81         rv = securityInfo->GetIsExtendedValidation(&isEV);
82         if (NS_SUCCEEDED(rv) && isEV) {
83           MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("  is EV"));
84           mState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
85         }
86       }
87     }
88   }
89 
90   // Add upgraded-state flags when request has been
91   // upgraded with HTTPS-Only Mode
92   if (win) {
93     // Check if top-level load has been upgraded
94     uint32_t httpsOnlyStatus = win->HttpsOnlyStatus();
95     if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) &&
96         !(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
97       mState |= nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED;
98     }
99     // Add the secruity flags from the window
100     mState |= win->GetSecurityFlags();
101   }
102 
103   // If we have loaded mixed content and this is a secure page,
104   // then clear secure flags and add broken instead.
105   static const uint32_t kLoadedMixedContentFlags =
106       nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
107       nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT;
108   if (win && win->GetIsSecure() && (mState & kLoadedMixedContentFlags)) {
109     // reset state security flag
110     mState = mState >> 4 << 4;
111     // set state security flag to broken, since there is mixed content
112     mState |= nsIWebProgressListener::STATE_IS_BROKEN;
113   }
114 
115   RefPtr<CanonicalBrowsingContext> ctx =
116       CanonicalBrowsingContext::Get(mBrowsingContextId);
117   if (!ctx) {
118     return;
119   }
120 
121   if (ctx->GetDocShell()) {
122     nsDocShell* nativeDocShell = nsDocShell::Cast(ctx->GetDocShell());
123     nativeDocShell->nsDocLoader::OnSecurityChange(nullptr, mState);
124   } else if (ctx->GetWebProgress()) {
125     ctx->GetWebProgress()->OnSecurityChange(nullptr, nullptr, mState);
126   }
127 }
128 
129 NS_IMETHODIMP
GetIsSecureContext(bool * aIsSecureContext)130 nsSecureBrowserUI::GetIsSecureContext(bool* aIsSecureContext) {
131   MOZ_ASSERT(NS_IsMainThread());
132   NS_ENSURE_ARG(aIsSecureContext);
133 
134   if (WindowGlobalParent* parent = GetCurrentWindow()) {
135     *aIsSecureContext = parent->GetIsSecureContext();
136   } else {
137     *aIsSecureContext = false;
138   }
139   return NS_OK;
140 }
141 
142 NS_IMETHODIMP
GetSecInfo(nsITransportSecurityInfo ** result)143 nsSecureBrowserUI::GetSecInfo(nsITransportSecurityInfo** result) {
144   MOZ_ASSERT(NS_IsMainThread());
145   NS_ENSURE_ARG_POINTER(result);
146 
147   if (WindowGlobalParent* parent = GetCurrentWindow()) {
148     *result = parent->GetSecurityInfo();
149   }
150   NS_IF_ADDREF(*result);
151 
152   return NS_OK;
153 }
154 
GetCurrentWindow()155 WindowGlobalParent* nsSecureBrowserUI::GetCurrentWindow() {
156   RefPtr<CanonicalBrowsingContext> ctx =
157       CanonicalBrowsingContext::Get(mBrowsingContextId);
158   if (!ctx) {
159     return nullptr;
160   }
161   return ctx->GetCurrentWindowGlobal();
162 }
163