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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a2878746b28d159b8d0c5fa2640fa3e1a6c236c4 |
--- /dev/null |
+++ b/ios/web/net/crw_cert_verification_controller.mm |
@@ -0,0 +1,144 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/web/net/crw_cert_verification_controller.h" |
+ |
+#include "base/mac/bind_objc_block.h" |
+#import "base/memory/scoped_ptr.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "ios/web/net/cert_verifier_block_adapter.h" |
+#include "ios/web/public/browser_state.h" |
+#include "ios/web/public/web_thread.h" |
+#include "net/cert/cert_verify_result.h" |
+#include "net/ssl/ssl_config_service.h" |
+#include "net/url_request/url_request_context.h" |
+#include "net/url_request/url_request_context_getter.h" |
+ |
+@interface CRWCertVerificationController () { |
+ // Cert verification object which wraps |net::CertVerifier|. Must be created, |
+ // used and destroyed on IO Thread. |
+ scoped_ptr<web::CertVerifierBlockAdapter> _certVerifier; |
+ |
+ // URLRequestContextGetter for obtaining net layer objects. |
+ net::URLRequestContextGetter* _contextGetter; |
+} |
+ |
+// Cert verification flags. Must be used on IO Thread. |
+@property(nonatomic, readonly) int certVerifyFlags; |
+ |
+// Creates _certVerifier object on IO thread. |
+- (void)createCertVerifier; |
+ |
+// Verifies the given |cert| for the given |host| and calls |completionHandler| |
+// on completion. |completionHandler| cannot be null and will be called |
+// synchronously or asynchronously on IO thread. |
+- (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert |
+ forHost:(NSString*)host |
+ completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler; |
+ |
+@end |
+ |
+@implementation CRWCertVerificationController |
+ |
+#pragma mark - Superclass |
+ |
+- (void)dealloc { |
+ DCHECK(!_certVerifier); // This is not a thread safe check. |
+ [super dealloc]; |
+} |
+ |
+#pragma mark - Public |
+ |
+- (instancetype)initWithBrowserState:(web::BrowserState*)browserState { |
+ DCHECK(browserState); |
+ DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
+ self = [super init]; |
+ if (self) { |
+ _contextGetter = browserState->GetRequestContext(); |
+ DCHECK(_contextGetter); |
+ [self createCertVerifier]; |
+ } |
+ return self; |
+} |
+ |
+- (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert |
+ host:(NSString*)host |
+ completionHandler:(void (^)(web::CertAcceptPolicy))handler { |
+ DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
+ [self verifyCert:cert |
+ forHost:host |
+ completionHandler:^(net::CertVerifyResult result, int error) { |
+ web::CertAcceptPolicy policy = web::CERT_ACCEPT_POLICY_UNKNOWN; |
+ if (error == net::OK) { |
+ policy = web::CERT_ACCEPT_POLICY_ALLOW; |
+ } else if (net::IsCertStatusError(result.cert_status)) { |
Eugene But (OOO till 7-30)
2015/08/25 18:05:54
David, could you please confirm that the logic is
davidben
2015/08/26 20:19:09
I would maybe UNKNOWN -> ERROR to make it clear th
Eugene But (OOO till 7-30)
2015/08/26 21:12:48
Done.
Ryan Sleevi
2015/09/03 21:56:04
Right, I don't think it's correct :) error can be
Eugene But (OOO till 7-30)
2015/09/03 22:26:37
Hm... not sure if I understand this...
If cert ce
|
+ // TODO(eugenebut): Check CertPolicyCache for user's decision. |
+ policy = net::IsCertStatusMinorError(result.cert_status) |
+ ? web::CERT_ACCEPT_POLICY_ALLOW |
+ : web::CERT_ACCEPT_POLICY_DENY; |
+ } |
+ |
+ dispatch_async(dispatch_get_main_queue(), ^{ |
+ handler(policy); |
davidben
2015/08/26 20:19:09
Hrm. I think we *still* have the threading problem
Eugene But (OOO till 7-30)
2015/08/26 21:12:48
You are right, this very block (Line 83) retains,
davidben
2015/08/26 21:20:46
The outer block must retain |handler| so that it m
Eugene But (OOO till 7-30)
2015/08/26 21:56:29
Oh, right, I reproduced the case you described and
Eugene But (OOO till 7-30)
2015/08/27 15:57:33
Alright, |handler| is not retained by the blocks a
|
+ }); |
+ }]; |
+} |
+ |
+- (void)shutDown { |
+ DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
+ web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
+ // This block captures |self| delaying its deallocation and possible causing |
+ // dealloc to happen on IO thread (which is fine for this class). |
+ _certVerifier.reset(); |
+ })); |
+} |
+ |
+#pragma mark - Private |
+ |
+- (int)certVerifyFlags { |
+ DCHECK(web::WebThread::CurrentlyOn(web::WebThread::IO)); |
+ DCHECK(_contextGetter); |
+ // |net::URLRequestContextGetter| lifetime is expected to be at least the same |
+ // or longer than |BrowserState| lifetime. |
+ net::URLRequestContext* context = _contextGetter->GetURLRequestContext(); |
+ DCHECK(context); |
+ net::SSLConfigService* SSLConfigService = context->ssl_config_service(); |
+ DCHECK(SSLConfigService); |
+ net::SSLConfig config; |
+ SSLConfigService->GetSSLConfig(&config); |
+ return config.GetCertVerifyFlags(); |
+} |
+ |
+- (void)createCertVerifier { |
+ web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
+ net::URLRequestContext* context = _contextGetter->GetURLRequestContext(); |
+ _certVerifier.reset(new web::CertVerifierBlockAdapter( |
+ context->cert_verifier(), context->net_log())); |
+ })); |
+} |
+ |
+- (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert |
+ forHost:(NSString*)host |
+ completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler { |
+ DCHECK(completionHandler); |
+ __block scoped_refptr<net::X509Certificate> blockCert = cert; |
+ web::WebThread::PostTask( |
+ web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
+ // WeakNSObject does not work across different threads, hence this block |
+ // retains self. |
+ if (!_certVerifier) { |
+ completionHandler(net::CertVerifyResult(), net::ERR_FAILED); |
+ return; |
+ } |
+ |
+ web::CertVerifierBlockAdapter::Params params( |
+ blockCert.Pass(), base::SysNSStringToUTF8(host)); |
+ params.flags = self.certVerifyFlags; |
+ params.crl_set = net::SSLConfigService::GetCRLSet(); |
+ // OCSP response is not provided by iOS API. |
+ _certVerifier->Verify(params, completionHandler); |
+ })); |
+} |
+ |
+@end |