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 |