Chromium Code Reviews| 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 |