| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/net/crw_ssl_status_updater.h" | 5 #import "ios/web/net/crw_ssl_status_updater.h" |
| 6 | 6 |
| 7 #import "base/ios/weak_nsobject.h" | 7 #import "base/ios/weak_nsobject.h" |
| 8 #import "base/mac/scoped_nsobject.h" | 8 #import "base/mac/scoped_nsobject.h" |
| 9 #import "base/strings/sys_string_conversions.h" | 9 #import "base/strings/sys_string_conversions.h" |
| 10 #include "ios/web/public/cert_store.h" | |
| 11 #import "ios/web/public/navigation_item.h" | 10 #import "ios/web/public/navigation_item.h" |
| 12 #import "ios/web/public/navigation_manager.h" | 11 #import "ios/web/public/navigation_manager.h" |
| 13 #include "ios/web/public/ssl_status.h" | 12 #include "ios/web/public/ssl_status.h" |
| 14 #import "ios/web/web_state/wk_web_view_security_util.h" | 13 #import "ios/web/web_state/wk_web_view_security_util.h" |
| 15 #include "net/cert/x509_certificate.h" | 14 #include "net/cert/x509_certificate.h" |
| 16 #include "url/gurl.h" | 15 #include "url/gurl.h" |
| 17 | 16 |
| 18 #if !defined(__has_feature) || !__has_feature(objc_arc) | 17 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 19 #error "This file requires ARC support." | 18 #error "This file requires ARC support." |
| 20 #endif | 19 #endif |
| 21 | 20 |
| 22 using base::ScopedCFTypeRef; | 21 using base::ScopedCFTypeRef; |
| 23 using net::CertStatus; | 22 using net::CertStatus; |
| 24 using web::SecurityStyle; | 23 using web::SecurityStyle; |
| 25 | 24 |
| 26 @interface CRWSSLStatusUpdater () { | 25 @interface CRWSSLStatusUpdater () { |
| 27 // DataSource for CRWSSLStatusUpdater. | 26 // DataSource for CRWSSLStatusUpdater. |
| 28 base::WeakNSProtocol<id<CRWSSLStatusUpdaterDataSource>> _dataSource; | 27 base::WeakNSProtocol<id<CRWSSLStatusUpdaterDataSource>> _dataSource; |
| 29 // Backs up property of the same name. | 28 // Backs up property of the same name. |
| 30 base::WeakNSProtocol<id<CRWSSLStatusUpdaterDelegate>> _delegate; | 29 base::WeakNSProtocol<id<CRWSSLStatusUpdaterDelegate>> _delegate; |
| 31 } | 30 } |
| 32 | 31 |
| 33 // Unowned pointer to web::NavigationManager. | 32 // Unowned pointer to web::NavigationManager. |
| 34 @property(nonatomic, readonly) web::NavigationManager* navigationManager; | 33 @property(nonatomic, readonly) web::NavigationManager* navigationManager; |
| 35 | 34 |
| 36 // Identifier used for storing and retrieving certificates. | |
| 37 @property(nonatomic, readonly) int certGroupID; | |
| 38 | |
| 39 // Updates |security_style| and |cert_status| for the NavigationItem with ID | 35 // Updates |security_style| and |cert_status| for the NavigationItem with ID |
| 40 // |navigationItemID|, if URL and certificate chain still match |host| and | 36 // |navigationItemID|, if URL and certificate chain still match |host| and |
| 41 // |certChain|. | 37 // |certChain|. |
| 42 - (void)updateSSLStatusForItemWithID:(int)navigationItemID | 38 - (void)updateSSLStatusForItemWithID:(int)navigationItemID |
| 43 trust:(ScopedCFTypeRef<SecTrustRef>)trust | 39 trust:(ScopedCFTypeRef<SecTrustRef>)trust |
| 44 host:(NSString*)host | 40 host:(NSString*)host |
| 45 withSecurityStyle:(SecurityStyle)style | 41 withSecurityStyle:(SecurityStyle)style |
| 46 certStatus:(CertStatus)certStatus; | 42 certStatus:(CertStatus)certStatus; |
| 47 | 43 |
| 48 // Asynchronously obtains SSL status from given |secTrust| and |host| and | 44 // Asynchronously obtains SSL status from given |secTrust| and |host| and |
| 49 // updates current navigation item. Before scheduling update changes SSLStatus' | 45 // updates current navigation item. Before scheduling update changes SSLStatus' |
| 50 // cert_status and security_style to default. | 46 // cert_status and security_style to default. |
| 51 - (void)scheduleSSLStatusUpdateUsingTrust:(ScopedCFTypeRef<SecTrustRef>)trust | 47 - (void)scheduleSSLStatusUpdateUsingTrust:(ScopedCFTypeRef<SecTrustRef>)trust |
| 52 host:(NSString*)host; | 48 host:(NSString*)host; |
| 53 | 49 |
| 54 // Notifies delegate about SSLStatus change. | 50 // Notifies delegate about SSLStatus change. |
| 55 - (void)didChangeSSLStatusForNavigationItem:(web::NavigationItem*)navItem; | 51 - (void)didChangeSSLStatusForNavigationItem:(web::NavigationItem*)navItem; |
| 56 | 52 |
| 57 @end | 53 @end |
| 58 | 54 |
| 59 @implementation CRWSSLStatusUpdater | 55 @implementation CRWSSLStatusUpdater |
| 60 @synthesize navigationManager = _navigationManager; | 56 @synthesize navigationManager = _navigationManager; |
| 61 @synthesize certGroupID = _certGroupID; | |
| 62 | 57 |
| 63 #pragma mark - Public | 58 #pragma mark - Public |
| 64 | 59 |
| 65 - (instancetype)initWithDataSource:(id<CRWSSLStatusUpdaterDataSource>)dataSource | 60 - (instancetype)initWithDataSource:(id<CRWSSLStatusUpdaterDataSource>)dataSource |
| 66 navigationManager:(web::NavigationManager*)navigationManager | 61 navigationManager:(web::NavigationManager*)navigationManager { |
| 67 certGroupID:(int)certGroupID { | |
| 68 DCHECK(dataSource); | 62 DCHECK(dataSource); |
| 69 DCHECK(navigationManager); | 63 DCHECK(navigationManager); |
| 70 DCHECK(certGroupID); | |
| 71 if (self = [super init]) { | 64 if (self = [super init]) { |
| 72 _dataSource.reset(dataSource); | 65 _dataSource.reset(dataSource); |
| 73 _navigationManager = navigationManager; | 66 _navigationManager = navigationManager; |
| 74 _certGroupID = certGroupID; | |
| 75 } | 67 } |
| 76 return self; | 68 return self; |
| 77 } | 69 } |
| 78 | 70 |
| 79 - (id<CRWSSLStatusUpdaterDelegate>)delegate { | 71 - (id<CRWSSLStatusUpdaterDelegate>)delegate { |
| 80 return _delegate.get(); | 72 return _delegate.get(); |
| 81 } | 73 } |
| 82 | 74 |
| 83 - (void)setDelegate:(id<CRWSSLStatusUpdaterDelegate>)delegate { | 75 - (void)setDelegate:(id<CRWSSLStatusUpdaterDelegate>)delegate { |
| 84 _delegate.reset(delegate); | 76 _delegate.reset(delegate); |
| 85 } | 77 } |
| 86 | 78 |
| 87 - (void)updateSSLStatusForNavigationItem:(web::NavigationItem*)item | 79 - (void)updateSSLStatusForNavigationItem:(web::NavigationItem*)item |
| 88 withCertHost:(NSString*)host | 80 withCertHost:(NSString*)host |
| 89 trust:(ScopedCFTypeRef<SecTrustRef>)trust | 81 trust:(ScopedCFTypeRef<SecTrustRef>)trust |
| 90 hasOnlySecureContent:(BOOL)hasOnlySecureContent { | 82 hasOnlySecureContent:(BOOL)hasOnlySecureContent { |
| 91 web::SSLStatus previousSSLStatus = item->GetSSL(); | 83 web::SSLStatus previousSSLStatus = item->GetSSL(); |
| 92 | 84 |
| 93 // Starting from iOS9 WKWebView blocks active mixed content, so if | 85 // Starting from iOS9 WKWebView blocks active mixed content, so if |
| 94 // |hasOnlySecureContent| returns NO it means passive content. | 86 // |hasOnlySecureContent| returns NO it means passive content. |
| 95 item->GetSSL().content_status = | 87 item->GetSSL().content_status = |
| 96 hasOnlySecureContent ? web::SSLStatus::NORMAL_CONTENT | 88 hasOnlySecureContent ? web::SSLStatus::NORMAL_CONTENT |
| 97 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | 89 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; |
| 98 | 90 |
| 99 // Try updating SSLStatus for current NavigationItem asynchronously. | 91 // Try updating SSLStatus for current NavigationItem asynchronously. |
| 100 scoped_refptr<net::X509Certificate> cert; | 92 scoped_refptr<net::X509Certificate> cert; |
| 101 if (item->GetURL().SchemeIsCryptographic()) { | 93 if (item->GetURL().SchemeIsCryptographic()) { |
| 102 cert = web::CreateCertFromTrust(trust); | 94 cert = web::CreateCertFromTrust(trust); |
| 103 if (cert) { | 95 if (cert) { |
| 104 int oldCertID = item->GetSSL().cert_id; | 96 scoped_refptr<net::X509Certificate> oldCert = item->GetSSL().certificate; |
| 105 std::string oldHost = item->GetSSL().cert_status_host; | 97 std::string oldHost = item->GetSSL().cert_status_host; |
| 106 item->GetSSL().cert_id = web::CertStore::GetInstance()->StoreCert( | 98 item->GetSSL().certificate = cert; |
| 107 cert.get(), self.certGroupID); | |
| 108 item->GetSSL().cert_status_host = base::SysNSStringToUTF8(host); | 99 item->GetSSL().cert_status_host = base::SysNSStringToUTF8(host); |
| 109 // Only recompute the SSLStatus information if the certificate or host has | 100 // Only recompute the SSLStatus information if the certificate or host has |
| 110 // since changed. Host can be changed in case of redirect. | 101 // since changed. Host can be changed in case of redirect. |
| 111 if (oldCertID != item->GetSSL().cert_id || | 102 if (!oldCert || !oldCert->Equals(cert.get()) || |
| 112 oldHost != item->GetSSL().cert_status_host) { | 103 oldHost != item->GetSSL().cert_status_host) { |
| 113 // Real SSL status is unknown, reset cert status and security style. | 104 // Real SSL status is unknown, reset cert status and security style. |
| 114 // They will be asynchronously updated in | 105 // They will be asynchronously updated in |
| 115 // |scheduleSSLStatusUpdateUsingTrust:host:|. | 106 // |scheduleSSLStatusUpdateUsingTrust:host:|. |
| 116 item->GetSSL().cert_status = CertStatus(); | 107 item->GetSSL().cert_status = CertStatus(); |
| 117 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; | 108 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; |
| 118 | 109 |
| 119 [self scheduleSSLStatusUpdateUsingTrust:std::move(trust) host:host]; | 110 [self scheduleSSLStatusUpdateUsingTrust:std::move(trust) host:host]; |
| 120 } | 111 } |
| 121 } | 112 } |
| 122 } | 113 } |
| 123 | 114 |
| 124 if (!cert) { | 115 if (!cert) { |
| 125 item->GetSSL().cert_id = 0; | 116 item->GetSSL().certificate = nullptr; |
| 126 if (!item->GetURL().SchemeIsCryptographic()) { | 117 if (!item->GetURL().SchemeIsCryptographic()) { |
| 127 // HTTP or other non-secure connection. | 118 // HTTP or other non-secure connection. |
| 128 item->GetSSL().security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 119 item->GetSSL().security_style = web::SECURITY_STYLE_UNAUTHENTICATED; |
| 129 } else { | 120 } else { |
| 130 // HTTPS, no certificate (this use-case has not been observed). | 121 // HTTPS, no certificate (this use-case has not been observed). |
| 131 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; | 122 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; |
| 132 } | 123 } |
| 133 } | 124 } |
| 134 | 125 |
| 135 if (!previousSSLStatus.Equals(item->GetSSL())) { | 126 if (!previousSSLStatus.Equals(item->GetSSL())) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 147 // The searched item almost always be the last one, so walk backward rather | 138 // The searched item almost always be the last one, so walk backward rather |
| 148 // than forward. | 139 // than forward. |
| 149 for (int i = _navigationManager->GetItemCount() - 1; 0 <= i; i--) { | 140 for (int i = _navigationManager->GetItemCount() - 1; 0 <= i; i--) { |
| 150 web::NavigationItem* item = _navigationManager->GetItemAtIndex(i); | 141 web::NavigationItem* item = _navigationManager->GetItemAtIndex(i); |
| 151 if (item->GetUniqueID() != navigationItemID) | 142 if (item->GetUniqueID() != navigationItemID) |
| 152 continue; | 143 continue; |
| 153 | 144 |
| 154 // NavigationItem's UniqueID is preserved even after redirects, so | 145 // NavigationItem's UniqueID is preserved even after redirects, so |
| 155 // checking that cert and URL match is necessary. | 146 // checking that cert and URL match is necessary. |
| 156 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust)); | 147 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust)); |
| 157 int certID = | |
| 158 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID); | |
| 159 std::string GURLHost = base::SysNSStringToUTF8(host); | 148 std::string GURLHost = base::SysNSStringToUTF8(host); |
| 160 web::SSLStatus& SSLStatus = item->GetSSL(); | 149 web::SSLStatus& SSLStatus = item->GetSSL(); |
| 161 if (item->GetURL().SchemeIsCryptographic() && SSLStatus.cert_id == certID && | 150 if (item->GetURL().SchemeIsCryptographic() && !!SSLStatus.certificate && |
| 151 SSLStatus.certificate->Equals(cert.get()) && |
| 162 item->GetURL().host() == GURLHost) { | 152 item->GetURL().host() == GURLHost) { |
| 163 web::SSLStatus previousSSLStatus = item->GetSSL(); | 153 web::SSLStatus previousSSLStatus = item->GetSSL(); |
| 164 SSLStatus.cert_status = certStatus; | 154 SSLStatus.cert_status = certStatus; |
| 165 SSLStatus.security_style = style; | 155 SSLStatus.security_style = style; |
| 166 if (!previousSSLStatus.Equals(SSLStatus)) { | 156 if (!previousSSLStatus.Equals(SSLStatus)) { |
| 167 [self didChangeSSLStatusForNavigationItem:item]; | 157 [self didChangeSSLStatusForNavigationItem:item]; |
| 168 } | 158 } |
| 169 } | 159 } |
| 170 return; | 160 return; |
| 171 } | 161 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 193 | 183 |
| 194 - (void)didChangeSSLStatusForNavigationItem:(web::NavigationItem*)navItem { | 184 - (void)didChangeSSLStatusForNavigationItem:(web::NavigationItem*)navItem { |
| 195 if ([_delegate respondsToSelector: | 185 if ([_delegate respondsToSelector: |
| 196 @selector(SSLStatusUpdater:didChangeSSLStatusForNavigationItem:)]) { | 186 @selector(SSLStatusUpdater:didChangeSSLStatusForNavigationItem:)]) { |
| 197 [_delegate SSLStatusUpdater:self | 187 [_delegate SSLStatusUpdater:self |
| 198 didChangeSSLStatusForNavigationItem:navItem]; | 188 didChangeSSLStatusForNavigationItem:navItem]; |
| 199 } | 189 } |
| 200 } | 190 } |
| 201 | 191 |
| 202 @end | 192 @end |
| OLD | NEW |