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 a0180d0f978a7f525bcb3ad8fff64a55669586e0..c5dca87c376a89361b8837eaa5b24990958ae5b2 100644 |
--- a/ios/web/net/crw_cert_verification_controller.mm |
+++ b/ios/web/net/crw_cert_verification_controller.mm |
@@ -9,9 +9,11 @@ |
#import "base/memory/ref_counted.h" |
#import "base/memory/scoped_ptr.h" |
#include "base/strings/sys_string_conversions.h" |
+#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/web_thread.h" |
+#import "ios/web/web_state/wk_web_view_security_util.h" |
#include "net/cert/cert_verify_result.h" |
#include "net/ssl/ssl_config_service.h" |
#include "net/url_request/url_request_context.h" |
@@ -73,13 +75,21 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
// 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. |
+// Verifies the given |cert| for the given |host| using |net::CertVerifier| and |
+// calls |completionHandler| on completion. This method can be called on any |
+// thread. |completionHandler| cannot be null and will be called asynchronously |
+// on IO thread. |
- (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert |
forHost:(NSString*)host |
completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler; |
+// Verifies the given |trust| using SecTrustRef API. |completionHandler| cannot |
+// be null and will be either called asynchronously on Worker thread or |
+// synchronously on current thread if the worker task can't start (in this |
+// case |dispatched| argument will be NO). |
+- (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust |
+ completionHandler:(void (^)(SecTrustResultType, BOOL dispatched))handler; |
+ |
@end |
@implementation CRWCertVerificationController |
@@ -112,16 +122,16 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
- (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert |
host:(NSString*)host |
- completionHandler:(web::PolicyDecisionHandler)handler { |
+ 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 |
// captured by completionHandler may be released on either UI or IO thread. |
- // Since |handler| can potentially capture multiple thread unsafe objects |
- // (like Web Controller) |handler| itself should never be released on |
- // background thread and |BlockHolder| ensures that. |
+ // Since |completionHandler| can potentially capture multiple thread unsafe |
+ // objects (like Web Controller) |completionHandler| itself should never be |
+ // released on background thread and |BlockHolder| ensures that. |
__block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder( |
- new BlockHolder<web::PolicyDecisionHandler>(handler)); |
+ new BlockHolder<web::PolicyDecisionHandler>(completionHandler)); |
[self verifyCert:cert |
forHost:host |
completionHandler:^(net::CertVerifyResult result, int error) { |
@@ -141,6 +151,55 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
}]; |
} |
+- (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust |
+ host:(NSString*)host |
+ completionHandler:(web::StatusQueryHandler)completionHandler { |
+ DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
+ |
+ // The completion handlers of |verifyCert:forHost:completionHandler:| and |
+ // |verifyTrust:completionHandler:| will be deallocated on background thread. |
+ // |completionHandler| itself should never be released on background thread |
+ // and |BlockHolder| ensures that. |
+ __block scoped_refptr<BlockHolder<web::StatusQueryHandler>> handlerHolder( |
+ new BlockHolder<web::StatusQueryHandler>(completionHandler)); |
+ [self verifyTrust:trust |
+ completionHandler:^(SecTrustResultType trustResult, BOOL dispatched) { |
+ if (!dispatched) { |
+ // CertVerification task did not start. |
+ dispatch_async(dispatch_get_main_queue(), ^{ |
+ handlerHolder->call(web::SECURITY_STYLE_UNKNOWN, net::CertStatus()); |
+ }); |
+ return; |
+ } |
+ |
+ web::SecurityStyle securityStyle = |
+ web::GetSecurityStyleFromTrustResult(trustResult); |
+ if (securityStyle == web::SECURITY_STYLE_AUTHENTICATED) { |
+ // SecTrust API considers this cert as valid. |
+ dispatch_async(dispatch_get_main_queue(), ^{ |
+ handlerHolder->call(securityStyle, net::CertStatus()); |
+ }); |
+ return; |
+ } |
+ |
+ // Retrieve the net::CertStatus for invalid certificates to determine |
+ // the rejection reason, it is possible that rejection reason could not |
+ // be determined and |cert_status| will be empty. |
+ // TODO(eugenebut): Add UMA for CertVerifier and SecTrust verification |
+ // mismatch (crbug.com/535699). |
+ scoped_refptr<net::X509Certificate> cert( |
+ web::CreateCertFromTrust(trust)); |
+ [self verifyCert:cert |
+ forHost:host |
+ completionHandler:^(net::CertVerifyResult certVerifierResult, int) { |
+ dispatch_async(dispatch_get_main_queue(), ^{ |
+ handlerHolder->call(securityStyle, |
+ certVerifierResult.cert_status); |
+ }); |
+ }]; |
+ }]; |
+} |
+ |
- (void)shutDown { |
DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ |
@@ -197,4 +256,22 @@ class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> { |
})); |
} |
+- (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust |
+ completionHandler:(void (^)(SecTrustResultType, BOOL))completionHandler { |
+ DCHECK(completionHandler); |
+ // SecTrustEvaluate performs trust evaluation synchronously, possibly making |
+ // network requests. The UI thread should not be blocked by that operation. |
+ bool dispatched = base::WorkerPool::PostTask(FROM_HERE, base::BindBlock(^{ |
+ SecTrustResultType trustResult = kSecTrustResultInvalid; |
+ if (SecTrustEvaluate(trust.get(), &trustResult) != errSecSuccess) { |
+ trustResult = kSecTrustResultInvalid; |
+ } |
+ completionHandler(trustResult, YES); |
+ }), false /* task_is_slow */); |
+ |
+ if (!dispatched) { |
+ completionHandler(kSecTrustResultInvalid, NO); |
+ } |
+} |
+ |
@end |