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 "ios/web/net/cert_verifier_block_adapter.h" | 13 #include "ios/web/net/cert_verifier_block_adapter.h" |
| 13 #include "ios/web/public/browser_state.h" | 14 #include "ios/web/public/browser_state.h" |
| 14 #include "ios/web/public/web_thread.h" | 15 #include "ios/web/public/web_thread.h" |
| 16 #import "ios/web/web_state/wk_web_view_security_util.h" | |
| 15 #include "net/cert/cert_verify_result.h" | 17 #include "net/cert/cert_verify_result.h" |
| 16 #include "net/ssl/ssl_config_service.h" | 18 #include "net/ssl/ssl_config_service.h" |
| 17 #include "net/url_request/url_request_context.h" | 19 #include "net/url_request/url_request_context.h" |
| 18 #include "net/url_request/url_request_context_getter.h" | 20 #include "net/url_request/url_request_context_getter.h" |
| 19 | 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 // This class takes ownership of block and releases it on UI thread, even if | 24 // This class takes ownership of block and releases it on UI thread, even if |
| 23 // |BlockHolder| is destructed on a background thread. | 25 // |BlockHolder| is destructed on a background thread. |
| 24 template <class T> | 26 template <class T> |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 // URLRequestContextGetter for obtaining net layer objects. | 68 // URLRequestContextGetter for obtaining net layer objects. |
| 67 net::URLRequestContextGetter* _contextGetter; | 69 net::URLRequestContextGetter* _contextGetter; |
| 68 } | 70 } |
| 69 | 71 |
| 70 // Cert verification flags. Must be used on IO Thread. | 72 // Cert verification flags. Must be used on IO Thread. |
| 71 @property(nonatomic, readonly) int certVerifyFlags; | 73 @property(nonatomic, readonly) int certVerifyFlags; |
| 72 | 74 |
| 73 // Creates _certVerifier object on IO thread. | 75 // Creates _certVerifier object on IO thread. |
| 74 - (void)createCertVerifier; | 76 - (void)createCertVerifier; |
| 75 | 77 |
| 76 // Verifies the given |cert| for the given |host| and calls |completionHandler| | 78 // Verifies the given |cert| for the given |host| using |net::CertVerifier| and |
| 77 // on completion. |completionHandler| cannot be null and will be called | 79 // calls |completionHandler| on completion. |completionHandler| cannot be null |
| 78 // synchronously or asynchronously on IO thread. | 80 // and will be called asynchronously on IO thread. |
| 79 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert | 81 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert |
| 80 forHost:(NSString*)host | 82 forHost:(NSString*)host |
| 81 completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler; | 83 completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler; |
| 82 | 84 |
| 85 // Verifies the given |trust| using SecTrustRef API. Must be called on IO | |
| 86 // thread. |completionHandler| cannot be null and will be called asynchronously | |
| 87 // on IO thread. | |
| 88 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust | |
| 89 completionHandler:(void (^)(SecTrustResultType))completionHandler; | |
| 90 | |
| 83 @end | 91 @end |
| 84 | 92 |
| 85 @implementation CRWCertVerificationController | 93 @implementation CRWCertVerificationController |
| 86 | 94 |
| 87 #pragma mark - Superclass | 95 #pragma mark - Superclass |
| 88 | 96 |
| 89 - (void)dealloc { | 97 - (void)dealloc { |
| 90 DCHECK(!_certVerifier); | 98 DCHECK(!_certVerifier); |
| 91 [super dealloc]; | 99 [super dealloc]; |
| 92 } | 100 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 105 if (self) { | 113 if (self) { |
| 106 _contextGetter = browserState->GetRequestContext(); | 114 _contextGetter = browserState->GetRequestContext(); |
| 107 DCHECK(_contextGetter); | 115 DCHECK(_contextGetter); |
| 108 [self createCertVerifier]; | 116 [self createCertVerifier]; |
| 109 } | 117 } |
| 110 return self; | 118 return self; |
| 111 } | 119 } |
| 112 | 120 |
| 113 - (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert | 121 - (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert |
| 114 host:(NSString*)host | 122 host:(NSString*)host |
| 115 completionHandler:(web::PolicyDecisionHandler)handler { | 123 completionHandler:(web::PolicyDecisionHandler)completionHandler { |
| 116 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 124 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
| 117 // completionHandler of |verifyCert:forHost:completionHandler:| is called on | 125 // completionHandler of |verifyCert:forHost:completionHandler:| is called on |
| 118 // IO thread and then bounces back to UI thread. As a result all objects | 126 // IO thread and then bounces back to UI thread. As a result all objects |
| 119 // captured by completionHandler may be released on either UI or IO thread. | 127 // captured by completionHandler may be released on either UI or IO thread. |
| 120 // Since |handler| can potentially capture multiple thread unsafe objects | 128 // Since |completionHandler| can potentially capture multiple thread unsafe |
| 121 // (like Web Controller) |handler| itself should never be released on | 129 // objects (like Web Controller) |completionHandler| itself should never be |
| 122 // background thread and |BlockHolder| ensures that. | 130 // released on background thread and |BlockHolder| ensures that. |
| 123 __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder( | 131 __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder( |
| 124 new BlockHolder<web::PolicyDecisionHandler>(handler)); | 132 new BlockHolder<web::PolicyDecisionHandler>(completionHandler)); |
| 125 [self verifyCert:cert | 133 [self verifyCert:cert |
| 126 forHost:host | 134 forHost:host |
| 127 completionHandler:^(net::CertVerifyResult result, int error) { | 135 completionHandler:^(net::CertVerifyResult result, int error) { |
| 128 web::CertAcceptPolicy policy = | 136 web::CertAcceptPolicy policy = |
| 129 web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; | 137 web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; |
| 130 if (error == net::OK) { | 138 if (error == net::OK) { |
| 131 policy = web::CERT_ACCEPT_POLICY_ALLOW; | 139 policy = web::CERT_ACCEPT_POLICY_ALLOW; |
| 132 } else if (net::IsCertStatusError(result.cert_status)) { | 140 } else if (net::IsCertStatusError(result.cert_status)) { |
| 133 policy = net::IsCertStatusMinorError(result.cert_status) | 141 policy = net::IsCertStatusMinorError(result.cert_status) |
| 134 ? web::CERT_ACCEPT_POLICY_ALLOW | 142 ? web::CERT_ACCEPT_POLICY_ALLOW |
| 135 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR; | 143 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR; |
| 136 } | 144 } |
| 137 | 145 |
| 138 dispatch_async(dispatch_get_main_queue(), ^{ | 146 dispatch_async(dispatch_get_main_queue(), ^{ |
| 139 handlerHolder->call(policy, result.cert_status); | 147 handlerHolder->call(policy, result.cert_status); |
| 140 }); | 148 }); |
| 141 }]; | 149 }]; |
| 142 } | 150 } |
| 143 | 151 |
| 152 - (void)querySSLStatusForCertChain:(NSArray*)certChain | |
| 153 host:(NSString*)host | |
| 154 completionHandler:(web::StatusQueryHandler)completionHandler { | |
| 155 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | |
| 156 DCHECK(certChain.count); | |
| 157 | |
| 158 // Completion handler of |verifyCert:forHost:completionHandler:| will be | |
| 159 // deallocated on IO thread. |completionHandler| itself should never be | |
| 160 // released on background thread and |BlockHolder| ensures that. | |
| 161 __block scoped_refptr<BlockHolder<web::StatusQueryHandler>> handlerHolder( | |
| 162 new BlockHolder<web::StatusQueryHandler>(completionHandler)); | |
| 163 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(certChain)); | |
|
Ryan Sleevi
2015/09/24 22:25:32
DANGER: What about when this conversion fails? It
Eugene But (OOO till 7-30)
2015/09/25 00:28:10
If cert is null then CertVerifier responds with er
| |
| 164 // Retrieve the net::CertStatus to allow Chromium-specific policies to be | |
| 165 // enacted. This is called for all certificates (valid and invalid alike), | |
|
Ryan Sleevi
2015/09/24 22:45:31
Aren't we "not supposed to end up here", per https
Eugene But (OOO till 7-30)
2015/09/25 00:28:10
Seem to be fine. Please see:
- "For computing loc
| |
| 166 // since the net::CertVerifier may reject or downgrade certificates that | |
| 167 // SecTrust accepts. | |
|
Ryan Sleevi
2015/09/24 22:25:32
I realize you copied both comments from me, but it
Eugene But (OOO till 7-30)
2015/09/25 00:28:10
Updated the comments. Please let me know if someth
| |
| 168 [self verifyCert:cert | |
| 169 forHost:host | |
| 170 completionHandler:^(net::CertVerifyResult certVerifierResult, int) { | |
| 171 [self verifyTrust:web::CreateServerTrustFromChain(certChain, host) | |
| 172 completionHandler:^(SecTrustResultType trustResult) { | |
| 173 // If SecTrust has accepted a certificate, clear any error | |
| 174 // statuses returned by net::CertVerifier, since the CertVerifier | |
| 175 // may not have access to the same trust information | |
| 176 // (e.g. custom-installed roots). Note, this also disables | |
| 177 // net::CertVerifier's ability to reject certificates, such as via | |
| 178 // CRLSets. However, copy any supplemental status bits over, since | |
| 179 // those may be used as part of policy logic, such as deprecating | |
| 180 // SHA-1 or requiring Certificate Transparency. | |
|
Ryan Sleevi
2015/09/24 22:25:32
I'm still having trouble reconciling whether or no
Eugene But (OOO till 7-30)
2015/09/25 00:28:10
This code uses the same chain for constructing Sec
Ryan Sleevi
2015/09/25 01:05:06
Yes, that was the point I was trying to clarify -
Eugene But (OOO till 7-30)
2015/09/25 17:03:10
ðŸ˜
Eugene But (OOO till 7-30)
2015/10/02 15:57:47
Per discussion with felt@ we will not use CertVeri
| |
| 181 web::SecurityStyle security_style = | |
| 182 web::GetSecurityStyleFromTrustResult(trustResult); | |
| 183 net::CertStatus cert_status = certVerifierResult.cert_status; | |
| 184 if (security_style == web::SECURITY_STYLE_AUTHENTICATED) { | |
| 185 cert_status &= ~net::CERT_STATUS_ALL_ERRORS; | |
| 186 } | |
| 187 | |
| 188 dispatch_async(dispatch_get_main_queue(), ^{ | |
| 189 handlerHolder->call(security_style, cert_status); | |
| 190 }); | |
| 191 }]; | |
| 192 }]; | |
| 193 } | |
| 194 | |
| 144 - (void)shutDown { | 195 - (void)shutDown { |
| 145 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 196 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
| 146 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ | 197 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
| 147 // This block captures |self| delaying its deallocation and causing dealloc | 198 // This block captures |self| delaying its deallocation and causing dealloc |
| 148 // to happen on either IO or UI thread (which is fine for this class). | 199 // to happen on either IO or UI thread (which is fine for this class). |
| 149 _certVerifier.reset(); | 200 _certVerifier.reset(); |
| 150 })); | 201 })); |
| 151 } | 202 } |
| 152 | 203 |
| 153 #pragma mark - Private | 204 #pragma mark - Private |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 | 241 |
| 191 web::CertVerifierBlockAdapter::Params params( | 242 web::CertVerifierBlockAdapter::Params params( |
| 192 blockCert.Pass(), base::SysNSStringToUTF8(host)); | 243 blockCert.Pass(), base::SysNSStringToUTF8(host)); |
| 193 params.flags = self.certVerifyFlags; | 244 params.flags = self.certVerifyFlags; |
| 194 params.crl_set = net::SSLConfigService::GetCRLSet(); | 245 params.crl_set = net::SSLConfigService::GetCRLSet(); |
| 195 // OCSP response is not provided by iOS API. | 246 // OCSP response is not provided by iOS API. |
| 196 _certVerifier->Verify(params, completionHandler); | 247 _certVerifier->Verify(params, completionHandler); |
| 197 })); | 248 })); |
| 198 } | 249 } |
| 199 | 250 |
| 251 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust | |
| 252 completionHandler:(void (^)(SecTrustResultType))completionHandler { | |
| 253 DCHECK(web::WebThread::CurrentlyOn(web::WebThread::IO)); | |
| 254 DCHECK(completionHandler); | |
| 255 // SecTrustEvaluate performs trust evaluation synchronously, possibly making | |
| 256 // betwork requests. IO thread should not be blocked by that operation. | |
| 257 bool result = base::WorkerPool::PostTask(FROM_HERE, base::BindBlock(^{ | |
| 258 SecTrustResultType trustResult = kSecTrustResultInvalid; | |
| 259 if (SecTrustEvaluate(trust.get(), &trustResult) != errSecSuccess) { | |
| 260 trustResult = kSecTrustResultInvalid; | |
| 261 } | |
| 262 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE,base::BindBlock(^{ | |
| 263 completionHandler(trustResult); | |
| 264 })); | |
| 265 }), false /* task_is_slow */); | |
| 266 | |
| 267 if (!result) { | |
| 268 completionHandler(kSecTrustResultInvalid); | |
| 269 } | |
| 270 } | |
| 271 | |
| 200 @end | 272 @end |
| OLD | NEW |