Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: ios/web/web_state/ui/crw_wk_web_view_web_controller.mm

Issue 1357773002: WKWebView: Implemented recoverable SSL interstitials. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lock_coloring
Patch Set: Merged with parent CL Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/web_state/ui/crw_wk_web_view_web_controller.h" 5 #import "ios/web/web_state/ui/crw_wk_web_view_web_controller.h"
6 6
7 #import <WebKit/WebKit.h> 7 #import <WebKit/WebKit.h>
8 8
9 #include "base/ios/ios_util.h" 9 #include "base/ios/ios_util.h"
10 #include "base/ios/weak_nsobject.h" 10 #include "base/ios/weak_nsobject.h"
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #import "base/mac/scoped_nsobject.h" 12 #import "base/mac/scoped_nsobject.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/strings/sys_string_conversions.h" 14 #include "base/strings/sys_string_conversions.h"
15 #include "base/values.h" 15 #include "base/values.h"
16 #import "ios/net/http_response_headers_util.h" 16 #import "ios/net/http_response_headers_util.h"
17 #import "ios/web/crw_network_activity_indicator_manager.h" 17 #import "ios/web/crw_network_activity_indicator_manager.h"
18 #import "ios/web/navigation/crw_session_controller.h" 18 #import "ios/web/navigation/crw_session_controller.h"
19 #import "ios/web/navigation/crw_session_entry.h" 19 #import "ios/web/navigation/crw_session_entry.h"
20 #include "ios/web/navigation/navigation_item_impl.h" 20 #include "ios/web/navigation/navigation_item_impl.h"
21 #include "ios/web/navigation/web_load_params.h" 21 #include "ios/web/navigation/web_load_params.h"
22 #include "ios/web/net/cert_verification_cache.h"
22 #import "ios/web/net/crw_cert_verification_controller.h" 23 #import "ios/web/net/crw_cert_verification_controller.h"
23 #include "ios/web/public/cert_store.h" 24 #include "ios/web/public/cert_store.h"
24 #include "ios/web/public/navigation_item.h" 25 #include "ios/web/public/navigation_item.h"
25 #include "ios/web/public/ssl_status.h" 26 #include "ios/web/public/ssl_status.h"
26 #include "ios/web/public/web_client.h" 27 #include "ios/web/public/web_client.h"
27 #import "ios/web/public/web_state/js/crw_js_injection_manager.h" 28 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
28 #import "ios/web/public/web_state/ui/crw_native_content_provider.h" 29 #import "ios/web/public/web_state/ui/crw_native_content_provider.h"
29 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h" 30 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
30 #import "ios/web/ui_web_view_util.h" 31 #import "ios/web/ui_web_view_util.h"
31 #include "ios/web/web_state/blocked_popup_info.h" 32 #include "ios/web/web_state/blocked_popup_info.h"
32 #import "ios/web/web_state/error_translation_util.h" 33 #import "ios/web/web_state/error_translation_util.h"
33 #include "ios/web/web_state/frame_info.h" 34 #include "ios/web/web_state/frame_info.h"
34 #import "ios/web/web_state/js/crw_js_window_id_manager.h" 35 #import "ios/web/web_state/js/crw_js_window_id_manager.h"
35 #import "ios/web/web_state/js/page_script_util.h" 36 #import "ios/web/web_state/js/page_script_util.h"
36 #import "ios/web/web_state/ui/crw_web_controller+protected.h" 37 #import "ios/web/web_state/ui/crw_web_controller+protected.h"
37 #import "ios/web/web_state/ui/crw_wk_web_view_crash_detector.h" 38 #import "ios/web/web_state/ui/crw_wk_web_view_crash_detector.h"
38 #import "ios/web/web_state/ui/web_view_js_utils.h" 39 #import "ios/web/web_state/ui/web_view_js_utils.h"
39 #import "ios/web/web_state/ui/wk_back_forward_list_item_holder.h" 40 #import "ios/web/web_state/ui/wk_back_forward_list_item_holder.h"
40 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h" 41 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
41 #import "ios/web/web_state/web_state_impl.h" 42 #import "ios/web/web_state/web_state_impl.h"
42 #import "ios/web/web_state/web_view_internal_creation_util.h" 43 #import "ios/web/web_state/web_view_internal_creation_util.h"
43 #import "ios/web/web_state/wk_web_view_security_util.h" 44 #import "ios/web/web_state/wk_web_view_security_util.h"
44 #import "ios/web/webui/crw_web_ui_manager.h" 45 #import "ios/web/webui/crw_web_ui_manager.h"
45 #include "net/cert/x509_certificate.h" 46 #include "net/cert/x509_certificate.h"
46 #import "net/base/mac/url_conversions.h" 47 #import "net/base/mac/url_conversions.h"
47 #include "net/ssl/ssl_info.h" 48 #include "net/ssl/ssl_info.h"
48 #include "url/url_constants.h" 49 #include "url/url_constants.h"
49 50
50 namespace { 51 namespace {
52
53 // Represents cert verification error, which happened inside
54 // |webView:didReceiveAuthenticationChallenge:completionHandler:| and should
55 // be checked inside |webView:didFailProvisionalNavigation:withError:|.
56 struct CertVerificationError {
57 BOOL is_recoverable;
58 net::CertStatus status;
59 };
60
51 // Extracts Referer value from WKNavigationAction request header. 61 // Extracts Referer value from WKNavigationAction request header.
52 NSString* GetRefererFromNavigationAction(WKNavigationAction* action) { 62 NSString* GetRefererFromNavigationAction(WKNavigationAction* action) {
53 return [action.request valueForHTTPHeaderField:@"Referer"]; 63 return [action.request valueForHTTPHeaderField:@"Referer"];
54 } 64 }
55 65
56 NSString* const kScriptMessageName = @"crwebinvoke"; 66 NSString* const kScriptMessageName = @"crwebinvoke";
57 NSString* const kScriptImmediateName = @"crwebinvokeimmediate"; 67 NSString* const kScriptImmediateName = @"crwebinvokeimmediate";
58 68
59 // Utility functions for storing the source of NSErrors received by WKWebViews: 69 // Utility functions for storing the source of NSErrors received by WKWebViews:
60 // - Errors received by |-webView:didFailProvisionalNavigation:withError:| are 70 // - Errors received by |-webView:didFailProvisionalNavigation:withError:| are
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 // bad SSL cert, presenting SSL interstitials and determining SSL status for 148 // bad SSL cert, presenting SSL interstitials and determining SSL status for
139 // Navigation Items. 149 // Navigation Items.
140 base::scoped_nsobject<CRWCertVerificationController> 150 base::scoped_nsobject<CRWCertVerificationController>
141 _certVerificationController; 151 _certVerificationController;
142 152
143 // Whether the pending navigation has been directly cancelled in 153 // Whether the pending navigation has been directly cancelled in
144 // |decidePolicyForNavigationAction| or |decidePolicyForNavigationResponse|. 154 // |decidePolicyForNavigationAction| or |decidePolicyForNavigationResponse|.
145 // Cancelled navigations should be simply discarded without handling any 155 // Cancelled navigations should be simply discarded without handling any
146 // specific error. 156 // specific error.
147 BOOL _pendingNavigationCancelled; 157 BOOL _pendingNavigationCancelled;
158
159 // CertVerification errors which happened inside
160 // |webView:didReceiveAuthenticationChallenge:completionHandler:|.
161 // Key is leaf-cert - host pair. This storage is used to carry calculated
162 // cert status from |didReceiveAuthenticationChallenge:| to
163 // |didFailProvisionalNavigation:| delegate method.
164 web::CertVerificationCache<CertVerificationError> _certVerificationErrors;
148 } 165 }
149 166
150 // Response's MIME type of the last known navigation. 167 // Response's MIME type of the last known navigation.
151 @property(nonatomic, copy) NSString* documentMIMEType; 168 @property(nonatomic, copy) NSString* documentMIMEType;
152 169
153 // Dictionary where keys are the names of WKWebView properties and values are 170 // Dictionary where keys are the names of WKWebView properties and values are
154 // selector names which should be called when a corresponding property has 171 // selector names which should be called when a corresponding property has
155 // changed. e.g. @{ @"URL" : @"webViewURLDidChange" } means that 172 // changed. e.g. @{ @"URL" : @"webViewURLDidChange" } means that
156 // -[self webViewURLDidChange] must be called every time when WKWebView.URL is 173 // -[self webViewURLDidChange] must be called every time when WKWebView.URL is
157 // changed. 174 // changed.
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 } 567 }
551 return [super URLForHistoryNavigationFromItem:fromItem toItem:toItem]; 568 return [super URLForHistoryNavigationFromItem:fromItem toItem:toItem];
552 } 569 }
553 570
554 - (void)setPageChangeProbability:(web::PageChangeProbability)probability { 571 - (void)setPageChangeProbability:(web::PageChangeProbability)probability {
555 // Nothing to do; no polling timer. 572 // Nothing to do; no polling timer.
556 } 573 }
557 574
558 - (void)abortWebLoad { 575 - (void)abortWebLoad {
559 [_wkWebView stopLoading]; 576 [_wkWebView stopLoading];
577 _certVerificationErrors.reset();
560 } 578 }
561 579
562 - (void)resetLoadState { 580 - (void)resetLoadState {
563 // Nothing to do. 581 // Nothing to do.
564 } 582 }
565 583
566 - (void)setSuppressDialogsWithHelperScript:(NSString*)script { 584 - (void)setSuppressDialogsWithHelperScript:(NSString*)script {
567 [self evaluateJavaScript:script stringResultHandler:nil]; 585 [self evaluateJavaScript:script stringResultHandler:nil];
568 } 586 }
569 587
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 sourceURL:sourceURL 854 sourceURL:sourceURL
837 referrerPolicy:base::SysNSStringToUTF8(policy)]; 855 referrerPolicy:base::SysNSStringToUTF8(policy)];
838 }]; 856 }];
839 }); 857 });
840 } 858 }
841 859
842 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) 860 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
843 - (void)handleSSLError:(NSError*)error { 861 - (void)handleSSLError:(NSError*)error {
844 DCHECK(web::IsWKWebViewSSLError(error)); 862 DCHECK(web::IsWKWebViewSSLError(error));
845 863
846 net::SSLInfo sslInfo; 864 net::SSLInfo SSLInfo;
847 web::GetSSLInfoFromWKWebViewSSLError(error, &sslInfo); 865 web::GetSSLInfoFromWKWebViewSSLError(error, &SSLInfo);
848 866
849 web::SSLStatus sslStatus; 867 web::SSLStatus SSLStatus;
850 sslStatus.security_style = web::SECURITY_STYLE_AUTHENTICATION_BROKEN; 868 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATION_BROKEN;
851 sslStatus.cert_status = sslInfo.cert_status; 869 SSLStatus.cert_status = SSLInfo.cert_status;
852 sslStatus.cert_id = web::CertStore::GetInstance()->StoreCert( 870 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert(
853 sslInfo.cert.get(), self.certGroupID); 871 SSLInfo.cert.get(), self.certGroupID);
854 872
855 [self.delegate presentSSLError:sslInfo 873 NSArray* chain = error.userInfo[web::kNSErrorPeerCertificateChainKey];
856 forSSLStatus:sslStatus 874 NSString* host = [error.userInfo[web::kNSErrorFailingURLKey] host];
857 recoverable:NO 875 // Verification results are cached for leaf cert, because cert chain in
858 callback:nullptr]; 876 // |didReceiveAuthenticationChallenge:| maybe different from |chain|.
877 scoped_refptr<net::X509Certificate> leafCert;
878 BOOL recoverable = NO;
879 if (chain.count && host.length) {
880 // Complete cert chain may not be available inside this method, so leaf
881 // cert is used as a key to retrieve _certVerificationErrors as well as for
882 // storing cert decision.
883 leafCert = web::CreateCertFromChain(@[ [chain firstObject] ]);
884 if (leafCert) {
885 CertVerificationError error;
886 if (_certVerificationErrors.get(leafCert, base::SysNSStringToUTF8(host),
887 &error)) {
888 SSLStatus.cert_status = error.status;
889 recoverable = error.is_recoverable;
890 }
891 }
892 }
893 [self.delegate presentSSLError:SSLInfo
894 forSSLStatus:SSLStatus
895 recoverable:recoverable
896 callback:^(BOOL proceed) {
897 if (proceed) {
898 // The interstitial will be removed during reload.
899 [_certVerificationController
stuartmorgan 2015/09/23 17:36:09 Are we okay with a strong reference to self here?
Eugene But (OOO till 7-30) 2015/09/23 20:40:47 Yes, displayed interstitial outlives web controlle
900 allowCert:leafCert
901 forHost:host
902 status:SSLStatus.cert_status];
903 [self loadCurrentURL];
904 }
905 }];
906 _certVerificationErrors.reset();
859 } 907 }
860 #endif // #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) 908 #endif // #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
861 909
862 - (void)addActivityIndicatorTask { 910 - (void)addActivityIndicatorTask {
863 [[CRWNetworkActivityIndicatorManager sharedInstance] 911 [[CRWNetworkActivityIndicatorManager sharedInstance]
864 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; 912 startNetworkTaskForGroup:[self activityIndicatorGroupID]];
865 } 913 }
866 914
867 - (void)clearActivityIndicatorTasks { 915 - (void)clearActivityIndicatorTasks {
868 [[CRWNetworkActivityIndicatorManager sharedInstance] 916 [[CRWNetworkActivityIndicatorManager sharedInstance]
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after
1391 else 1439 else
1392 #endif 1440 #endif
1393 [self handleLoadError:error inMainFrame:YES]; 1441 [self handleLoadError:error inMainFrame:YES];
1394 1442
1395 [self discardPendingNavigationTypeForMainFrame]; 1443 [self discardPendingNavigationTypeForMainFrame];
1396 } 1444 }
1397 1445
1398 - (void)webView:(WKWebView *)webView 1446 - (void)webView:(WKWebView *)webView
1399 didCommitNavigation:(WKNavigation *)navigation { 1447 didCommitNavigation:(WKNavigation *)navigation {
1400 DCHECK_EQ(_wkWebView, webView); 1448 DCHECK_EQ(_wkWebView, webView);
1449 _certVerificationErrors.reset();
1401 // This point should closely approximate the document object change, so reset 1450 // This point should closely approximate the document object change, so reset
1402 // the list of injected scripts to those that are automatically injected. 1451 // the list of injected scripts to those that are automatically injected.
1403 _injectedScriptManagers.reset([[NSMutableSet alloc] init]); 1452 _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
1404 [self injectWindowID]; 1453 [self injectWindowID];
1405 1454
1406 // The page has changed; commit the pending referrer. 1455 // The page has changed; commit the pending referrer.
1407 [self commitPendingReferrerString]; 1456 [self commitPendingReferrerString];
1408 1457
1409 // This is the point where the document's URL has actually changed. 1458 // This is the point where the document's URL has actually changed.
1410 _documentURL = net::GURLWithNSURL([_wkWebView URL]); 1459 _documentURL = net::GURLWithNSURL([_wkWebView URL]);
(...skipping 30 matching lines...) Expand all
1441 completionHandler: 1490 completionHandler:
1442 (void (^)(NSURLSessionAuthChallengeDisposition disposition, 1491 (void (^)(NSURLSessionAuthChallengeDisposition disposition,
1443 NSURLCredential *credential))completionHandler { 1492 NSURLCredential *credential))completionHandler {
1444 if (![challenge.protectionSpace.authenticationMethod 1493 if (![challenge.protectionSpace.authenticationMethod
1445 isEqual:NSURLAuthenticationMethodServerTrust]) { 1494 isEqual:NSURLAuthenticationMethodServerTrust]) {
1446 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 1495 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
1447 return; 1496 return;
1448 } 1497 }
1449 1498
1450 SecTrustRef trust = challenge.protectionSpace.serverTrust; 1499 SecTrustRef trust = challenge.protectionSpace.serverTrust;
1451 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); 1500 id handler = ^(web::CertAcceptPolicy policy, net::CertStatus status) {
1501 if (policy == web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER) {
1502 // cert is invalid, but user agreed to proceed.
1503 completionHandler(NSURLSessionAuthChallengeUseCredential,
1504 [NSURLCredential credentialForTrust:trust]);
1505 } else {
1506 if (policy != web::CERT_ACCEPT_POLICY_ALLOW) {
1507 // cert is invalid and user has not agreed to proceed.
1508
1509 // Cache cert verification result with _certVerificationErrors storage,
1510 // so it can be later reused inside |didFailProvisionalNavigation:|.
1511 // didFailProvisionalNavigation: does not receive full cert chain and it
1512 // will not be possible to resulculate cert status there.
1513 if (SecTrustGetCertificateCount(trust)) {
1514 // Leaf cert (w/o any intermidiates) is used for caching.
1515 // Chain inside |didFailProvisionalNavigation:| may be different and
1516 // using intermidiates will result in keys mismatch.
1517 scoped_refptr<net::X509Certificate> leafCert =
1518 web::CreateCertFromChain(@[
1519 static_cast<id>(SecTrustGetCertificateAtIndex(trust, 0))
1520 ]);
1521 if (leafCert) {
1522 BOOL is_recoverable =
1523 policy ==
1524 web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_NOT_ACCEPTED_BY_USER;
1525 _certVerificationErrors.set(
1526 leafCert,
1527 base::SysNSStringToUTF8(challenge.protectionSpace.host),
1528 {is_recoverable, status});
1529 }
1530 }
1531 }
1532 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
1533 }
1534 };
1535
1452 [_certVerificationController 1536 [_certVerificationController
1453 decidePolicyForCert:cert 1537 decideLoadPolicyForTrust:trust
1454 host:challenge.protectionSpace.host 1538 host:challenge.protectionSpace.host
1455 completionHandler:^(web::CertAcceptPolicy policy, 1539 completionHandler:handler];
stuartmorgan 2015/09/23 17:36:09 Same question here; what's the ownership/lifetime
Eugene But (OOO till 7-30) 2015/09/23 20:40:48 Good catch. CRWCertVerificationController has -clo
1456 net::CertStatus status) {
1457 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace,
1458 nil);
1459 }];
1460 } 1540 }
1461 1541
1462 - (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView { 1542 - (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView {
1463 [self webViewWebProcessDidCrash]; 1543 [self webViewWebProcessDidCrash];
1464 } 1544 }
1465 1545
1466 #pragma mark WKUIDelegate Methods 1546 #pragma mark WKUIDelegate Methods
1467 1547
1468 - (WKWebView*)webView:(WKWebView*)webView 1548 - (WKWebView*)webView:(WKWebView*)webView
1469 createWebViewWithConfiguration:(WKWebViewConfiguration*)configuration 1549 createWebViewWithConfiguration:(WKWebViewConfiguration*)configuration
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1548 placeholderText:defaultText 1628 placeholderText:defaultText
1549 requestURL: 1629 requestURL:
1550 net::GURLWithNSURL(frame.request.URL) 1630 net::GURLWithNSURL(frame.request.URL)
1551 completionHandler:completionHandler]; 1631 completionHandler:completionHandler];
1552 } else if (completionHandler) { 1632 } else if (completionHandler) {
1553 completionHandler(nil); 1633 completionHandler(nil);
1554 } 1634 }
1555 } 1635 }
1556 1636
1557 @end 1637 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698