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 | |
111 SSLManager::SSLManager(NavigationController* controller) | 31 SSLManager::SSLManager(NavigationController* controller) |
112 : backend_(controller), | 32 : backend_(controller), |
113 policy_(new SSLPolicy(&backend_)), | 33 policy_(new SSLPolicy(&backend_)), |
114 controller_(controller) { | 34 controller_(controller) { |
115 DCHECK(controller_); | 35 DCHECK(controller_); |
116 | 36 |
117 // Subscribe to various notifications. | 37 // Subscribe to various notifications. |
118 registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, | 38 registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, |
119 Source<NavigationController>(controller_)); | 39 Source<NavigationController>(controller_)); |
120 registrar_.Add(this, NotificationType::RESOURCE_RESPONSE_STARTED, | 40 registrar_.Add(this, NotificationType::RESOURCE_RESPONSE_STARTED, |
121 Source<NavigationController>(controller_)); | 41 Source<NavigationController>(controller_)); |
122 registrar_.Add(this, NotificationType::RESOURCE_RECEIVED_REDIRECT, | 42 registrar_.Add(this, NotificationType::RESOURCE_RECEIVED_REDIRECT, |
123 Source<NavigationController>(controller_)); | 43 Source<NavigationController>(controller_)); |
124 registrar_.Add(this, NotificationType::LOAD_FROM_MEMORY_CACHE, | 44 registrar_.Add(this, NotificationType::LOAD_FROM_MEMORY_CACHE, |
125 Source<NavigationController>(controller_)); | 45 Source<NavigationController>(controller_)); |
126 registrar_.Add(this, NotificationType::SSL_INTERNAL_STATE_CHANGED, | 46 registrar_.Add(this, NotificationType::SSL_INTERNAL_STATE_CHANGED, |
127 NotificationService::AllSources()); | 47 NotificationService::AllSources()); |
128 } | 48 } |
129 | 49 |
130 SSLManager::~SSLManager() { | 50 SSLManager::~SSLManager() { |
131 } | 51 } |
132 | 52 |
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 | |
167 bool SSLManager::ProcessedSSLErrorFromRequest() const { | 53 bool SSLManager::ProcessedSSLErrorFromRequest() const { |
168 NavigationEntry* entry = controller_->GetActiveEntry(); | 54 NavigationEntry* entry = controller_->GetActiveEntry(); |
169 if (!entry) { | 55 if (!entry) { |
170 NOTREACHED(); | 56 NOTREACHED(); |
171 return false; | 57 return false; |
172 } | 58 } |
173 | 59 |
174 return net::IsCertStatusError(entry->ssl().cert_status()); | 60 return net::IsCertStatusError(entry->ssl().cert_status()); |
175 } | 61 } |
176 | 62 |
| 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 |
177 void SSLManager::Observe(NotificationType type, | 98 void SSLManager::Observe(NotificationType type, |
178 const NotificationSource& source, | 99 const NotificationSource& source, |
179 const NotificationDetails& details) { | 100 const NotificationDetails& details) { |
180 // Dispatch by type. | 101 // Dispatch by type. |
181 switch (type.value) { | 102 switch (type.value) { |
182 case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: | 103 case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: |
183 DidFailProvisionalLoadWithError( | 104 DidFailProvisionalLoadWithError( |
184 Details<ProvisionalLoadDetails>(details).ptr()); | 105 Details<ProvisionalLoadDetails>(details).ptr()); |
185 break; | 106 break; |
186 case NotificationType::RESOURCE_RESPONSE_STARTED: | 107 case NotificationType::RESOURCE_RESPONSE_STARTED: |
187 DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr()); | 108 DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr()); |
188 break; | 109 break; |
189 case NotificationType::RESOURCE_RECEIVED_REDIRECT: | 110 case NotificationType::RESOURCE_RECEIVED_REDIRECT: |
190 DidReceiveResourceRedirect( | 111 DidReceiveResourceRedirect( |
191 Details<ResourceRedirectDetails>(details).ptr()); | 112 Details<ResourceRedirectDetails>(details).ptr()); |
192 break; | 113 break; |
193 case NotificationType::LOAD_FROM_MEMORY_CACHE: | 114 case NotificationType::LOAD_FROM_MEMORY_CACHE: |
194 DidLoadFromMemoryCache( | 115 DidLoadFromMemoryCache( |
195 Details<LoadFromMemoryCacheDetails>(details).ptr()); | 116 Details<LoadFromMemoryCacheDetails>(details).ptr()); |
196 break; | 117 break; |
197 case NotificationType::SSL_INTERNAL_STATE_CHANGED: | 118 case NotificationType::SSL_INTERNAL_STATE_CHANGED: |
198 DidChangeSSLInternalState(); | 119 DidChangeSSLInternalState(); |
199 break; | 120 break; |
200 default: | 121 default: |
201 NOTREACHED() << "The SSLManager received an unexpected notification."; | 122 NOTREACHED() << "The SSLManager received an unexpected notification."; |
202 } | 123 } |
203 } | 124 } |
204 | 125 |
| 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 |
205 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { | 147 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { |
206 DCHECK(details); | 148 DCHECK(details); |
207 | 149 |
208 // Simulate loading this resource through the usual path. | 150 // Simulate loading this resource through the usual path. |
209 // Note that we specify SUB_RESOURCE as the resource type as WebCore only | 151 // Note that we specify SUB_RESOURCE as the resource type as WebCore only |
210 // caches sub-resources. | 152 // caches sub-resources. |
211 // This resource must have been loaded with FilterPolicy::DONT_FILTER because | 153 // This resource must have been loaded with FilterPolicy::DONT_FILTER because |
212 // filtered resouces aren't cachable. | 154 // filtered resouces aren't cachable. |
213 scoped_refptr<SSLRequestInfo> info = new SSLRequestInfo( | 155 scoped_refptr<SSLRequestInfo> info = new SSLRequestInfo( |
214 details->url(), | 156 details->url(), |
215 ResourceType::SUB_RESOURCE, | 157 ResourceType::SUB_RESOURCE, |
216 details->frame_origin(), | 158 details->frame_origin(), |
217 details->main_frame_origin(), | 159 details->main_frame_origin(), |
218 FilterPolicy::DONT_FILTER, | 160 FilterPolicy::DONT_FILTER, |
219 details->pid(), | 161 details->pid(), |
220 details->ssl_cert_id(), | 162 details->ssl_cert_id(), |
221 details->ssl_cert_status()); | 163 details->ssl_cert_status()); |
222 | 164 |
223 // Simulate loading this resource through the usual path. | 165 // Simulate loading this resource through the usual path. |
224 policy()->OnRequestStarted(info.get()); | 166 policy()->OnRequestStarted(info.get()); |
225 } | 167 } |
226 | 168 |
| 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 |
227 void SSLManager::DidFailProvisionalLoadWithError( | 198 void SSLManager::DidFailProvisionalLoadWithError( |
228 ProvisionalLoadDetails* details) { | 199 ProvisionalLoadDetails* details) { |
229 DCHECK(details); | 200 DCHECK(details); |
230 | 201 |
231 // Ignore in-page navigations. | 202 // Ignore in-page navigations. |
232 if (details->in_page_navigation()) | 203 if (details->in_page_navigation()) |
233 return; | 204 return; |
234 | 205 |
235 if (details->main_frame()) | 206 if (details->main_frame()) |
236 backend_.ClearPendingMessages(); | 207 backend_.ClearPendingMessages(); |
(...skipping 23 matching lines...) Expand all Loading... |
260 // a non-HTTPS resource in the redirect chain, we want to | 231 // a non-HTTPS resource in the redirect chain, we want to |
261 // trigger mixed content, even if the redirect chain goes back | 232 // trigger mixed content, even if the redirect chain goes back |
262 // to HTTPS. This is because the network attacker can redirect | 233 // to HTTPS. This is because the network attacker can redirect |
263 // the HTTP request to https://attacker.com/payload.js. | 234 // the HTTP request to https://attacker.com/payload.js. |
264 } | 235 } |
265 | 236 |
266 void SSLManager::DidChangeSSLInternalState() { | 237 void SSLManager::DidChangeSSLInternalState() { |
267 UpdateEntry(controller_->GetActiveEntry()); | 238 UpdateEntry(controller_->GetActiveEntry()); |
268 } | 239 } |
269 | 240 |
270 void SSLManager::UpdateEntry(NavigationEntry* entry) { | 241 // static |
271 // We don't always have a navigation entry to update, for example in the | 242 std::string SSLManager::SerializeSecurityInfo(int cert_id, |
272 // case of the Web Inspector. | 243 int cert_status, |
273 if (!entry) | 244 int security_bits) { |
274 return; | 245 Pickle pickle; |
| 246 pickle.WriteInt(cert_id); |
| 247 pickle.WriteInt(cert_status); |
| 248 pickle.WriteInt(security_bits); |
| 249 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); |
| 250 } |
275 | 251 |
276 NavigationEntry::SSLStatus original_ssl_status = entry->ssl(); // Copy! | 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 } |
277 | 265 |
278 policy()->UpdateEntry(entry, controller_->tab_contents()); | 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 } |
279 | 272 |
280 if (!entry->ssl().Equals(original_ssl_status)) { | 273 // static |
281 NotificationService::current()->Notify( | 274 std::wstring SSLManager::GetEVCertName(const net::X509Certificate& cert) { |
282 NotificationType::SSL_VISIBLE_STATE_CHANGED, | 275 // EV are required to have an organization name and country. |
283 Source<NavigationController>(controller_), | 276 if (cert.subject().organization_names.empty() || |
284 NotificationService::NoDetails()); | 277 cert.subject().country_name.empty()) { |
| 278 NOTREACHED(); |
| 279 return std::wstring(); |
285 } | 280 } |
| 281 |
| 282 return l10n_util::GetStringF(IDS_SECURE_CONNECTION_EV, |
| 283 UTF8ToWide(cert.subject().organization_names[0]), |
| 284 UTF8ToWide(cert.subject().country_name)); |
286 } | 285 } |
OLD | NEW |