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

Side by Side Diff: net/ocsp/nss_ocsp.cc

Issue 3421039: Revert 60739 (still leaks on ChromiumOS!) - Reland r59972: Eagerly set the IO... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 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 | Annotate | Revision Log
« no previous file with comments | « net/ocsp/nss_ocsp.h ('k') | net/url_request/url_request_context.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 #include "net/ocsp/nss_ocsp.h" 5 #include "net/ocsp/nss_ocsp.h"
6 6
7 #include <certt.h> 7 #include <certt.h>
8 #include <certdb.h> 8 #include <certdb.h>
9 #include <ocsp.h> 9 #include <ocsp.h>
10 #include <nspr.h> 10 #include <nspr.h>
11 #include <nss.h> 11 #include <nss.h>
12 #include <pthread.h>
13 #include <secerr.h> 12 #include <secerr.h>
14 13
15 #include <string> 14 #include <string>
16 15
17 #include "base/basictypes.h"
18 #include "base/compiler_specific.h" 16 #include "base/compiler_specific.h"
19 #include "base/condition_variable.h" 17 #include "base/condition_variable.h"
20 #include "base/histogram.h" 18 #include "base/histogram.h"
21 #include "base/lazy_instance.h"
22 #include "base/lock.h"
23 #include "base/logging.h" 19 #include "base/logging.h"
24 #include "base/message_loop.h" 20 #include "base/message_loop.h"
21 #include "base/singleton.h"
25 #include "base/string_util.h" 22 #include "base/string_util.h"
26 #include "base/stringprintf.h" 23 #include "base/stringprintf.h"
27 #include "base/thread.h" 24 #include "base/thread.h"
28 #include "base/time.h" 25 #include "base/time.h"
29 #include "googleurl/src/gurl.h" 26 #include "googleurl/src/gurl.h"
30 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
31 #include "net/base/load_flags.h" 28 #include "net/base/load_flags.h"
32 #include "net/http/http_request_headers.h" 29 #include "net/http/http_request_headers.h"
33 #include "net/http/http_response_headers.h" 30 #include "net/http/http_response_headers.h"
34 #include "net/url_request/url_request.h" 31 #include "net/url_request/url_request.h"
35 #include "net/url_request/url_request_context.h" 32 #include "net/url_request/url_request_context.h"
36 33
37 namespace { 34 namespace {
38 35
39 // Protects |g_request_context|.
40 pthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER;
41 static URLRequestContext* g_request_context = NULL;
42
43 class OCSPIOLoop : public MessageLoop::DestructionObserver {
44 public:
45 // MessageLoop::DestructionObserver:
46 virtual void WillDestroyCurrentMessageLoop();
47
48 void StartUsing() {
49 AutoLock autolock(lock_);
50 used_ = true;
51 }
52
53 bool used() const {
54 AutoLock autolock(lock_);
55 return used_;
56 }
57
58 // Called from worker thread.
59 void PostTaskToIOLoop(const tracked_objects::Location& from_here, Task* task);
60
61 void EnsureIOLoop();
62
63 private:
64 friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>;
65
66 OCSPIOLoop();
67 ~OCSPIOLoop();
68
69 mutable Lock lock_;
70 bool used_; // Protected by |lock_|.
71 // This should not be modified after |used_|.
72 MessageLoopForIO* io_loop_; // Protected by |lock_|.
73
74 DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop);
75 };
76
77 OCSPIOLoop::OCSPIOLoop()
78 : used_(false),
79 io_loop_(MessageLoopForIO::current()) {
80 DCHECK(io_loop_);
81 io_loop_->AddDestructionObserver(this);
82 }
83
84 OCSPIOLoop::~OCSPIOLoop() {
85 // IO thread was already deleted before the singleton is deleted
86 // in AtExitManager.
87 {
88 AutoLock autolock(lock_);
89 DCHECK(!io_loop_);
90 DCHECK(!used_);
91 }
92
93 pthread_mutex_lock(&g_request_context_lock);
94 DCHECK(!g_request_context);
95 pthread_mutex_unlock(&g_request_context_lock);
96 }
97
98 void OCSPIOLoop::WillDestroyCurrentMessageLoop() {
99 // Prevent the worker thread from trying to access |io_loop_|.
100 {
101 AutoLock autolock(lock_);
102 DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
103 io_loop_ = NULL;
104 used_ = false;
105 }
106
107 pthread_mutex_lock(&g_request_context_lock);
108 g_request_context = NULL;
109 pthread_mutex_unlock(&g_request_context_lock);
110 }
111
112 void OCSPIOLoop::PostTaskToIOLoop(
113 const tracked_objects::Location& from_here, Task* task) {
114 AutoLock autolock(lock_);
115 if (io_loop_)
116 io_loop_->PostTask(from_here, task);
117 }
118
119 void OCSPIOLoop::EnsureIOLoop() {
120 AutoLock autolock(lock_);
121 DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
122 }
123
124 base::LazyInstance<OCSPIOLoop> g_ocsp_io_loop(base::LINKER_INITIALIZED);
125
126 const int kRecvBufferSize = 4096; 36 const int kRecvBufferSize = 4096;
127 37
128 // All OCSP handlers should be called in the context of 38 // All OCSP handlers should be called in the context of
129 // CertVerifier's thread (i.e. worker pool, not on the I/O thread). 39 // CertVerifier's thread (i.e. worker pool, not on the I/O thread).
130 // It supports blocking mode only. 40 // It supports blocking mode only.
131 41
132 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 42 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
133 SEC_HTTP_SERVER_SESSION* pSession); 43 SEC_HTTP_SERVER_SESSION* pSession);
134 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, 44 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,
135 PRPollDesc **pPollDesc); 45 PRPollDesc **pPollDesc);
(...skipping 16 matching lines...) Expand all
152 PRPollDesc** pPollDesc, 62 PRPollDesc** pPollDesc,
153 PRUint16* http_response_code, 63 PRUint16* http_response_code,
154 const char** http_response_content_type, 64 const char** http_response_content_type,
155 const char** http_response_headers, 65 const char** http_response_headers,
156 const char** http_response_data, 66 const char** http_response_data,
157 PRUint32* http_response_data_len); 67 PRUint32* http_response_data_len);
158 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); 68 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request);
159 69
160 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert); 70 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert);
161 71
162 class OCSPNSSInitialization { 72 class OCSPInitSingleton : public MessageLoop::DestructionObserver {
73 public:
74 // Called on IO thread.
75 virtual void WillDestroyCurrentMessageLoop() {
76 AutoLock autolock(lock_);
77 DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
78 io_loop_ = NULL;
79 request_context_ = NULL;
80 };
81
82 // Called from worker thread.
83 void PostTaskToIOLoop(
84 const tracked_objects::Location& from_here, Task* task) {
85 AutoLock autolock(lock_);
86 if (io_loop_)
87 io_loop_->PostTask(from_here, task);
88 }
89
90 // This is static method because it is called before NSS initialization,
91 // that is, before OCSPInitSingleton is initialized.
92 static void set_url_request_context(URLRequestContext* request_context) {
93 request_context_ = request_context;
94 }
95 static URLRequestContext* url_request_context() {
96 return request_context_;
97 }
98
163 private: 99 private:
164 friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; 100 friend struct DefaultSingletonTraits<OCSPInitSingleton>;
165 101
166 OCSPNSSInitialization(); 102 OCSPInitSingleton()
167 ~OCSPNSSInitialization(); 103 : io_loop_(MessageLoopForIO::current()) {
104 DCHECK(io_loop_);
105 io_loop_->AddDestructionObserver(this);
106
107 // NSS calls the functions in the function table to download certificates
108 // or CRLs or talk to OCSP responders over HTTP. These functions must
109 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the
110 // residual error code from an earlier failed function call.
111 client_fcn_.version = 1;
112 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
113 ft->createSessionFcn = OCSPCreateSession;
114 ft->keepAliveSessionFcn = OCSPKeepAliveSession;
115 ft->freeSessionFcn = OCSPFreeSession;
116 ft->createFcn = OCSPCreate;
117 ft->setPostDataFcn = OCSPSetPostData;
118 ft->addHeaderFcn = OCSPAddHeader;
119 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
120 ft->cancelFcn = NULL;
121 ft->freeFcn = OCSPFree;
122 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
123 if (status != SECSuccess) {
124 NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
125 }
126
127 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the
128 // CRLs for Network Solutions Certificate Authority have bad signatures,
129 // which causes certificates issued by that CA to be reported as revoked.
130 // By using OCSP for those certificates, which don't have AIA extensions,
131 // we can work around these bugs. See http://crbug.com/41730.
132 CERT_StringFromCertFcn old_callback = NULL;
133 status = CERT_RegisterAlternateOCSPAIAInfoCallBack(
134 GetAlternateOCSPAIAInfo, &old_callback);
135 if (status == SECSuccess) {
136 DCHECK(!old_callback);
137 } else {
138 NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
139 }
140 }
141
142 virtual ~OCSPInitSingleton() {
143 // IO thread was already deleted before the singleton is deleted
144 // in AtExitManager.
145 AutoLock autolock(lock_);
146 DCHECK(!io_loop_);
147 DCHECK(!request_context_);
148 }
168 149
169 SEC_HttpClientFcn client_fcn_; 150 SEC_HttpClientFcn client_fcn_;
170 151
171 DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization); 152 // |lock_| protects |io_loop_|.
153 Lock lock_;
154 // I/O thread.
155 MessageLoop* io_loop_; // I/O thread
156 // URLRequestContext for OCSP handlers.
157 static URLRequestContext* request_context_;
158
159 DISALLOW_COPY_AND_ASSIGN(OCSPInitSingleton);
172 }; 160 };
173 161
174 OCSPNSSInitialization::OCSPNSSInitialization() { 162 URLRequestContext* OCSPInitSingleton::request_context_ = NULL;
175 // NSS calls the functions in the function table to download certificates
176 // or CRLs or talk to OCSP responders over HTTP. These functions must
177 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the
178 // residual error code from an earlier failed function call.
179 client_fcn_.version = 1;
180 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
181 ft->createSessionFcn = OCSPCreateSession;
182 ft->keepAliveSessionFcn = OCSPKeepAliveSession;
183 ft->freeSessionFcn = OCSPFreeSession;
184 ft->createFcn = OCSPCreate;
185 ft->setPostDataFcn = OCSPSetPostData;
186 ft->addHeaderFcn = OCSPAddHeader;
187 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
188 ft->cancelFcn = NULL;
189 ft->freeFcn = OCSPFree;
190 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
191 if (status != SECSuccess) {
192 NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
193 }
194
195 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the
196 // CRLs for Network Solutions Certificate Authority have bad signatures,
197 // which causes certificates issued by that CA to be reported as revoked.
198 // By using OCSP for those certificates, which don't have AIA extensions,
199 // we can work around these bugs. See http://crbug.com/41730.
200 CERT_StringFromCertFcn old_callback = NULL;
201 status = CERT_RegisterAlternateOCSPAIAInfoCallBack(
202 GetAlternateOCSPAIAInfo, &old_callback);
203 if (status == SECSuccess) {
204 DCHECK(!old_callback);
205 } else {
206 NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
207 }
208 }
209
210 OCSPNSSInitialization::~OCSPNSSInitialization() {}
211
212 base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization(
213 base::LINKER_INITIALIZED);
214 163
215 // Concrete class for SEC_HTTP_REQUEST_SESSION. 164 // Concrete class for SEC_HTTP_REQUEST_SESSION.
216 // Public methods except virtual methods of URLRequest::Delegate (On* methods) 165 // Public methods except virtual methods of URLRequest::Delegate (On* methods)
217 // run on certificate verifier thread (worker thread). 166 // run on certificate verifier thread (worker thread).
218 // Virtual methods of URLRequest::Delegate and private methods run 167 // Virtual methods of URLRequest::Delegate and private methods run
219 // on IO thread. 168 // on IO thread.
220 class OCSPRequestSession 169 class OCSPRequestSession
221 : public base::RefCountedThreadSafe<OCSPRequestSession>, 170 : public base::RefCountedThreadSafe<OCSPRequestSession>,
222 public URLRequest::Delegate, 171 public URLRequest::Delegate,
223 public MessageLoop::DestructionObserver { 172 public MessageLoop::DestructionObserver {
(...skipping 20 matching lines...) Expand all
244 void AddHeader(const char* http_header_name, const char* http_header_value) { 193 void AddHeader(const char* http_header_name, const char* http_header_value) {
245 extra_request_headers_.SetHeader(http_header_name, 194 extra_request_headers_.SetHeader(http_header_name,
246 http_header_value); 195 http_header_value);
247 } 196 }
248 197
249 void Start() { 198 void Start() {
250 // At this point, it runs on worker thread. 199 // At this point, it runs on worker thread.
251 // |io_loop_| was initialized to be NULL in constructor, and 200 // |io_loop_| was initialized to be NULL in constructor, and
252 // set only in StartURLRequest, so no need to lock |lock_| here. 201 // set only in StartURLRequest, so no need to lock |lock_| here.
253 DCHECK(!io_loop_); 202 DCHECK(!io_loop_);
254 g_ocsp_io_loop.Get().PostTaskToIOLoop( 203 Singleton<OCSPInitSingleton>()->PostTaskToIOLoop(
255 FROM_HERE, 204 FROM_HERE,
256 NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest)); 205 NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest));
257 } 206 }
258 207
259 bool Started() const { 208 bool Started() const {
260 return request_ != NULL; 209 return request_ != NULL;
261 } 210 }
262 211
263 void Cancel() { 212 void Cancel() {
264 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. 213 // IO thread may set |io_loop_| to NULL, so protect by |lock_|.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 // Must call this method while holding |lock_|. 332 // Must call this method while holding |lock_|.
384 void CancelLocked() { 333 void CancelLocked() {
385 lock_.AssertAcquired(); 334 lock_.AssertAcquired();
386 if (io_loop_) { 335 if (io_loop_) {
387 io_loop_->PostTask( 336 io_loop_->PostTask(
388 FROM_HERE, 337 FROM_HERE,
389 NewRunnableMethod(this, &OCSPRequestSession::CancelURLRequest)); 338 NewRunnableMethod(this, &OCSPRequestSession::CancelURLRequest));
390 } 339 }
391 } 340 }
392 341
393 // Runs on |g_ocsp_io_loop|'s IO loop.
394 void StartURLRequest() { 342 void StartURLRequest() {
395 DCHECK(!request_); 343 DCHECK(!request_);
396 344
397 pthread_mutex_lock(&g_request_context_lock); 345 URLRequestContext* url_request_context =
398 URLRequestContext* url_request_context = g_request_context; 346 OCSPInitSingleton::url_request_context();
399 pthread_mutex_unlock(&g_request_context_lock);
400
401 if (url_request_context == NULL) 347 if (url_request_context == NULL)
402 return; 348 return;
403 349
404 { 350 {
405 AutoLock autolock(lock_); 351 AutoLock autolock(lock_);
406 DCHECK(!io_loop_); 352 DCHECK(!io_loop_);
407 io_loop_ = MessageLoopForIO::current(); 353 io_loop_ = MessageLoopForIO::current();
408 io_loop_->AddDestructionObserver(this); 354 io_loop_->AddDestructionObserver(this);
409 } 355 }
410 356
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); 469 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession);
524 }; 470 };
525 471
526 472
527 // OCSP Http Client functions. 473 // OCSP Http Client functions.
528 // Our Http Client functions operate in blocking mode. 474 // Our Http Client functions operate in blocking mode.
529 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 475 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
530 SEC_HTTP_SERVER_SESSION* pSession) { 476 SEC_HTTP_SERVER_SESSION* pSession) {
531 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum; 477 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum;
532 DCHECK(!MessageLoop::current()); 478 DCHECK(!MessageLoop::current());
533 pthread_mutex_lock(&g_request_context_lock); 479 if (OCSPInitSingleton::url_request_context() == NULL) {
534 URLRequestContext* request_context = g_request_context;
535 pthread_mutex_unlock(&g_request_context_lock);
536 if (request_context == NULL) {
537 LOG(ERROR) << "No URLRequestContext for OCSP handler."; 480 LOG(ERROR) << "No URLRequestContext for OCSP handler.";
538 // The application failed to call SetURLRequestContextForOCSP, so we 481 // The application failed to call SetURLRequestContextForOCSP, so we
539 // can't create and use URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an 482 // can't create and use URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an
540 // accurate error code for this error condition, but is close enough. 483 // accurate error code for this error condition, but is close enough.
541 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 484 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
542 return SECFailure; 485 return SECFailure;
543 } 486 }
544 *pSession = new OCSPServerSession(host, portnum); 487 *pSession = new OCSPServerSession(host, portnum);
545 return SECSuccess; 488 return SECSuccess;
546 } 489 }
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 } 776 }
834 } 777 }
835 778
836 return NULL; 779 return NULL;
837 } 780 }
838 781
839 } // anonymous namespace 782 } // anonymous namespace
840 783
841 namespace net { 784 namespace net {
842 785
843 void SetMessageLoopForOCSP() {
844 // Must have a MessageLoopForIO.
845 DCHECK(MessageLoopForIO::current());
846
847 bool used = g_ocsp_io_loop.Get().used();
848
849 // Should not be called when g_ocsp_io_loop has already been used.
850 DCHECK(!used);
851 }
852
853 void EnsureOCSPInit() { 786 void EnsureOCSPInit() {
854 g_ocsp_io_loop.Get().StartUsing(); 787 Singleton<OCSPInitSingleton>::get();
855 g_ocsp_nss_initialization.Get();
856 } 788 }
857 789
858 // This function would be called before NSS initialization. 790 // This function would be called before NSS initialization.
859 void SetURLRequestContextForOCSP(URLRequestContext* request_context) { 791 void SetURLRequestContextForOCSP(URLRequestContext* request_context) {
860 pthread_mutex_lock(&g_request_context_lock); 792 OCSPInitSingleton::set_url_request_context(request_context);
861 if (request_context) {
862 DCHECK(request_context->is_main());
863 DCHECK(!g_request_context);
864 } else {
865 DCHECK(g_request_context);
866 }
867 g_request_context = request_context;
868 pthread_mutex_unlock(&g_request_context_lock);
869 } 793 }
870 794
871 URLRequestContext* GetURLRequestContextForOCSP() { 795 URLRequestContext* GetURLRequestContextForOCSP() {
872 pthread_mutex_lock(&g_request_context_lock); 796 return OCSPInitSingleton::url_request_context();
873 URLRequestContext* request_context = g_request_context;
874 pthread_mutex_unlock(&g_request_context_lock);
875 DCHECK(request_context->is_main());
876 return request_context;
877 } 797 }
878 798
879 } // namespace net 799 } // namespace net
OLDNEW
« no previous file with comments | « net/ocsp/nss_ocsp.h ('k') | net/url_request/url_request_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698