OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ssl/ssl_manager.h" | 5 #include "chrome/browser/ssl/ssl_manager.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/browser/chrome_thread.h" | 9 #include "chrome/browser/chrome_thread.h" |
10 #include "chrome/browser/load_from_memory_cache_details.h" | 10 #include "chrome/browser/load_from_memory_cache_details.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "chrome/common/pref_names.h" | 21 #include "chrome/common/pref_names.h" |
22 #include "grit/generated_resources.h" | 22 #include "grit/generated_resources.h" |
23 #include "net/base/cert_status_flags.h" | 23 #include "net/base/cert_status_flags.h" |
24 | 24 |
25 // static | 25 // static |
26 void SSLManager::RegisterUserPrefs(PrefService* prefs) { | 26 void SSLManager::RegisterUserPrefs(PrefService* prefs) { |
27 prefs->RegisterIntegerPref(prefs::kMixedContentFiltering, | 27 prefs->RegisterIntegerPref(prefs::kMixedContentFiltering, |
28 FilterPolicy::DONT_FILTER); | 28 FilterPolicy::DONT_FILTER); |
29 } | 29 } |
30 | 30 |
| 31 // static |
| 32 void SSLManager::OnSSLCertificateError(ResourceDispatcherHost* rdh, |
| 33 URLRequest* request, |
| 34 int cert_error, |
| 35 net::X509Certificate* cert) { |
| 36 DLOG(INFO) << "OnSSLCertificateError() cert_error: " << cert_error << |
| 37 " url: " << request->url().spec(); |
| 38 |
| 39 ResourceDispatcherHostRequestInfo* info = |
| 40 ResourceDispatcherHost::InfoForRequest(request); |
| 41 DCHECK(info); |
| 42 |
| 43 // A certificate error occurred. Construct a SSLCertErrorHandler object and |
| 44 // hand it over to the UI thread for processing. |
| 45 ChromeThread::PostTask( |
| 46 ChromeThread::UI, FROM_HERE, |
| 47 NewRunnableMethod(new SSLCertErrorHandler(rdh, |
| 48 request, |
| 49 info->resource_type(), |
| 50 info->frame_origin(), |
| 51 info->main_frame_origin(), |
| 52 cert_error, |
| 53 cert), |
| 54 &SSLCertErrorHandler::Dispatch)); |
| 55 } |
| 56 |
| 57 // static |
| 58 void SSLManager::NotifySSLInternalStateChanged() { |
| 59 NotificationService::current()->Notify( |
| 60 NotificationType::SSL_INTERNAL_STATE_CHANGED, |
| 61 NotificationService::AllSources(), |
| 62 NotificationService::NoDetails()); |
| 63 } |
| 64 |
| 65 // static |
| 66 std::string SSLManager::SerializeSecurityInfo(int cert_id, |
| 67 int cert_status, |
| 68 int security_bits) { |
| 69 Pickle pickle; |
| 70 pickle.WriteInt(cert_id); |
| 71 pickle.WriteInt(cert_status); |
| 72 pickle.WriteInt(security_bits); |
| 73 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); |
| 74 } |
| 75 |
| 76 // static |
| 77 bool SSLManager::DeserializeSecurityInfo(const std::string& state, |
| 78 int* cert_id, |
| 79 int* cert_status, |
| 80 int* security_bits) { |
| 81 DCHECK(cert_id && cert_status && security_bits); |
| 82 if (state.empty()) { |
| 83 // No SSL used. |
| 84 *cert_id = 0; |
| 85 *cert_status = 0; |
| 86 *security_bits = -1; |
| 87 return false; |
| 88 } |
| 89 |
| 90 Pickle pickle(state.data(), static_cast<int>(state.size())); |
| 91 void * iter = NULL; |
| 92 return pickle.ReadInt(&iter, cert_id) && |
| 93 pickle.ReadInt(&iter, cert_status) && |
| 94 pickle.ReadInt(&iter, security_bits); |
| 95 } |
| 96 |
| 97 // static |
| 98 std::wstring SSLManager::GetEVCertName(const net::X509Certificate& cert) { |
| 99 // EV are required to have an organization name and country. |
| 100 if (cert.subject().organization_names.empty() || |
| 101 cert.subject().country_name.empty()) { |
| 102 NOTREACHED(); |
| 103 return std::wstring(); |
| 104 } |
| 105 |
| 106 return l10n_util::GetStringF(IDS_SECURE_CONNECTION_EV, |
| 107 UTF8ToWide(cert.subject().organization_names[0]), |
| 108 UTF8ToWide(cert.subject().country_name)); |
| 109 } |
| 110 |
31 SSLManager::SSLManager(NavigationController* controller) | 111 SSLManager::SSLManager(NavigationController* controller) |
32 : backend_(controller), | 112 : backend_(controller), |
33 policy_(new SSLPolicy(&backend_)), | 113 policy_(new SSLPolicy(&backend_)), |
34 controller_(controller) { | 114 controller_(controller) { |
35 DCHECK(controller_); | 115 DCHECK(controller_); |
36 | 116 |
37 // Subscribe to various notifications. | 117 // Subscribe to various notifications. |
38 registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, | 118 registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, |
39 Source<NavigationController>(controller_)); | 119 Source<NavigationController>(controller_)); |
40 registrar_.Add(this, NotificationType::RESOURCE_RESPONSE_STARTED, | 120 registrar_.Add(this, NotificationType::RESOURCE_RESPONSE_STARTED, |
41 Source<NavigationController>(controller_)); | 121 Source<NavigationController>(controller_)); |
42 registrar_.Add(this, NotificationType::RESOURCE_RECEIVED_REDIRECT, | 122 registrar_.Add(this, NotificationType::RESOURCE_RECEIVED_REDIRECT, |
43 Source<NavigationController>(controller_)); | 123 Source<NavigationController>(controller_)); |
44 registrar_.Add(this, NotificationType::LOAD_FROM_MEMORY_CACHE, | 124 registrar_.Add(this, NotificationType::LOAD_FROM_MEMORY_CACHE, |
45 Source<NavigationController>(controller_)); | 125 Source<NavigationController>(controller_)); |
46 registrar_.Add(this, NotificationType::SSL_INTERNAL_STATE_CHANGED, | 126 registrar_.Add(this, NotificationType::SSL_INTERNAL_STATE_CHANGED, |
47 NotificationService::AllSources()); | 127 NotificationService::AllSources()); |
48 } | 128 } |
49 | 129 |
50 SSLManager::~SSLManager() { | 130 SSLManager::~SSLManager() { |
51 } | 131 } |
52 | 132 |
| 133 void SSLManager::DidCommitProvisionalLoad( |
| 134 const NotificationDetails& in_details) { |
| 135 NavigationController::LoadCommittedDetails* details = |
| 136 Details<NavigationController::LoadCommittedDetails>(in_details).ptr(); |
| 137 |
| 138 NavigationEntry* entry = controller_->GetActiveEntry(); |
| 139 |
| 140 if (details->is_main_frame) { |
| 141 if (entry) { |
| 142 // Decode the security details. |
| 143 int ssl_cert_id, ssl_cert_status, ssl_security_bits; |
| 144 DeserializeSecurityInfo(details->serialized_security_info, |
| 145 &ssl_cert_id, |
| 146 &ssl_cert_status, |
| 147 &ssl_security_bits); |
| 148 |
| 149 // We may not have an entry if this is a navigation to an initial blank |
| 150 // page. Reset the SSL information and add the new data we have. |
| 151 entry->ssl() = NavigationEntry::SSLStatus(); |
| 152 entry->ssl().set_cert_id(ssl_cert_id); |
| 153 entry->ssl().set_cert_status(ssl_cert_status); |
| 154 entry->ssl().set_security_bits(ssl_security_bits); |
| 155 } |
| 156 backend_.ShowPendingMessages(); |
| 157 } |
| 158 |
| 159 UpdateEntry(entry); |
| 160 } |
| 161 |
| 162 void SSLManager::DidRunInsecureContent(const std::string& security_origin) { |
| 163 policy()->DidRunInsecureContent(controller_->GetActiveEntry(), |
| 164 security_origin); |
| 165 } |
| 166 |
53 bool SSLManager::ProcessedSSLErrorFromRequest() const { | 167 bool SSLManager::ProcessedSSLErrorFromRequest() const { |
54 NavigationEntry* entry = controller_->GetActiveEntry(); | 168 NavigationEntry* entry = controller_->GetActiveEntry(); |
55 if (!entry) { | 169 if (!entry) { |
56 NOTREACHED(); | 170 NOTREACHED(); |
57 return false; | 171 return false; |
58 } | 172 } |
59 | 173 |
60 return net::IsCertStatusError(entry->ssl().cert_status()); | 174 return net::IsCertStatusError(entry->ssl().cert_status()); |
61 } | 175 } |
62 | 176 |
63 // static | |
64 void SSLManager::OnSSLCertificateError(ResourceDispatcherHost* rdh, | |
65 URLRequest* request, | |
66 int cert_error, | |
67 net::X509Certificate* cert) { | |
68 DLOG(INFO) << "OnSSLCertificateError() cert_error: " << cert_error << | |
69 " url: " << request->url().spec(); | |
70 | |
71 ResourceDispatcherHostRequestInfo* info = | |
72 ResourceDispatcherHost::InfoForRequest(request); | |
73 DCHECK(info); | |
74 | |
75 // A certificate error occurred. Construct a SSLCertErrorHandler object and | |
76 // hand it over to the UI thread for processing. | |
77 ChromeThread::PostTask( | |
78 ChromeThread::UI, FROM_HERE, | |
79 NewRunnableMethod(new SSLCertErrorHandler(rdh, | |
80 request, | |
81 info->resource_type(), | |
82 info->frame_origin(), | |
83 info->main_frame_origin(), | |
84 cert_error, | |
85 cert), | |
86 &SSLCertErrorHandler::Dispatch)); | |
87 } | |
88 | |
89 void SSLManager::DidDisplayInsecureContent() { | |
90 policy()->DidDisplayInsecureContent(controller_->GetActiveEntry()); | |
91 } | |
92 | |
93 void SSLManager::DidRunInsecureContent(const std::string& security_origin) { | |
94 policy()->DidRunInsecureContent(controller_->GetActiveEntry(), | |
95 security_origin); | |
96 } | |
97 | |
98 void SSLManager::Observe(NotificationType type, | 177 void SSLManager::Observe(NotificationType type, |
99 const NotificationSource& source, | 178 const NotificationSource& source, |
100 const NotificationDetails& details) { | 179 const NotificationDetails& details) { |
101 // Dispatch by type. | 180 // Dispatch by type. |
102 switch (type.value) { | 181 switch (type.value) { |
103 case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: | 182 case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: |
104 DidFailProvisionalLoadWithError( | 183 DidFailProvisionalLoadWithError( |
105 Details<ProvisionalLoadDetails>(details).ptr()); | 184 Details<ProvisionalLoadDetails>(details).ptr()); |
106 break; | 185 break; |
107 case NotificationType::RESOURCE_RESPONSE_STARTED: | 186 case NotificationType::RESOURCE_RESPONSE_STARTED: |
108 DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr()); | 187 DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr()); |
109 break; | 188 break; |
110 case NotificationType::RESOURCE_RECEIVED_REDIRECT: | 189 case NotificationType::RESOURCE_RECEIVED_REDIRECT: |
111 DidReceiveResourceRedirect( | 190 DidReceiveResourceRedirect( |
112 Details<ResourceRedirectDetails>(details).ptr()); | 191 Details<ResourceRedirectDetails>(details).ptr()); |
113 break; | 192 break; |
114 case NotificationType::LOAD_FROM_MEMORY_CACHE: | 193 case NotificationType::LOAD_FROM_MEMORY_CACHE: |
115 DidLoadFromMemoryCache( | 194 DidLoadFromMemoryCache( |
116 Details<LoadFromMemoryCacheDetails>(details).ptr()); | 195 Details<LoadFromMemoryCacheDetails>(details).ptr()); |
117 break; | 196 break; |
118 case NotificationType::SSL_INTERNAL_STATE_CHANGED: | 197 case NotificationType::SSL_INTERNAL_STATE_CHANGED: |
119 DidChangeSSLInternalState(); | 198 DidChangeSSLInternalState(); |
120 break; | 199 break; |
121 default: | 200 default: |
122 NOTREACHED() << "The SSLManager received an unexpected notification."; | 201 NOTREACHED() << "The SSLManager received an unexpected notification."; |
123 } | 202 } |
124 } | 203 } |
125 | 204 |
126 void SSLManager::DispatchSSLVisibleStateChanged() { | |
127 NotificationService::current()->Notify( | |
128 NotificationType::SSL_VISIBLE_STATE_CHANGED, | |
129 Source<NavigationController>(controller_), | |
130 NotificationService::NoDetails()); | |
131 } | |
132 | |
133 void SSLManager::UpdateEntry(NavigationEntry* entry) { | |
134 // We don't always have a navigation entry to update, for example in the | |
135 // case of the Web Inspector. | |
136 if (!entry) | |
137 return; | |
138 | |
139 NavigationEntry::SSLStatus original_ssl_status = entry->ssl(); // Copy! | |
140 | |
141 policy()->UpdateEntry(entry); | |
142 | |
143 if (!entry->ssl().Equals(original_ssl_status)) | |
144 DispatchSSLVisibleStateChanged(); | |
145 } | |
146 | |
147 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { | 205 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { |
148 DCHECK(details); | 206 DCHECK(details); |
149 | 207 |
150 // Simulate loading this resource through the usual path. | 208 // Simulate loading this resource through the usual path. |
151 // Note that we specify SUB_RESOURCE as the resource type as WebCore only | 209 // Note that we specify SUB_RESOURCE as the resource type as WebCore only |
152 // caches sub-resources. | 210 // caches sub-resources. |
153 // This resource must have been loaded with FilterPolicy::DONT_FILTER because | 211 // This resource must have been loaded with FilterPolicy::DONT_FILTER because |
154 // filtered resouces aren't cachable. | 212 // filtered resouces aren't cachable. |
155 scoped_refptr<SSLRequestInfo> info = new SSLRequestInfo( | 213 scoped_refptr<SSLRequestInfo> info = new SSLRequestInfo( |
156 details->url(), | 214 details->url(), |
157 ResourceType::SUB_RESOURCE, | 215 ResourceType::SUB_RESOURCE, |
158 details->frame_origin(), | 216 details->frame_origin(), |
159 details->main_frame_origin(), | 217 details->main_frame_origin(), |
160 FilterPolicy::DONT_FILTER, | 218 FilterPolicy::DONT_FILTER, |
161 details->pid(), | 219 details->pid(), |
162 details->ssl_cert_id(), | 220 details->ssl_cert_id(), |
163 details->ssl_cert_status()); | 221 details->ssl_cert_status()); |
164 | 222 |
165 // Simulate loading this resource through the usual path. | 223 // Simulate loading this resource through the usual path. |
166 policy()->OnRequestStarted(info.get()); | 224 policy()->OnRequestStarted(info.get()); |
167 } | 225 } |
168 | 226 |
169 void SSLManager::DidCommitProvisionalLoad( | |
170 const NotificationDetails& in_details) { | |
171 NavigationController::LoadCommittedDetails* details = | |
172 Details<NavigationController::LoadCommittedDetails>(in_details).ptr(); | |
173 | |
174 NavigationEntry* entry = controller_->GetActiveEntry(); | |
175 | |
176 if (details->is_main_frame) { | |
177 if (entry) { | |
178 // Decode the security details. | |
179 int ssl_cert_id, ssl_cert_status, ssl_security_bits; | |
180 DeserializeSecurityInfo(details->serialized_security_info, | |
181 &ssl_cert_id, | |
182 &ssl_cert_status, | |
183 &ssl_security_bits); | |
184 | |
185 // We may not have an entry if this is a navigation to an initial blank | |
186 // page. Reset the SSL information and add the new data we have. | |
187 entry->ssl() = NavigationEntry::SSLStatus(); | |
188 entry->ssl().set_cert_id(ssl_cert_id); | |
189 entry->ssl().set_cert_status(ssl_cert_status); | |
190 entry->ssl().set_security_bits(ssl_security_bits); | |
191 } | |
192 backend_.ShowPendingMessages(); | |
193 } | |
194 | |
195 UpdateEntry(entry); | |
196 } | |
197 | |
198 void SSLManager::DidFailProvisionalLoadWithError( | 227 void SSLManager::DidFailProvisionalLoadWithError( |
199 ProvisionalLoadDetails* details) { | 228 ProvisionalLoadDetails* details) { |
200 DCHECK(details); | 229 DCHECK(details); |
201 | 230 |
202 // Ignore in-page navigations. | 231 // Ignore in-page navigations. |
203 if (details->in_page_navigation()) | 232 if (details->in_page_navigation()) |
204 return; | 233 return; |
205 | 234 |
206 if (details->main_frame()) | 235 if (details->main_frame()) |
207 backend_.ClearPendingMessages(); | 236 backend_.ClearPendingMessages(); |
(...skipping 23 matching lines...) Expand all Loading... |
231 // a non-HTTPS resource in the redirect chain, we want to | 260 // a non-HTTPS resource in the redirect chain, we want to |
232 // trigger mixed content, even if the redirect chain goes back | 261 // trigger mixed content, even if the redirect chain goes back |
233 // to HTTPS. This is because the network attacker can redirect | 262 // to HTTPS. This is because the network attacker can redirect |
234 // the HTTP request to https://attacker.com/payload.js. | 263 // the HTTP request to https://attacker.com/payload.js. |
235 } | 264 } |
236 | 265 |
237 void SSLManager::DidChangeSSLInternalState() { | 266 void SSLManager::DidChangeSSLInternalState() { |
238 UpdateEntry(controller_->GetActiveEntry()); | 267 UpdateEntry(controller_->GetActiveEntry()); |
239 } | 268 } |
240 | 269 |
241 // static | 270 void SSLManager::UpdateEntry(NavigationEntry* entry) { |
242 std::string SSLManager::SerializeSecurityInfo(int cert_id, | 271 // We don't always have a navigation entry to update, for example in the |
243 int cert_status, | 272 // case of the Web Inspector. |
244 int security_bits) { | 273 if (!entry) |
245 Pickle pickle; | 274 return; |
246 pickle.WriteInt(cert_id); | 275 |
247 pickle.WriteInt(cert_status); | 276 NavigationEntry::SSLStatus original_ssl_status = entry->ssl(); // Copy! |
248 pickle.WriteInt(security_bits); | 277 |
249 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); | 278 policy()->UpdateEntry(entry, controller_->tab_contents()); |
| 279 |
| 280 if (!entry->ssl().Equals(original_ssl_status)) { |
| 281 NotificationService::current()->Notify( |
| 282 NotificationType::SSL_VISIBLE_STATE_CHANGED, |
| 283 Source<NavigationController>(controller_), |
| 284 NotificationService::NoDetails()); |
| 285 } |
250 } | 286 } |
251 | |
252 // static | |
253 bool SSLManager::DeserializeSecurityInfo(const std::string& state, | |
254 int* cert_id, | |
255 int* cert_status, | |
256 int* security_bits) { | |
257 DCHECK(cert_id && cert_status && security_bits); | |
258 if (state.empty()) { | |
259 // No SSL used. | |
260 *cert_id = 0; | |
261 *cert_status = 0; | |
262 *security_bits = -1; | |
263 return false; | |
264 } | |
265 | |
266 Pickle pickle(state.data(), static_cast<int>(state.size())); | |
267 void * iter = NULL; | |
268 return pickle.ReadInt(&iter, cert_id) && | |
269 pickle.ReadInt(&iter, cert_status) && | |
270 pickle.ReadInt(&iter, security_bits); | |
271 } | |
272 | |
273 // static | |
274 std::wstring SSLManager::GetEVCertName(const net::X509Certificate& cert) { | |
275 // EV are required to have an organization name and country. | |
276 if (cert.subject().organization_names.empty() || | |
277 cert.subject().country_name.empty()) { | |
278 NOTREACHED(); | |
279 return std::wstring(); | |
280 } | |
281 | |
282 return l10n_util::GetStringF(IDS_SECURE_CONNECTION_EV, | |
283 UTF8ToWide(cert.subject().organization_names[0]), | |
284 UTF8ToWide(cert.subject().country_name)); | |
285 } | |
OLD | NEW |