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

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

Issue 1230033005: WKWebView: Added cert verification API to web controller. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated comment (s/used/user); Created 5 years, 3 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/web/net/crw_cert_verification_controller.h"
6
7 #include "base/mac/bind_objc_block.h"
8 #import "base/memory/ref_counted.h"
9 #import "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "ios/web/net/cert_verifier_block_adapter.h"
12 #include "ios/web/public/browser_state.h"
13 #include "ios/web/public/web_thread.h"
14 #include "net/cert/cert_verify_result.h"
15 #include "net/ssl/ssl_config_service.h"
16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_context_getter.h"
18
19 namespace {
20
21 // This class takes ownership of block and releases it on UI thread, even if
22 // |BlockHolder| is destructed on a background thread.
23 template <class T>
24 class BlockHolder : public base::RefCountedThreadSafe<BlockHolder<T>> {
25 public:
26 // Takes ownership of |block|, which must not be null.
27 explicit BlockHolder(T block) : block_([block copy]) { DCHECK(block_); }
28
29 // Calls underlying block with the given variadic arguments.
30 template <typename... Arguments>
31 void call(Arguments... Args) {
32 block_(Args...);
33 }
34
35 private:
36 BlockHolder() = delete;
37 friend class base::RefCountedThreadSafe<BlockHolder>;
38
39 // Releases the given block, must be called on UI thread.
40 static void ReleaseBlock(id block) {
41 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
42 [block release];
43 }
44
45 // Releases underlying |block_| on UI thread.
46 ~BlockHolder() {
47 if (web::WebThread::CurrentlyOn(web::WebThread::UI)) {
48 ReleaseBlock(block_);
49 } else {
50 web::WebThread::PostTask(web::WebThread::UI, FROM_HERE,
51 base::Bind(&BlockHolder::ReleaseBlock, block_));
52 }
53 }
54
55 T block_;
56 };
57
58 } // namespace
59
60 @interface CRWCertVerificationController () {
61 // Cert verification object which wraps |net::CertVerifier|. Must be created,
62 // used and destroyed on IO Thread.
63 scoped_ptr<web::CertVerifierBlockAdapter> _certVerifier;
64
65 // URLRequestContextGetter for obtaining net layer objects.
66 net::URLRequestContextGetter* _contextGetter;
67 }
68
69 // Cert verification flags. Must be used on IO Thread.
70 @property(nonatomic, readonly) int certVerifyFlags;
71
72 // Creates _certVerifier object on IO thread.
73 - (void)createCertVerifier;
74
75 // Verifies the given |cert| for the given |host| and calls |completionHandler|
76 // on completion. |completionHandler| cannot be null and will be called
77 // synchronously or asynchronously on IO thread.
78 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert
79 forHost:(NSString*)host
80 completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler;
81
82 @end
83
84 @implementation CRWCertVerificationController
85
86 #pragma mark - Superclass
87
88 - (void)dealloc {
89 DCHECK(!_certVerifier);
90 [super dealloc];
91 }
92
93 #pragma mark - Public
94
95 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
96 DCHECK(browserState);
97 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
98 self = [super init];
99 if (self) {
100 _contextGetter = browserState->GetRequestContext();
101 DCHECK(_contextGetter);
102 [self createCertVerifier];
103 }
104 return self;
105 }
106
107 - (void)decidePolicyForCert:(const scoped_refptr<net::X509Certificate>&)cert
108 host:(NSString*)host
109 completionHandler:(web::PolicyDecisionHandler)handler {
110 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
111 // completionHandler of |verifyCert:forHost:completionHandler:| is called on
112 // IO thread and then bounces back to UI thread. As a result all objects
113 // captured by completionHandler may be released on either UI or IO thread.
114 // Since |handler| can potentially capture multiple thread unsafe objects
115 // (like Web Controller) |handler| itself should never be released on
116 // background thread and |BlockHolder| ensures that.
117 __block scoped_refptr<BlockHolder<web::PolicyDecisionHandler>> handlerHolder(
118 new BlockHolder<web::PolicyDecisionHandler>(handler));
119 [self verifyCert:cert
120 forHost:host
121 completionHandler:^(net::CertVerifyResult result, int error) {
122 web::CertAcceptPolicy policy =
123 web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR;
124 if (error == net::OK) {
125 policy = web::CERT_ACCEPT_POLICY_ALLOW;
126 } else if (net::IsCertStatusError(result.cert_status)) {
127 policy = net::IsCertStatusMinorError(result.cert_status)
128 ? web::CERT_ACCEPT_POLICY_ALLOW
129 : web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR;
130 }
131
132 dispatch_async(dispatch_get_main_queue(), ^{
133 handlerHolder->call(policy, result.cert_status);
134 });
135 }];
136 }
137
138 - (void)shutDown {
139 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI);
140 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
141 // This block captures |self| delaying its deallocation and causing dealloc
142 // to happen on either IO or UI thread (which is fine for this class).
143 _certVerifier.reset();
144 }));
145 }
146
147 #pragma mark - Private
148
149 - (int)certVerifyFlags {
150 DCHECK(web::WebThread::CurrentlyOn(web::WebThread::IO));
151 DCHECK(_contextGetter);
152 // |net::URLRequestContextGetter| lifetime is expected to be at least the same
153 // or longer than |BrowserState| lifetime.
154 net::URLRequestContext* context = _contextGetter->GetURLRequestContext();
155 DCHECK(context);
156 net::SSLConfigService* SSLConfigService = context->ssl_config_service();
157 DCHECK(SSLConfigService);
158 net::SSLConfig config;
159 SSLConfigService->GetSSLConfig(&config);
160 return config.GetCertVerifyFlags();
161 }
162
163 - (void)createCertVerifier {
164 web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{
165 net::URLRequestContext* context = _contextGetter->GetURLRequestContext();
166 _certVerifier.reset(new web::CertVerifierBlockAdapter(
167 context->cert_verifier(), context->net_log()));
168 }));
169 }
170
171 - (void)verifyCert:(const scoped_refptr<net::X509Certificate>&)cert
172 forHost:(NSString*)host
173 completionHandler:(void (^)(net::CertVerifyResult, int))completionHandler {
174 DCHECK(completionHandler);
175 __block scoped_refptr<net::X509Certificate> blockCert = cert;
176 web::WebThread::PostTask(
177 web::WebThread::IO, FROM_HERE, base::BindBlock(^{
178 // WeakNSObject does not work across different threads, hence this block
179 // retains self.
180 if (!_certVerifier) {
181 completionHandler(net::CertVerifyResult(), net::ERR_FAILED);
182 return;
183 }
184
185 web::CertVerifierBlockAdapter::Params params(
186 blockCert.Pass(), base::SysNSStringToUTF8(host));
187 params.flags = self.certVerifyFlags;
188 params.crl_set = net::SSLConfigService::GetCRLSet();
189 // OCSP response is not provided by iOS API.
190 _certVerifier->Verify(params, completionHandler);
191 }));
192 }
193
194 @end
OLDNEW
« no previous file with comments | « ios/web/net/crw_cert_verification_controller.h ('k') | ios/web/net/crw_cert_verification_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698