OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |