Chromium Code Reviews| Index: ios/web/net/crw_cert_verification_controller.mm |
| diff --git a/ios/web/net/crw_cert_verification_controller.mm b/ios/web/net/crw_cert_verification_controller.mm |
| index 6c0dd0beb4b8a5be59d34a9928ec5e056ed6af91..55a34c1127bfeb938941194bc732332b7416e0d9 100644 |
| --- a/ios/web/net/crw_cert_verification_controller.mm |
| +++ b/ios/web/net/crw_cert_verification_controller.mm |
| @@ -12,6 +12,7 @@ |
| #include "base/threading/worker_pool.h" |
| #include "ios/web/net/cert_verifier_block_adapter.h" |
| #include "ios/web/public/browser_state.h" |
| +#include "ios/web/public/certificate_policy_cache.h" |
| #include "ios/web/public/web_thread.h" |
| #import "ios/web/web_state/wk_web_view_security_util.h" |
| #include "net/cert/cert_verify_result.h" |
| @@ -60,6 +61,9 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
| } // namespace |
| +using web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER; |
| +using web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_NOT_ACCEPTED_BY_USER; |
| + |
| @interface CRWCertVerificationController () { |
| // Cert verification object which wraps |net::CertVerifier|. Must be created, |
| // used and destroyed on IO Thread. |
| @@ -67,6 +71,9 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
| // URLRequestContextGetter for obtaining net layer objects. |
| net::URLRequestContextGetter* _contextGetter; |
| + |
| + // Used to remember decisions about how to handle problematic certs. |
| + scoped_refptr<web::CertificatePolicyCache> _certPolicyCache; |
| } |
| // Cert verification flags. Must be used on IO Thread. |
| @@ -114,14 +121,17 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
| if (self) { |
| _contextGetter = browserState->GetRequestContext(); |
| DCHECK(_contextGetter); |
| + _certPolicyCache = |
| + web::BrowserState::GetCertificatePolicyCache(browserState); |
| + |
| [self createCertVerifier]; |
| } |
| return self; |
| } |
| -- (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert |
| - host:(NSString*)host |
| - completionHandler:(web::PolicyDecisionHandler)completionHandler { |
| +- (void)decideLoadPolicyForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust |
| + host:(NSString*)host |
| + completionHandler:(web::PolicyDecisionHandler)completionHandler { |
| DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
| // completionHandler of |verifyCert:forHost:completionHandler:| is called on |
| // IO thread and then bounces back to UI thread. As a result all objects |
| @@ -131,23 +141,48 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
| // released on background thread and |BlockHolder| ensures that. |
| __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder( |
| new BlockHolder<web::PolicyDecisionHandler>(completionHandler)); |
| - [self verifyCert:cert |
| - forHost:host |
| - completionHandler:^(net::CertVerifyResult result, int error) { |
| - web::CertAcceptPolicy policy = |
| - web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; |
| - if (error == net::OK) { |
| - policy = web::CERT_ACCEPT_POLICY_ALLOW; |
| - } else if (net::IsCertStatusError(result.cert_status)) { |
| - policy = net::IsCertStatusMinorError(result.cert_status) |
| - ? web::CERT_ACCEPT_POLICY_ALLOW |
| - : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR; |
| - } |
| + [self verifyTrust:trust completionHandler:^(SecTrustResultType trustResult) { |
| + if (web::GetSecurityStyleFromTrustResult(trustResult) == |
| + web::SECURITY_STYLE_AUTHENTICATED) { |
| + // SecTrust API considers this cert as valid. |
| + dispatch_async(dispatch_get_main_queue(), ^{ |
| + handlerHolder->call(web::CERT_ACCEPT_POLICY_ALLOW, net::CertStatus()); |
| + }); |
| + return; |
| + } |
| - dispatch_async(dispatch_get_main_queue(), ^{ |
| - handlerHolder->call(policy, result.cert_status); |
| - }); |
| - }]; |
| + // SecTrust API considers this cert as invalid. Check the reason and |
| + // whether or not user has decided to proceed with this bad cert. |
| + scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust)); |
| + [self verifyCert:cert |
| + forHost:host |
| + completionHandler:^(net::CertVerifyResult certVerifierResult, int) { |
| + web::CertAcceptPolicy policy = |
| + web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; |
| + if (trustResult == kSecTrustResultRecoverableTrustFailure && |
| + SecTrustGetCertificateCount(trust)) { |
| + // Check if user has decided to proceed with this bad cert. |
| + 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.
|
| + web::CreateCertFromChain(@[ |
| + static_cast<id>(SecTrustGetCertificateAtIndex(trust, 0)) |
| + ]); |
| + |
| + web::CertPolicy::Judgment judgment = |
| + _certPolicyCache->QueryPolicy( |
| + leafCert.get(), base::SysNSStringToUTF8(host), |
| + certVerifierResult.cert_status); |
| + |
| + policy = |
| + (judgment == web::CertPolicy::ALLOWED) |
| + ? CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER |
| + : CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_NOT_ACCEPTED_BY_USER; |
| + } |
| + |
| + dispatch_async(dispatch_get_main_queue(), ^{ |
| + handlerHolder->call(policy, certVerifierResult.cert_status); |
| + }); |
| + }]; |
| + }]; |
| } |
| - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust |
| @@ -194,6 +229,24 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
| }]; |
| } |
| +- (void)allowCert:(scoped_refptr<net::X509Certificate>)cert |
| + forHost:(NSString*)host |
| + status:(net::CertStatus)status { |
| + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
| + // Store user decision only for leaf server cert, and drop any intermediates. |
| + // This is a workaround for WKWebView behavior, where different delegate |
| + // methods receive different certificate chains for the same server cert. |
| + if (cert->GetIntermediateCertificates().size() > 0) { |
| + cert = net::X509Certificate::CreateFromHandle( |
| + cert->os_cert_handle(), net::X509Certificate::OSCertHandles()); |
| + } |
| + DCHECK_EQ(0U, cert->GetIntermediateCertificates().size()); |
| + web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
| + _certPolicyCache->AllowCertForHost( |
| + cert.get(), base::SysNSStringToUTF8(host), status); |
| + })); |
| +} |
| + |
| - (void)shutDown { |
| DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
| web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |