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

Side by Side Diff: ios/web/net/crw_cert_verification_controller.mm

Issue 2225483002: [ios] Removed CertVerifierBlockAdapter. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Self review Created 4 years, 4 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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_cert_verification_controller.h" 5 #import "ios/web/net/crw_cert_verification_controller.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/ios/block_types.h" 9 #include "base/ios/block_types.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/mac/bind_objc_block.h" 11 #include "base/mac/bind_objc_block.h"
12 #include "base/mac/scoped_block.h"
13 #import "base/memory/ref_counted.h" 12 #import "base/memory/ref_counted.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/rand_util.h"
16 #include "base/strings/sys_string_conversions.h" 13 #include "base/strings/sys_string_conversions.h"
17 #include "base/threading/worker_pool.h" 14 #include "base/threading/worker_pool.h"
18 #include "ios/web/net/cert_verifier_block_adapter.h"
19 #include "ios/web/public/browser_state.h" 15 #include "ios/web/public/browser_state.h"
20 #include "ios/web/public/certificate_policy_cache.h" 16 #include "ios/web/public/certificate_policy_cache.h"
21 #include "ios/web/public/web_thread.h" 17 #include "ios/web/public/web_thread.h"
22 #import "ios/web/web_state/wk_web_view_security_util.h" 18 #import "ios/web/web_state/wk_web_view_security_util.h"
23 #include "net/cert/cert_verify_result.h" 19 #include "net/cert/sec_trust_util.h"
24 #include "net/url_request/url_request_context.h"
25 #include "net/url_request/url_request_context_getter.h"
26
27 namespace {
28
29 // Enum for Web.CertVerifyAgreement UMA metric to report certificate
30 // verification mismatch between SecTrust API and CertVerifier. SecTrust API is
31 // used for making load/no-load decision and CertVerifier is used for getting
32 // the reason of verification failure. It is expected that mismatches will
33 // happen for those 2 approaches (e.g. SecTrust API accepts the cert but
34 // CertVerifier rejects it). This metric helps to understand how common
35 // mismatches are.
36 // Note: This enum is used to back an UMA histogram, and should be treated as
37 // append-only.
38 enum CertVerifyAgreement {
39 // There is no mismach. Both SecTrust API and CertVerifier accepted this cert.
40 CERT_VERIFY_AGREEMENT_ACCEPTED_BY_BOTH = 0,
41 // There is no mismach. Both SecTrust API and CertVerifier rejected this cert.
42 CERT_VERIFY_AGREEMENT_REJECTED_BY_BOTH,
43 // SecTrust API accepted the cert, but CertVerifier rejected it (e.g. MDM cert
44 // or CertVerifier was more strict during verification), this mismach is
45 // expected to be common because of MDM certs.
46 CERT_VERIFY_AGREEMENT_ACCEPTED_ONLY_BY_IOS,
47 // SecTrust API rejected the cert, but CertVerifier accepted it. This mismatch
48 // is expected to be uncommon.
49 CERT_VERIFY_AGREEMENT_ACCEPTED_ONLY_BY_NSS,
50 CERT_VERIFY_AGREEMENT_COUNT,
51 };
52
53 // This class takes ownership of block and releases it on UI thread, even if
54 // |BlockHolder| is destructed on a background thread. On destruction calls its
55 // block with default arguments, if block was not called before. This way
56 // BlockHolder guarantees that block is always called to satisfy API contract
57 // for CRWCertVerificationController (completion handlers are always called).
58 template <class T>
59 class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> {
60 public:
61 // Takes ownership of |block|, which must not be null. On destruction calls
62 // this block with |DefaultArgs|, if block was not called before.
63 // |DefaultArgs| must be passed by value, not by ponter or reference.
64 template <typename... Arguments>
65 BlockHolder(T block, Arguments... DefaultArgs)
66 : block_([block copy]),
67 called_(false),
68 default_block_([^{
69 block(DefaultArgs...);
70 } copy]) {
71 DCHECK(block_);
72 }
73
74 // Calls underlying block with the given variadic arguments.
75 template <typename... Arguments>
76 void call(Arguments... Args) {
77 block_(Args...);
78 called_ = true;
79 }
80
81 private:
82 BlockHolder() = delete;
83 friend class base::RefCountedThreadSafe<BlockHolder>;
84
85 // Finalizes object's destruction on UI thread by calling |default_block| (if
86 // |block| has not been called yet) and releasing all blocks. Must be called
87 // on UI thread.
88 static void Finalize(id block,
89 ProceduralBlock default_block,
90 bool block_was_called) {
91 DCHECK_CURRENTLY_ON(web::WebThread::UI);
92 // By calling default_block, BlockHolder guarantees that block is always
93 // called to satisfy API contract for CRWCertVerificationController
94 // (completion handlers are always called).
95 if (!block_was_called)
96 default_block();
97 [block release];
98 [default_block release];
99 }
100
101 // Releases underlying |block_| on UI thread, calls |default_block_| if
102 // |block_| has not been called yet.
103 ~BlockHolder() {
104 if (web::WebThread::CurrentlyOn(web::WebThread::UI)) {
105 Finalize(block_, default_block_, called_);
106 } else {
107 web::WebThread::PostTask(
108 web::WebThread::UI, FROM_HERE,
109 base::Bind(&BlockHolder::Finalize, block_, default_block_, called_));
110 }
111 }
112
113 T block_;
114 // true if this |block_| has already been called.
115 bool called_;
116 // Called on destruction if |block_| was not called.
117 ProceduralBlock default_block_;
118 };
119
120 typedef scoped_refptr<BlockHolder<web::PolicyDecisionHandler>>
121 PolicyDecisionHandlerHolder;
122
123 } // namespace
124 20
125 @interface CRWCertVerificationController () { 21 @interface CRWCertVerificationController () {
126 // Cert verification object which wraps |net::CertVerifier|. Must be created,
127 // used and destroyed on IO Thread.
128 std::unique_ptr<web::CertVerifierBlockAdapter> _certVerifier;
129
130 // URLRequestContextGetter for obtaining net layer objects.
131 net::URLRequestContextGetter* _contextGetter;
132
133 // Used to remember user exceptions to invalid certs. 22 // Used to remember user exceptions to invalid certs.
134 scoped_refptr<web::CertificatePolicyCache> _certPolicyCache; 23 scoped_refptr<web::CertificatePolicyCache> _certPolicyCache;
135 } 24 }
136 25
137 // Cert verification flags. Must be used on IO Thread. 26 // Returns cert status for the given |trust|.
138 @property(nonatomic, readonly) int certVerifyFlags; 27 - (net::CertStatus)certStatusFromTrustResult:(SecTrustResultType)trustResult
139 28 serverTrust:
140 // Returns YES if CertVerifier should be run (even if SecTrust API considers 29 (base::ScopedCFTypeRef<SecTrustRef>)trust;
141 // cert as valid) and Web.CertVerifyAgreement UMA metric should be reported.
142 // The result of this method is random and nondeterministic.
143 - (BOOL)shouldReportCertVerifyAgreement;
144
145 // Reports Web.CertVerifyAgreement UMA metric.
146 - (void)reportUMAForCertVerifyAgreement:(CertVerifyAgreement)agreement;
147
148 // Creates _certVerifier object on IO thread.
149 - (void)createCertVerifier;
150 30
151 // Decides the policy for the given |trust| which was rejected by iOS and the 31 // Decides the policy for the given |trust| which was rejected by iOS and the
152 // given |host| and calls |handler| on completion. 32 // given |host| and calls |handler| on completion. Must be called on UI thread.
33 // |handler| can not be null and will be called on UI thread.
153 - (void) 34 - (void)
154 decideLoadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult 35 decideLoadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult
155 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 36 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
156 host:(NSString*)host 37 host:(NSString*)host
157 completionHandler:(PolicyDecisionHandlerHolder)handler; 38 completionHandler:(web::PolicyDecisionHandler)handler;
158
159 // Decides the policy for the given |trust| which was accepted by iOS and the
160 // given |host| and calls |handler| on completion.
161 - (void)
162 decideLoadPolicyForAcceptedTrustResult:(SecTrustResultType)trustResult
163 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
164 host:(NSString*)host
165 completionHandler:(PolicyDecisionHandlerHolder)handler;
166
167 // Verifies the given |cert| for the given |host| using |net::CertVerifier| and
168 // calls |completionHandler| on completion. This method can be called on any
169 // thread. |completionHandler| cannot be null and will be called asynchronously
170 // on IO thread or will never be called if IO task can't start or complete.
171 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert
172 forHost:(NSString*)host
173 completionHandler:(void (^)(net::CertVerifyResult))completionHandler;
174 39
175 // Verifies the given |trust| using SecTrustRef API. |completionHandler| cannot 40 // Verifies the given |trust| using SecTrustRef API. |completionHandler| cannot
176 // be null and will be either called asynchronously on Worker thread or will 41 // be null and will be called on UI thread or never be called if the worker task
177 // never be called if the worker task can't start or complete. 42 // can't start or complete. Must be called on UI thread.
178 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 43 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
179 completionHandler:(void (^)(SecTrustResultType))completionHandler; 44 completionHandler:(void (^)(SecTrustResultType))completionHandler;
180 45
181 // Returns cert accept policy for the given SecTrust result. |trustResult| must 46 // Returns cert accept policy for the given SecTrust result. |trustResult| must
182 // not be for a valid cert. Must be called on IO thread. 47 // not be for a valid cert. Must be called on IO thread.
183 - (web::CertAcceptPolicy) 48 - (web::CertAcceptPolicy)
184 loadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult 49 loadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult
185 certVerifierResult:(net::CertVerifyResult)certVerifierResult 50 certStatus:(net::CertStatus)certStatus
186 serverTrust:(SecTrustRef)trust 51 serverTrust:(SecTrustRef)trust
187 host:(NSString*)host; 52 host:(NSString*)host;
188 53
189 @end 54 @end
190 55
191 @implementation CRWCertVerificationController 56 @implementation CRWCertVerificationController
192 57
193 #pragma mark - Superclass
194
195 - (void)dealloc {
196 DCHECK(!_certVerifier);
197 [super dealloc];
198 }
199
200 #pragma mark - Public 58 #pragma mark - Public
201 59
202 - (instancetype)init { 60 - (instancetype)init {
203 NOTREACHED(); 61 NOTREACHED();
204 return nil; 62 return nil;
205 } 63 }
206 64
207 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState { 65 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
208 DCHECK(browserState); 66 DCHECK(browserState);
209 DCHECK_CURRENTLY_ON(web::WebThread::UI); 67 DCHECK_CURRENTLY_ON(web::WebThread::UI);
210 self = [super init]; 68 self = [super init];
211 if (self) { 69 if (self) {
212 _contextGetter = browserState->GetRequestContext();
213 DCHECK(_contextGetter);
214 _certPolicyCache = 70 _certPolicyCache =
215 web::BrowserState::GetCertificatePolicyCache(browserState); 71 web::BrowserState::GetCertificatePolicyCache(browserState);
216
217 [self createCertVerifier];
218 } 72 }
219 return self; 73 return self;
220 } 74 }
221 75
222 - (void)decideLoadPolicyForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 76 - (void)decideLoadPolicyForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
223 host:(NSString*)host 77 host:(NSString*)host
224 completionHandler:(web::PolicyDecisionHandler)completionHandler { 78 completionHandler:(web::PolicyDecisionHandler)completionHandler {
225 DCHECK_CURRENTLY_ON(web::WebThread::UI); 79 DCHECK_CURRENTLY_ON(web::WebThread::UI);
226 // completionHandler of |verifyCert:forHost:completionHandler:| is called on 80 DCHECK(completionHandler);
227 // IO thread and then bounces back to UI thread. As a result all objects 81
228 // captured by completionHandler may be released on either UI or IO thread. 82 [self verifyTrust:trust completionHandler:^(SecTrustResultType trustResult) {
229 // Since |completionHandler| can potentially capture multiple thread unsafe 83 DCHECK_CURRENTLY_ON(web::WebThread::UI);
230 // objects (like Web Controller) |completionHandler| itself should never be 84 if (web::GetSecurityStyleFromTrustResult(trustResult) ==
231 // released on background thread and |BlockHolder| ensures that. 85 web::SECURITY_STYLE_AUTHENTICATED) {
232 __block PolicyDecisionHandlerHolder handlerHolder( 86 completionHandler(web::CERT_ACCEPT_POLICY_ALLOW, net::CertStatus());
233 new BlockHolder<web::PolicyDecisionHandler>( 87 return;
234 completionHandler, web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR, 88 }
235 net::CertStatus())); 89 [self decideLoadPolicyForRejectedTrustResult:trustResult
236 [self verifyTrust:trust 90 serverTrust:trust
237 completionHandler:^(SecTrustResultType trustResult) { 91 host:host
238 if (web::GetSecurityStyleFromTrustResult(trustResult) == 92 completionHandler:completionHandler];
239 web::SECURITY_STYLE_AUTHENTICATED) { 93 }];
240 [self decideLoadPolicyForAcceptedTrustResult:trustResult
241 serverTrust:trust
242 host:host
243 completionHandler:handlerHolder];
244 } else {
245 [self decideLoadPolicyForRejectedTrustResult:trustResult
246 serverTrust:trust
247 host:host
248 completionHandler:handlerHolder];
249 }
250 }];
251 } 94 }
252 95
253 - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 96 - (void)querySSLStatusForTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
254 host:(NSString*)host 97 host:(NSString*)host
255 completionHandler:(web::StatusQueryHandler)completionHandler { 98 completionHandler:(web::StatusQueryHandler)completionHandler {
256 DCHECK_CURRENTLY_ON(web::WebThread::UI); 99 DCHECK_CURRENTLY_ON(web::WebThread::UI);
100 DCHECK(completionHandler);
257 101
258 // The completion handlers of |verifyCert:forHost:completionHandler:| and 102 [self verifyTrust:trust completionHandler:^(SecTrustResultType trustResult) {
259 // |verifyTrust:completionHandler:| will be deallocated on background thread. 103 web::SecurityStyle securityStyle =
260 // |completionHandler| itself should never be released on background thread 104 web::GetSecurityStyleFromTrustResult(trustResult);
261 // and |BlockHolder| ensures that.
262 __block scoped_refptr<BlockHolder<web::StatusQueryHandler>> handlerHolder(
263 new BlockHolder<web::StatusQueryHandler>(
264 completionHandler, web::SECURITY_STYLE_UNKNOWN, net::CertStatus()));
265 [self verifyTrust:trust
266 completionHandler:^(SecTrustResultType trustResult) {
267 web::SecurityStyle securityStyle =
268 web::GetSecurityStyleFromTrustResult(trustResult);
269 if (securityStyle == web::SECURITY_STYLE_AUTHENTICATED) {
270 // SecTrust API considers this cert as valid.
271 dispatch_async(dispatch_get_main_queue(), ^{
272 handlerHolder->call(securityStyle, net::CertStatus());
273 });
274 return;
275 }
276 105
277 // Retrieve the net::CertStatus for invalid certificates to determine 106 net::CertStatus certStatus =
278 // the rejection reason, it is possible that rejection reason could not 107 [self certStatusFromTrustResult:trustResult serverTrust:trust];
279 // be determined and |cert_status| will be empty. 108 completionHandler(securityStyle, certStatus);
280 scoped_refptr<net::X509Certificate> cert( 109 }];
281 web::CreateCertFromTrust(trust));
282 [self verifyCert:cert
283 forHost:host
284 completionHandler:^(net::CertVerifyResult certVerifierResult) {
285 dispatch_async(dispatch_get_main_queue(), ^{
286 handlerHolder->call(securityStyle,
287 certVerifierResult.cert_status);
288 });
289 }];
290 }];
291 } 110 }
292 111
293 - (void)allowCert:(scoped_refptr<net::X509Certificate>)cert 112 - (void)allowCert:(scoped_refptr<net::X509Certificate>)cert
294 forHost:(NSString*)host 113 forHost:(NSString*)host
295 status:(net::CertStatus)status { 114 status:(net::CertStatus)status {
296 DCHECK_CURRENTLY_ON(web::WebThread::UI); 115 DCHECK_CURRENTLY_ON(web::WebThread::UI);
297 // Store user decisions with the leaf cert, ignoring any intermediates. 116 // Store user decisions with the leaf cert, ignoring any intermediates.
298 // This is because WKWebView returns the verified certificate chain in 117 // This is because WKWebView returns the verified certificate chain in
299 // |webView:didReceiveAuthenticationChallenge:completionHandler:|, 118 // |webView:didReceiveAuthenticationChallenge:completionHandler:|,
300 // but the server-supplied chain in 119 // but the server-supplied chain in
301 // |webView:didFailProvisionalNavigation:withError:|. 120 // |webView:didFailProvisionalNavigation:withError:|.
302 if (!cert->GetIntermediateCertificates().empty()) { 121 if (!cert->GetIntermediateCertificates().empty()) {
303 cert = net::X509Certificate::CreateFromHandle( 122 cert = net::X509Certificate::CreateFromHandle(
304 cert->os_cert_handle(), net::X509Certificate::OSCertHandles()); 123 cert->os_cert_handle(), net::X509Certificate::OSCertHandles());
305 } 124 }
306 DCHECK(cert->GetIntermediateCertificates().empty()); 125 DCHECK(cert->GetIntermediateCertificates().empty());
307 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ 126 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
308 _certPolicyCache->AllowCertForHost( 127 _certPolicyCache->AllowCertForHost(
309 cert.get(), base::SysNSStringToUTF8(host), status); 128 cert.get(), base::SysNSStringToUTF8(host), status);
310 })); 129 }));
311 } 130 }
312 131
313 - (void)shutDown {
314 DCHECK_CURRENTLY_ON(web::WebThread::UI);
315 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
316 // This block captures |self| delaying its deallocation and causing dealloc
317 // to happen on either IO or UI thread (which is fine for this class).
318 _certVerifier.reset();
319 }));
320 }
321
322 #pragma mark - Private 132 #pragma mark - Private
323 133
324 - (int)certVerifyFlags { 134 - (net::CertStatus)certStatusFromTrustResult:(SecTrustResultType)trustResult
325 DCHECK(web::WebThread::CurrentlyOn(web::WebThread::IO)); 135 serverTrust:
326 DCHECK(_contextGetter); 136 (base::ScopedCFTypeRef<SecTrustRef>)trust {
327 // |net::URLRequestContextGetter| lifetime is expected to be at least the same 137 web::SecurityStyle securityStyle =
328 // or longer than |BrowserState| lifetime. 138 web::GetSecurityStyleFromTrustResult(trustResult);
329 net::URLRequestContext* context = _contextGetter->GetURLRequestContext(); 139 if (securityStyle == web::SECURITY_STYLE_AUTHENTICATED)
330 DCHECK(context); 140 return net::CertStatus();
331 net::SSLConfigService* SSLConfigService = context->ssl_config_service();
332 DCHECK(SSLConfigService);
333 net::SSLConfig config;
334 SSLConfigService->GetSSLConfig(&config);
335 return config.GetCertVerifyFlags();
336 }
337 141
338 - (BOOL)shouldReportCertVerifyAgreement { 142 if (trustResult == kSecTrustResultDeny)
339 // Cert verification is an expensive operation. Since extra verification will 143 return net::CERT_STATUS_AUTHORITY_INVALID;
340 // be used only for UMA reporting purposes, do that only for 1% of cases.
341 return base::RandGenerator(100) == 0;
342 }
343 144
344 - (void)reportUMAForCertVerifyAgreement:(CertVerifyAgreement)agreement { 145 net::CertStatus certStatus = net::GetCertFailureStatusFromTrust(trust);
345 UMA_HISTOGRAM_ENUMERATION("Web.CertVerifyAgreement", agreement, 146 if (!net::IsCertStatusError(certStatus)) {
346 CERT_VERIFY_AGREEMENT_COUNT); 147 // |cert_status| must not be no-error if SecTrust API considers the
347 } 148 // cert as invalid. Otherwise there will be issues with errors
348 149 // reporting and recovery.
349 - (void)createCertVerifier { 150 certStatus = net::CERT_STATUS_INVALID;
350 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ 151 }
351 net::URLRequestContext* context = _contextGetter->GetURLRequestContext(); 152 return certStatus;
352 _certVerifier.reset(new web::CertVerifierBlockAdapter(
353 context->cert_verifier(), context->net_log()));
354 }));
355 } 153 }
356 154
357 - (void) 155 - (void)
358 decideLoadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult 156 decideLoadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult
359 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 157 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
360 host:(NSString*)host 158 host:(NSString*)host
361 completionHandler:(PolicyDecisionHandlerHolder)handler { 159 completionHandler:(web::PolicyDecisionHandler)handler {
362 // SecTrust API considers this cert as invalid. Check the reason and 160 DCHECK_CURRENTLY_ON(web::WebThread::UI);
363 // whether or not user has decided to proceed with this bad cert. 161 DCHECK(handler);
364 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust)); 162 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
365 [self verifyCert:cert 163 net::CertStatus certStatus =
366 forHost:host 164 [self certStatusFromTrustResult:trustResult serverTrust:trust];
367 completionHandler:^(net::CertVerifyResult certVerifierResult) {
368 if (!net::IsCertStatusError(certVerifierResult.cert_status)) {
369 // |cert_status| must not be no-error if SecTrust API considers the
370 // cert as invalid. Otherwise there will be issues with errors
371 // reporting and recovery.
372 certVerifierResult.cert_status = net::CERT_STATUS_INVALID;
373 }
374 165
375 web::CertAcceptPolicy policy = 166 web::CertAcceptPolicy policy =
376 [self loadPolicyForRejectedTrustResult:trustResult 167 [self loadPolicyForRejectedTrustResult:trustResult
377 certVerifierResult:certVerifierResult 168 certStatus:certStatus
378 serverTrust:trust.get() 169 serverTrust:trust.get()
379 host:host]; 170 host:host];
380 171
381 dispatch_async(dispatch_get_main_queue(), ^{ 172 dispatch_async(dispatch_get_main_queue(), ^{
382 if ([self shouldReportCertVerifyAgreement]) { 173 handler(policy, certStatus);
383 CertVerifyAgreement agreement =
384 net::IsCertStatusError(certVerifierResult.cert_status)
385 ? CERT_VERIFY_AGREEMENT_REJECTED_BY_BOTH
386 : CERT_VERIFY_AGREEMENT_ACCEPTED_ONLY_BY_NSS;
387 [self reportUMAForCertVerifyAgreement:agreement];
388 }
389 handler->call(policy, certVerifierResult.cert_status);
390 });
391 }];
392 }
393
394 - (void)
395 decideLoadPolicyForAcceptedTrustResult:(SecTrustResultType)trustResult
396 serverTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
397 host:(NSString*)host
398 completionHandler:(PolicyDecisionHandlerHolder)handler {
399 // SecTrust API considers this cert as valid.
400 dispatch_async(dispatch_get_main_queue(), ^{
401 handler->call(web::CERT_ACCEPT_POLICY_ALLOW, net::CertStatus());
402 });
403
404 if ([self shouldReportCertVerifyAgreement]) {
405 // Execute CertVerifier::Verify to collect CertVerifyAgreement UMA.
406 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromTrust(trust));
407 [self verifyCert:cert
408 forHost:host
409 completionHandler:^(net::CertVerifyResult certVerifierResult) {
410 // SecTrust API accepted this cert and |PolicyDecisionHandler| has
411 // been called already. |CertVerifier| verification is executed only
412 // to collect CertVerifyAgreement UMA.
413 dispatch_async(dispatch_get_main_queue(), ^{
414 CertVerifyAgreement agreement =
415 net::IsCertStatusError(certVerifierResult.cert_status)
416 ? CERT_VERIFY_AGREEMENT_ACCEPTED_ONLY_BY_IOS
417 : CERT_VERIFY_AGREEMENT_ACCEPTED_BY_BOTH;
418 [self reportUMAForCertVerifyAgreement:agreement];
419 });
420 }];
421 }
422 }
423
424 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert
425 forHost:(NSString*)host
426 completionHandler:(void (^)(net::CertVerifyResult))completionHandler {
427 DCHECK(completionHandler);
428 __block scoped_refptr<net::X509Certificate> blockCert = cert;
429 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
430 // WeakNSObject does not work across different threads, hence this block
431 // retains self.
432 if (!_certVerifier) {
433 completionHandler(net::CertVerifyResult());
434 return;
435 }
436
437 web::CertVerifierBlockAdapter::Params params(std::move(blockCert),
438 base::SysNSStringToUTF8(host));
439 params.flags = self.certVerifyFlags;
440 // OCSP response is not provided by iOS API.
441 // CRLSets are not used, as the OS is used to make load/no-load
442 // decisions, not the CertVerifier.
443 _certVerifier->Verify(params, ^(net::CertVerifyResult result, int) {
444 completionHandler(result);
445 }); 174 });
446 })); 175 }));
447 } 176 }
448 177
449 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust 178 - (void)verifyTrust:(base::ScopedCFTypeRef<SecTrustRef>)trust
450 completionHandler:(void (^)(SecTrustResultType))completionHandler { 179 completionHandler:(void (^)(SecTrustResultType))completionHandler {
180 DCHECK_CURRENTLY_ON(web::WebThread::UI);
451 DCHECK(completionHandler); 181 DCHECK(completionHandler);
452 // SecTrustEvaluate performs trust evaluation synchronously, possibly making 182 // SecTrustEvaluate performs trust evaluation synchronously, possibly making
453 // network requests. The UI thread should not be blocked by that operation. 183 // network requests. The UI thread should not be blocked by that operation.
454 base::WorkerPool::PostTask(FROM_HERE, base::BindBlock(^{ 184 base::WorkerPool::PostTask(FROM_HERE, base::BindBlock(^{
455 SecTrustResultType trustResult = kSecTrustResultInvalid; 185 SecTrustResultType trustResult = kSecTrustResultInvalid;
456 if (SecTrustEvaluate(trust.get(), &trustResult) != errSecSuccess) { 186 if (SecTrustEvaluate(trust.get(), &trustResult) != errSecSuccess) {
457 trustResult = kSecTrustResultInvalid; 187 trustResult = kSecTrustResultInvalid;
458 } 188 }
459 completionHandler(trustResult); 189 dispatch_async(dispatch_get_main_queue(), ^{
190 completionHandler(trustResult);
191 });
460 }), false /* task_is_slow */); 192 }), false /* task_is_slow */);
461 } 193 }
462 194
463 - (web::CertAcceptPolicy) 195 - (web::CertAcceptPolicy)
464 loadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult 196 loadPolicyForRejectedTrustResult:(SecTrustResultType)trustResult
465 certVerifierResult:(net::CertVerifyResult)certVerifierResult 197 certStatus:(net::CertStatus)certStatus
466 serverTrust:(SecTrustRef)trust 198 serverTrust:(SecTrustRef)trust
467 host:(NSString*)host { 199 host:(NSString*)host {
468 DCHECK_CURRENTLY_ON(web::WebThread::IO); 200 DCHECK_CURRENTLY_ON(web::WebThread::IO);
469 DCHECK_NE(web::SECURITY_STYLE_AUTHENTICATED, 201 DCHECK_NE(web::SECURITY_STYLE_AUTHENTICATED,
470 web::GetSecurityStyleFromTrustResult(trustResult)); 202 web::GetSecurityStyleFromTrustResult(trustResult));
471 203
472 if (trustResult != kSecTrustResultRecoverableTrustFailure || 204 if (trustResult != kSecTrustResultRecoverableTrustFailure ||
473 SecTrustGetCertificateCount(trust) == 0) { 205 SecTrustGetCertificateCount(trust) == 0) {
474 // Trust result is not recoverable or leaf cert is missing. 206 // Trust result is not recoverable or leaf cert is missing.
475 return web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR; 207 return web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR;
476 } 208 }
477 209
478 // Check if user has decided to proceed with this bad cert. 210 // Check if user has decided to proceed with this bad cert.
479 scoped_refptr<net::X509Certificate> leafCert = 211 scoped_refptr<net::X509Certificate> leafCert =
480 net::X509Certificate::CreateFromHandle( 212 net::X509Certificate::CreateFromHandle(
481 SecTrustGetCertificateAtIndex(trust, 0), 213 SecTrustGetCertificateAtIndex(trust, 0),
482 net::X509Certificate::OSCertHandles()); 214 net::X509Certificate::OSCertHandles());
483 215
484 web::CertPolicy::Judgment judgment = _certPolicyCache->QueryPolicy( 216 web::CertPolicy::Judgment judgment = _certPolicyCache->QueryPolicy(
485 leafCert.get(), base::SysNSStringToUTF8(host), 217 leafCert.get(), base::SysNSStringToUTF8(host), certStatus);
486 certVerifierResult.cert_status);
487 218
488 return (judgment == web::CertPolicy::ALLOWED) 219 return (judgment == web::CertPolicy::ALLOWED)
489 ? web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER 220 ? web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_ACCEPTED_BY_USER
490 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_UNDECIDED_BY_USER; 221 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_UNDECIDED_BY_USER;
491 } 222 }
492 223
493 @end 224 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698