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