Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: ios/web/net/crw_cert_verification_controller.mm

Issue 1357773002: WKWebView: Implemented recoverable SSL interstitials. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lock_coloring
Patch Set: Merged with origin/master Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #import "ios/web/net/crw_cert_verification_controller.h" 5 #import "ios/web/net/crw_cert_verification_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/mac/bind_objc_block.h" 8 #include "base/mac/bind_objc_block.h"
9 #import "base/memory/ref_counted.h" 9 #import "base/memory/ref_counted.h"
10 #import "base/memory/scoped_ptr.h" 10 #import "base/memory/scoped_ptr.h"
11 #include "base/strings/sys_string_conversions.h" 11 #include "base/strings/sys_string_conversions.h"
12 #include "base/threading/worker_pool.h" 12 #include "base/threading/worker_pool.h"
13 #include "ios/web/net/cert_verifier_block_adapter.h" 13 #include "ios/web/net/cert_verifier_block_adapter.h"
14 #include "ios/web/public/browser_state.h" 14 #include "ios/web/public/browser_state.h"
15 #include "ios/web/public/certificate_policy_cache.h"
15 #include "ios/web/public/web_thread.h" 16 #include "ios/web/public/web_thread.h"
16 #import "ios/web/web_state/wk_web_view_security_util.h" 17 #import "ios/web/web_state/wk_web_view_security_util.h"
17 #include "net/cert/cert_verify_result.h" 18 #include "net/cert/cert_verify_result.h"
18 #include "net/ssl/ssl_config_service.h" 19 #include "net/ssl/ssl_config_service.h"
19 #include "net/url_request/url_request_context.h" 20 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_context_getter.h" 21 #include "net/url_request/url_request_context_getter.h"
21 22
22 namespace { 23 namespace {
23 24
24 // This class takes ownership of block and releases it on UI thread, even if 25 // This class takes ownership of block and releases it on UI thread, even if
(...skipping 28 matching lines...) Expand all
53 web::WebThread::PostTask(web::WebThread::UI, FROM_HERE, 54 web::WebThread::PostTask(web::WebThread::UI, FROM_HERE,
54 base::Bind(&BlockHolder::ReleaseBlock, block_)); 55 base::Bind(&BlockHolder::ReleaseBlock, block_));
55 } 56 }
56 } 57 }
57 58
58 T block_; 59 T block_;
59 }; 60 };
60 61
61 } // namespace 62 } // namespace
62 63
64 using web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER;
65 using web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_NOT_ACCEPTED_BY_USER;
66
63 @interface CRWCertVerificationController () { 67 @interface CRWCertVerificationController () {
64 // Cert verification object which wraps |net::CertVerifier|. Must be created, 68 // Cert verification object which wraps |net::CertVerifier|. Must be created,
65 // used and destroyed on IO Thread. 69 // used and destroyed on IO Thread.
66 scoped_ptr<web::CertVerifierBlockAdapter> _certVerifier; 70 scoped_ptr<web::CertVerifierBlockAdapter> _certVerifier;
67 71
68 // URLRequestContextGetter for obtaining net layer objects. 72 // URLRequestContextGetter for obtaining net layer objects.
69 net::URLRequestContextGetter* _contextGetter; 73 net::URLRequestContextGetter* _contextGetter;
74
75 // Used to remember decisions about how to handle problematic certs.
76 scoped_refptr<web::CertificatePolicyCache> _certPolicyCache;
70 } 77 }
71 78
72 // Cert verification flags. Must be used on IO Thread. 79 // Cert verification flags. Must be used on IO Thread.
73 @property(nonatomic, readonly) int certVerifyFlags; 80 @property(nonatomic, readonly) int certVerifyFlags;
74 81
75 // Creates _certVerifier object on IO thread. 82 // Creates _certVerifier object on IO thread.
76 - (void)createCertVerifier; 83 - (void)createCertVerifier;
77 84
78 // Verifies the given |cert| for the given |host| using |net::CertVerifier| and 85 // Verifies the given |cert| for the given |host| using |net::CertVerifier| and
79 // calls |completionHandler| on completion. |completionHandler| cannot be null 86 // calls |completionHandler| on completion. |completionHandler| cannot be null
(...skipping 27 matching lines...) Expand all
107 return nil; 114 return nil;
108 } 115 }
109 116
110 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState { 117 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
111 DCHECK(browserState); 118 DCHECK(browserState);
112 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); 119 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
113 self = [super init]; 120 self = [super init];
114 if (self) { 121 if (self) {
115 _contextGetter = browserState->GetRequestContext(); 122 _contextGetter = browserState->GetRequestContext();
116 DCHECK(_contextGetter); 123 DCHECK(_contextGetter);
124 _certPolicyCache =
125 web::BrowserState::GetCertificatePolicyCache(browserState);
126
117 [self createCertVerifier]; 127 [self createCertVerifier];
118 } 128 }
119 return self; 129 return self;
120 } 130 }
121 131
122 - (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert 132 - (void)decideLoadPolicyForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
123 host:(NSString*)host 133 host:(NSString*)host
124 completionHandler:(web::PolicyDecisionHandler)completionHandler { 134 completionHandler:(web::PolicyDecisionHandler)completionHandler {
125 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); 135 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
126 // completionHandler of |verifyCert:forHost:completionHandler:| is called on 136 // completionHandler of |verifyCert:forHost:completionHandler:| is called on
127 // IO thread and then bounces back to UI thread. As a result all objects 137 // IO thread and then bounces back to UI thread. As a result all objects
128 // captured by completionHandler may be released on either UI or IO thread. 138 // captured by completionHandler may be released on either UI or IO thread.
129 // Since |completionHandler| can potentially capture multiple thread unsafe 139 // Since |completionHandler| can potentially capture multiple thread unsafe
130 // objects (like Web Controller) |completionHandler| itself should never be 140 // objects (like Web Controller) |completionHandler| itself should never be
131 // released on background thread and |BlockHolder| ensures that. 141 // released on background thread and |BlockHolder| ensures that.
132 __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder( 142 __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder(
133 new BlockHolder<web::PolicyDecisionHandler>(completionHandler)); 143 new BlockHolder<web::PolicyDecisionHandler>(completionHandler));
134 [self verifyCert:cert 144 [self verifyTrust:trust completionHandler:^(SecTrustResultType trustResult) {
135 forHost:host 145 if (web::GetSecurityStyleFromTrustResult(trustResult) ==
136 completionHandler:^(net::CertVerifyResult result, int error) { 146 web::SECURITY_STYLE_AUTHENTICATED) {
137 web::CertAcceptPolicy policy = 147 // SecTrust API considers this cert as valid.
138 web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; 148 dispatch_async(dispatch_get_main_queue(), ^{
139 if (error == net::OK) { 149 handlerHolder->call(web::CERT_ACCEPT_POLICY_ALLOW, net::CertStatus());
140 policy = web::CERT_ACCEPT_POLICY_ALLOW; 150 });
141 } else if (net::IsCertStatusError(result.cert_status)) { 151 return;
142 policy = net::IsCertStatusMinorError(result.cert_status) 152 }
143 ? web::CERT_ACCEPT_POLICY_ALLOW
144 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR;
145 }
146 153
147 dispatch_async(dispatch_get_main_queue(), ^{ 154 // SecTrust API considers this cert as invalid. Check the reason and
148 handlerHolder->call(policy, result.cert_status); 155 // whether or not user has decided to proceed with this bad cert.
149 }); 156 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust));
150 }]; 157 [self verifyCert:cert
158 forHost:host
159 completionHandler:^(net::CertVerifyResult certVerifierResult, int) {
160 web::CertAcceptPolicy policy =
161 web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR;
162 if (trustResult == kSecTrustResultRecoverableTrustFailure &&
163 SecTrustGetCertificateCount(trust)) {
164 // Check if user has decided to proceed with this bad cert.
165 scoped_refptr<net::X509Certificate> leafCert =
stuartmorgan 2015/10/08 16:52:39 Fix the indentation of this statement. (Is this a
Eugene But (OOO till 7-30) 2015/10/09 16:32:36 Fixed. This probably was not clang format bug.
166 web::CreateCertFromChain(@[
167 static_cast<id>(SecTrustGetCertificateAtIndex(trust, 0))
168 ]);
169
170 web::CertPolicy::Judgment judgment =
171 _certPolicyCache->QueryPolicy(
172 leafCert.get(), base::SysNSStringToUTF8(host),
173 certVerifierResult.cert_status);
174
175 policy =
176 (judgment == web::CertPolicy::ALLOWED)
177 ? CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER
178 : CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_NOT_ACCEPTED_BY_USER;
179 }
180
181 dispatch_async(dispatch_get_main_queue(), ^{
182 handlerHolder->call(policy, certVerifierResult.cert_status);
183 });
184 }];
185 }];
151 } 186 }
152 187
153 - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 188 - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
154 host:(NSString*)host 189 host:(NSString*)host
155 completionHandler:(web::StatusQueryHandler)completionHandler { 190 completionHandler:(web::StatusQueryHandler)completionHandler {
156 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); 191 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
157 192
158 // The completion handlers of |verifyCert:forHost:completionHandler:| and 193 // The completion handlers of |verifyCert:forHost:completionHandler:| and
159 // |verifyTrust:completionHandler:| will be deallocated on background thread. 194 // |verifyTrust:completionHandler:| will be deallocated on background thread.
160 // |completionHandler| itself should never be released on background thread 195 // |completionHandler| itself should never be released on background thread
(...skipping 26 matching lines...) Expand all
187 forHost:host 222 forHost:host
188 completionHandler:^(net::CertVerifyResult certVerifierResult, int) { 223 completionHandler:^(net::CertVerifyResult certVerifierResult, int) {
189 dispatch_async(dispatch_get_main_queue(), ^{ 224 dispatch_async(dispatch_get_main_queue(), ^{
190 handlerHolder->call(securityStyle, 225 handlerHolder->call(securityStyle,
191 certVerifierResult.cert_status); 226 certVerifierResult.cert_status);
192 }); 227 });
193 }]; 228 }];
194 }]; 229 }];
195 } 230 }
196 231
232 - (void)allowCert:(scoped_refptr<net::X509Certificate>)cert
233 forHost:(NSString*)host
234 status:(net::CertStatus)status {
235 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
236 // Store user decision only for leaf server cert, and drop any intermediates.
237 // This is a workaround for WKWebView behavior, where different delegate
238 // methods receive different certificate chains for the same server cert.
239 if (cert->GetIntermediateCertificates().size() > 0) {
240 cert = net::X509Certificate::CreateFromHandle(
241 cert->os_cert_handle(), net::X509Certificate::OSCertHandles());
242 }
243 DCHECK_EQ(0U, cert->GetIntermediateCertificates().size());
244 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
245 _certPolicyCache->AllowCertForHost(
246 cert.get(), base::SysNSStringToUTF8(host), status);
247 }));
248 }
249
197 - (void)shutDown { 250 - (void)shutDown {
198 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); 251 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
199 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ 252 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
200 // This block captures |self| delaying its deallocation and causing dealloc 253 // This block captures |self| delaying its deallocation and causing dealloc
201 // to happen on either IO or UI thread (which is fine for this class). 254 // to happen on either IO or UI thread (which is fine for this class).
202 _certVerifier.reset(); 255 _certVerifier.reset();
203 })); 256 }));
204 } 257 }
205 258
206 #pragma mark - Private 259 #pragma mark - Private
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 315 }
263 completionHandler(trustResult, YES); 316 completionHandler(trustResult, YES);
264 }), false /* task_is_slow */); 317 }), false /* task_is_slow */);
265 318
266 if (!result) { 319 if (!result) {
267 completionHandler(kSecTrustResultInvalid, NO); 320 completionHandler(kSecTrustResultInvalid, NO);
268 } 321 }
269 } 322 }
270 323
271 @end 324 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698