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

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

Issue 1322193003: WKWebView(iOS9): correctly update SSL status for current navigation item (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@reland_cert_verification
Patch Set: Moved reportHasCertForSecureConnectionUMAWithValue: out of ifdefs. 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/metrics/histogram_macros.h"
14 #include "base/strings/sys_string_conversions.h" 15 #include "base/strings/sys_string_conversions.h"
15 #include "base/values.h" 16 #include "base/values.h"
16 #import "ios/net/http_response_headers_util.h" 17 #import "ios/net/http_response_headers_util.h"
17 #import "ios/web/crw_network_activity_indicator_manager.h" 18 #import "ios/web/crw_network_activity_indicator_manager.h"
18 #import "ios/web/navigation/crw_session_controller.h" 19 #import "ios/web/navigation/crw_session_controller.h"
19 #import "ios/web/navigation/crw_session_entry.h" 20 #import "ios/web/navigation/crw_session_entry.h"
20 #include "ios/web/navigation/navigation_item_impl.h" 21 #include "ios/web/navigation/navigation_item_impl.h"
21 #include "ios/web/navigation/web_load_params.h" 22 #include "ios/web/navigation/web_load_params.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"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 userInfo:userInfo]; 76 userInfo:userInfo];
76 } 77 }
77 WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { 78 WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) {
78 DCHECK(error); 79 DCHECK(error);
79 return static_cast<WKWebViewErrorSource>( 80 return static_cast<WKWebViewErrorSource>(
80 [error.userInfo[kWKWebViewErrorSourceKey] integerValue]); 81 [error.userInfo[kWKWebViewErrorSourceKey] integerValue]);
81 } 82 }
82 83
83 } // namespace 84 } // namespace
84 85
86 #if !defined(__IPHONE_9_0) || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
87 // Predeclare iOS9 API so calls are compiled on iOS8 bots.
88 // TODO(eugenebut): cleanup this (crbug.com/523365).
stuartmorgan 2015/10/09 20:28:23 "Clean this up"
Eugene But (OOO till 7-30) 2015/10/09 20:59:37 Done.
89 @interface WKWebView (CRWIOS9API)
90 @property(nonatomic, readonly, copy) NSArray* certificateChain;
91 @end
92 #endif
93
85 @interface CRWWKWebViewWebController () <WKNavigationDelegate, 94 @interface CRWWKWebViewWebController () <WKNavigationDelegate,
86 WKScriptMessageHandler, 95 WKScriptMessageHandler,
87 WKUIDelegate> { 96 WKUIDelegate> {
88 // The WKWebView managed by this instance. 97 // The WKWebView managed by this instance.
89 base::scoped_nsobject<WKWebView> _wkWebView; 98 base::scoped_nsobject<WKWebView> _wkWebView;
90 99
91 // The Watch Dog that detects and reports WKWebView crashes. 100 // The Watch Dog that detects and reports WKWebView crashes.
92 base::scoped_nsobject<CRWWKWebViewCrashDetector> _crashDetector; 101 base::scoped_nsobject<CRWWKWebViewCrashDetector> _crashDetector;
93 102
94 // The actual URL of the document object (i.e., the last committed URL). 103 // The actual URL of the document object (i.e., the last committed URL).
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 // Called when a load ends in an SSL error and certificate chain. 252 // Called when a load ends in an SSL error and certificate chain.
244 - (void)handleSSLCertError:(NSError*)error; 253 - (void)handleSSLCertError:(NSError*)error;
245 #endif 254 #endif
246 255
247 // Adds an activity indicator tasks for this web controller. 256 // Adds an activity indicator tasks for this web controller.
248 - (void)addActivityIndicatorTask; 257 - (void)addActivityIndicatorTask;
249 258
250 // Clears all activity indicator tasks for this web controller. 259 // Clears all activity indicator tasks for this web controller.
251 - (void)clearActivityIndicatorTasks; 260 - (void)clearActivityIndicatorTasks;
252 261
262 // Updates and |style| and |certStatus| for Navigation Item wich has given
stuartmorgan 2015/10/09 20:28:23 s/Updates and/Updates/ /for ... given/of the Navig
Eugene But (OOO till 7-30) 2015/10/09 20:59:37 Done.
263 // |navigationItemID|, |host| and represents given |certChain|.
264 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID
265 certChain:(NSArray*)certChain
266 host:(NSString*)host
267 withSecurityStyle:(web::SecurityStyle)style
268 certStatus:(net::CertStatus)certStatus;
269
270 // Asynchronously obtains SSL status from given |certChain| and |host| and
271 // updates current navigation item.
272 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain
273 host:(NSString*)host;
274
253 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) 275 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
254 // Updates SSL status for the current navigation item based on the information 276 // Updates SSL status for the current navigation item based on the information
255 // provided by web view. 277 // provided by web view.
256 - (void)updateSSLStatusForCurrentNavigationItem; 278 - (void)updateSSLStatusForCurrentNavigationItem;
257 #endif 279 #endif
258 280
281 // Reports "WebController.WKWebViewHasCertForSecureConnection" UMA.
282 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value;
283
259 // Registers load request with empty referrer and link or client redirect 284 // Registers load request with empty referrer and link or client redirect
260 // transition based on user interaction state. 285 // transition based on user interaction state.
261 - (void)registerLoadRequest:(const GURL&)url; 286 - (void)registerLoadRequest:(const GURL&)url;
262 287
263 // Called when a non-document-changing URL change occurs. Updates the 288 // Called when a non-document-changing URL change occurs. Updates the
264 // _documentURL, and informs the superclass of the change. 289 // _documentURL, and informs the superclass of the change.
265 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; 290 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL;
266 291
267 // Returns new autoreleased instance of WKUserContentController which has 292 // Returns new autoreleased instance of WKUserContentController which has
268 // early page script. 293 // early page script.
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 - (void)addActivityIndicatorTask { 882 - (void)addActivityIndicatorTask {
858 [[CRWNetworkActivityIndicatorManager sharedInstance] 883 [[CRWNetworkActivityIndicatorManager sharedInstance]
859 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; 884 startNetworkTaskForGroup:[self activityIndicatorGroupID]];
860 } 885 }
861 886
862 - (void)clearActivityIndicatorTasks { 887 - (void)clearActivityIndicatorTasks {
863 [[CRWNetworkActivityIndicatorManager sharedInstance] 888 [[CRWNetworkActivityIndicatorManager sharedInstance]
864 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; 889 clearNetworkTasksForGroup:[self activityIndicatorGroupID]];
865 } 890 }
866 891
892 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID
893 certChain:(NSArray*)chain
894 host:(NSString*)host
895 withSecurityStyle:(web::SecurityStyle)style
896 certStatus:(net::CertStatus)certStatus {
897 web::NavigationManager* navigationManager =
898 self.webStateImpl->GetNavigationManager();
899
900 // The searched item almost always be the last one, so walk backward rather
901 // than forward.
902 for (int i = navigationManager->GetEntryCount() - 1; 0 <= i; i--) {
903 web::NavigationItem* item = navigationManager->GetItemAtIndex(i);
904 if (item->GetUniqueID() != navigationItemID)
905 continue;
906
907 // NavigationItem's UniqueID is preserved even after redirects, so
908 // checking that cert and URL matche is necessary.
909 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(chain));
910 int certID =
911 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID);
912 std::string GURLHost = base::SysNSStringToUTF8(host);
913 web::SSLStatus& SSLStatus = item->GetSSL();
914 if (SSLStatus.cert_id == certID && item->GetURL().host() == GURLHost) {
915 web::SSLStatus previousSSLStatus = item->GetSSL();
916 SSLStatus.cert_status = certStatus;
917 SSLStatus.security_style = style;
918 if (navigationManager->GetCurrentEntryIndex() == i &&
919 !previousSSLStatus.Equals(SSLStatus)) {
920 [self didUpdateSSLStatusForCurrentNavigationItem];
921 }
922 }
923 return;
924 }
925 }
926
927 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain
928 host:(NSString*)host {
929 // Use Navigation Item's unique ID to locate requested item after
930 // obtaining cert status asynchronously.
931 int itemID = self.webStateImpl->GetNavigationManager()
932 ->GetLastCommittedItem()
933 ->GetUniqueID();
934
935 base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self);
936 void (^SSLStatusResponse)(web::SecurityStyle, net::CertStatus) =
937 ^(web::SecurityStyle style, net::CertStatus certStatus) {
938 base::scoped_nsobject<CRWWKWebViewWebController> strongSelf(
939 [weakSelf retain]);
940 if (!strongSelf || [strongSelf isBeingDestroyed]) {
941 return;
942 }
943 [strongSelf updateSSLStatusForNavigationItemWithID:itemID
944 certChain:chain
945 host:host
946 withSecurityStyle:style
947 certStatus:certStatus];
948 };
949
950 [_certVerificationController
951 querySSLStatusForTrust:web::CreateServerTrustFromChain(chain, host)
952 host:host
953 completionHandler:SSLStatusResponse];
954 }
955
867 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) 956 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
957
868 - (void)updateSSLStatusForCurrentNavigationItem { 958 - (void)updateSSLStatusForCurrentNavigationItem {
869 if ([self isBeingDestroyed]) 959 if ([self isBeingDestroyed])
870 return; 960 return;
871 961
872 DCHECK(self.webStateImpl);
873 web::NavigationItem* item = 962 web::NavigationItem* item =
874 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); 963 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem();
875 if (!item) 964 if (!item)
876 return; 965 return;
877 966
878 web::SSLStatus previousSSLStatus = item->GetSSL(); 967 web::SSLStatus previousSSLStatus = item->GetSSL();
879 web::SSLStatus& SSLStatus = item->GetSSL(); 968 web::SSLStatus& SSLStatus = item->GetSSL();
880 if (item->GetURL().SchemeIsCryptographic()) {
881 // TODO(eugenebut): Do not set security style to authenticated once
882 // proceeding with bad ssl cert is implemented.
883 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED;
884 SSLStatus.content_status = [_wkWebView hasOnlySecureContent]
885 ? web::SSLStatus::NORMAL_CONTENT
886 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT;
887 969
888 if (base::ios::IsRunningOnIOS9OrLater()) { 970 // Starting from iOS9 WKWebView blocks active mixed content, so if
889 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain( 971 // |hasOnlySecureContent| returns NO it means passive content.
890 [_wkWebView performSelector:@selector(certificateChain)])); 972 // On iOS8 there is no way to determine if web view has active mixed content.
891 if (cert) { 973 SSLStatus.content_status = [_wkWebView hasOnlySecureContent]
892 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( 974 ? web::SSLStatus::NORMAL_CONTENT
893 cert.get(), self.certGroupID); 975 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT;
894 } else { 976
895 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; 977 // Try updating SSLStatus for current NavigationItem asynchronously.
896 SSLStatus.cert_id = 0; 978 scoped_refptr<net::X509Certificate> cert;
979 if (base::ios::IsRunningOnIOS9OrLater() &&
980 item->GetURL().SchemeIsCryptographic()) {
981 NSArray* chain = [_wkWebView certificateChain];
982 cert = web::CreateCertFromChain(chain);
983 if (cert) {
984 int oldCertID = SSLStatus.cert_id;
985 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert(
986 cert.get(), self.certGroupID);
987 // Only recompute the SSLStatus information if the certificate has since
988 // changed.
989 if (oldCertID != SSLStatus.cert_id ||
990 item->GetURL().host() != _documentURL.host()) {
991 NSString* host = base::SysUTF8ToNSString(_documentURL.host());
992 [self scheduleSSLStatusUpdateUsingCertChain:chain host:host];
993 [self reportHasCertForSecureConnectionUMAWithValue:true];
897 } 994 }
898 } 995 }
899 } else { 996 }
900 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; 997
998 if (!cert) {
901 SSLStatus.cert_id = 0; 999 SSLStatus.cert_id = 0;
1000 if (!item->GetURL().SchemeIsCryptographic()) {
1001 // HTTP or other non-secure connection.
1002 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED;
1003 } else if (base::ios::IsRunningOnIOS9OrLater()) {
1004 // HTTPS, iOS9 and no certificate (this use-case has not been observed).
1005 [self reportHasCertForSecureConnectionUMAWithValue:false];
1006 SSLStatus.security_style = web::SECURITY_STYLE_UNKNOWN;
1007 } else {
1008 // HTTPS, iOS8.
1009 // iOS8 cannot load unauthenticated HTTPS content.
1010 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED;
1011 }
902 } 1012 }
903 1013
904 if (!previousSSLStatus.Equals(SSLStatus)) { 1014 if (!previousSSLStatus.Equals(SSLStatus)) {
905 [self didUpdateSSLStatusForCurrentNavigationItem]; 1015 [self didUpdateSSLStatusForCurrentNavigationItem];
906 } 1016 }
907 } 1017 }
1018
908 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) 1019 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
909 1020
1021 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value {
1022 UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection",
1023 value);
1024 }
1025
910 - (void)registerLoadRequest:(const GURL&)url { 1026 - (void)registerLoadRequest:(const GURL&)url {
911 // If load request is registered via WKWebViewWebController, assume transition 1027 // If load request is registered via WKWebViewWebController, assume transition
912 // is link or client redirect as other transitions will already be registered 1028 // is link or client redirect as other transitions will already be registered
913 // by web controller or delegates. 1029 // by web controller or delegates.
914 // TODO(stuartmorgan): Remove guesswork and replace with information from 1030 // TODO(stuartmorgan): Remove guesswork and replace with information from
915 // decidePolicyForNavigationAction:. 1031 // decidePolicyForNavigationAction:.
916 ui::PageTransition transition = self.userInteractionRegistered 1032 ui::PageTransition transition = self.userInteractionRegistered
917 ? ui::PAGE_TRANSITION_LINK 1033 ? ui::PAGE_TRANSITION_LINK
918 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; 1034 : ui::PAGE_TRANSITION_CLIENT_REDIRECT;
919 // The referrer is not known yet, and will be updated later. 1035 // The referrer is not known yet, and will be updated later.
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 (void (^)(NSURLSessionAuthChallengeDisposition disposition, 1498 (void (^)(NSURLSessionAuthChallengeDisposition disposition,
1383 NSURLCredential *credential))completionHandler { 1499 NSURLCredential *credential))completionHandler {
1384 if (![challenge.protectionSpace.authenticationMethod 1500 if (![challenge.protectionSpace.authenticationMethod
1385 isEqual:NSURLAuthenticationMethodServerTrust]) { 1501 isEqual:NSURLAuthenticationMethodServerTrust]) {
1386 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 1502 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
1387 return; 1503 return;
1388 } 1504 }
1389 1505
1390 SecTrustRef trust = challenge.protectionSpace.serverTrust; 1506 SecTrustRef trust = challenge.protectionSpace.serverTrust;
1391 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); 1507 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust);
1508 // TODO(eugenebut): pass SecTrustRef instead of cert.
1392 [_certVerificationController 1509 [_certVerificationController
1393 decidePolicyForCert:cert 1510 decidePolicyForCert:cert
1394 host:challenge.protectionSpace.host 1511 host:challenge.protectionSpace.host
1395 completionHandler:^(web::CertAcceptPolicy policy, 1512 completionHandler:^(web::CertAcceptPolicy policy,
1396 net::CertStatus status) { 1513 net::CertStatus status) {
1397 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, 1514 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace,
1398 nil); 1515 nil);
1399 }]; 1516 }];
1400 } 1517 }
1401 1518
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 placeholderText:defaultText 1605 placeholderText:defaultText
1489 requestURL: 1606 requestURL:
1490 net::GURLWithNSURL(frame.request.URL) 1607 net::GURLWithNSURL(frame.request.URL)
1491 completionHandler:completionHandler]; 1608 completionHandler:completionHandler];
1492 } else if (completionHandler) { 1609 } else if (completionHandler) {
1493 completionHandler(nil); 1610 completionHandler(nil);
1494 } 1611 }
1495 } 1612 }
1496 1613
1497 @end 1614 @end
OLDNEW
« no previous file with comments | « ios/web/net/crw_cert_verification_controller_unittest.mm ('k') | ios/web/web_state/wk_web_view_security_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698