/security/manager/ssl/src/nsNSSCallbacks.cpp

http://github.com/zpao/v8monkey · C++ · 1153 lines · 854 code · 185 blank · 114 comment · 140 complexity · c063312ec8d1cca643548c2859690fc7 MD5 · raw file

  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. *
  3. * ***** BEGIN LICENSE BLOCK *****
  4. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is mozilla.org code.
  17. *
  18. * The Initial Developer of the Original Code is
  19. * Netscape Communications Corporation.
  20. * Portions created by the Initial Developer are Copyright (C) 1998
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. * Brian Ryner <bryner@brianryner.com>
  25. * Terry Hayes <thayes@netscape.com>
  26. * Kai Engert <kengert@redhat.com>
  27. * Petr Kostka <petr.kostka@st.com>
  28. * Honza Bambas <honzab@firemni.cz>
  29. *
  30. * Alternatively, the contents of this file may be used under the terms of
  31. * either the GNU General Public License Version 2 or later (the "GPL"), or
  32. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  33. * in which case the provisions of the GPL or the LGPL are applicable instead
  34. * of those above. If you wish to allow use of your version of this file only
  35. * under the terms of either the GPL or the LGPL, and not to allow others to
  36. * use your version of this file under the terms of the MPL, indicate your
  37. * decision by deleting the provisions above and replace them with the notice
  38. * and other provisions required by the GPL or the LGPL. If you do not delete
  39. * the provisions above, a recipient may use your version of this file under
  40. * the terms of any one of the MPL, the GPL or the LGPL.
  41. *
  42. * ***** END LICENSE BLOCK ***** */
  43. #include "nsNSSComponent.h"
  44. #include "nsNSSCallbacks.h"
  45. #include "nsNSSIOLayer.h"
  46. #include "nsIWebProgressListener.h"
  47. #include "nsProtectedAuthThread.h"
  48. #include "nsITokenDialogs.h"
  49. #include "nsNSSShutDown.h"
  50. #include "nsIUploadChannel.h"
  51. #include "nsThreadUtils.h"
  52. #include "nsIPrompt.h"
  53. #include "nsProxyRelease.h"
  54. #include "PSMRunnable.h"
  55. #include "nsIConsoleService.h"
  56. #include "nsIHttpChannelInternal.h"
  57. #include "ssl.h"
  58. #include "ocsp.h"
  59. #include "nssb64.h"
  60. using namespace mozilla;
  61. using namespace mozilla::psm;
  62. static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  63. #ifdef PR_LOGGING
  64. extern PRLogModuleInfo* gPIPNSSLog;
  65. #endif
  66. class nsHTTPDownloadEvent : public nsRunnable {
  67. public:
  68. nsHTTPDownloadEvent();
  69. ~nsHTTPDownloadEvent();
  70. NS_IMETHOD Run();
  71. nsNSSHttpRequestSession *mRequestSession;
  72. nsCOMPtr<nsHTTPListener> mListener;
  73. bool mResponsibleForDoneSignal;
  74. };
  75. nsHTTPDownloadEvent::nsHTTPDownloadEvent()
  76. :mResponsibleForDoneSignal(true)
  77. {
  78. }
  79. nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
  80. {
  81. if (mResponsibleForDoneSignal && mListener)
  82. mListener->send_done_signal();
  83. mRequestSession->Release();
  84. }
  85. NS_IMETHODIMP
  86. nsHTTPDownloadEvent::Run()
  87. {
  88. if (!mListener)
  89. return NS_OK;
  90. nsresult rv;
  91. nsCOMPtr<nsIIOService> ios = do_GetIOService();
  92. NS_ENSURE_STATE(ios);
  93. nsCOMPtr<nsIChannel> chan;
  94. ios->NewChannel(mRequestSession->mURL, nsnull, nsnull, getter_AddRefs(chan));
  95. NS_ENSURE_STATE(chan);
  96. // Disabled because it breaks authentication with a proxy, when such proxy
  97. // had been setup, and brings blue UI for EV certs.
  98. // chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS);
  99. // Create a loadgroup for this new channel. This way if the channel
  100. // is redirected, we'll have a way to cancel the resulting channel.
  101. nsCOMPtr<nsILoadGroup> lg = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
  102. chan->SetLoadGroup(lg);
  103. if (mRequestSession->mHasPostData)
  104. {
  105. nsCOMPtr<nsIInputStream> uploadStream;
  106. rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
  107. false,
  108. mRequestSession->mPostData,
  109. 0, ios);
  110. NS_ENSURE_SUCCESS(rv, rv);
  111. nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan));
  112. NS_ENSURE_STATE(uploadChannel);
  113. rv = uploadChannel->SetUploadStream(uploadStream,
  114. mRequestSession->mPostContentType,
  115. -1);
  116. NS_ENSURE_SUCCESS(rv, rv);
  117. }
  118. // Do not use SPDY for internal security operations. It could result
  119. // in the silent upgrade to ssl, which in turn could require an SSL
  120. // operation to fufill something like a CRL fetch, which is an
  121. // endless loop.
  122. nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
  123. if (internalChannel) {
  124. rv = internalChannel->SetAllowSpdy(false);
  125. NS_ENSURE_SUCCESS(rv, rv);
  126. }
  127. nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
  128. NS_ENSURE_STATE(hchan);
  129. rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
  130. NS_ENSURE_SUCCESS(rv, rv);
  131. mResponsibleForDoneSignal = false;
  132. mListener->mResponsibleForDoneSignal = true;
  133. mListener->mLoadGroup = lg.get();
  134. NS_ADDREF(mListener->mLoadGroup);
  135. mListener->mLoadGroupOwnerThread = PR_GetCurrentThread();
  136. rv = NS_NewStreamLoader(getter_AddRefs(mListener->mLoader),
  137. mListener);
  138. if (NS_SUCCEEDED(rv))
  139. rv = hchan->AsyncOpen(mListener->mLoader, nsnull);
  140. if (NS_FAILED(rv)) {
  141. mListener->mResponsibleForDoneSignal = false;
  142. mResponsibleForDoneSignal = true;
  143. NS_RELEASE(mListener->mLoadGroup);
  144. mListener->mLoadGroup = nsnull;
  145. mListener->mLoadGroupOwnerThread = nsnull;
  146. }
  147. return NS_OK;
  148. }
  149. struct nsCancelHTTPDownloadEvent : nsRunnable {
  150. nsCOMPtr<nsHTTPListener> mListener;
  151. NS_IMETHOD Run() {
  152. mListener->FreeLoadGroup(true);
  153. mListener = nsnull;
  154. return NS_OK;
  155. }
  156. };
  157. SECStatus nsNSSHttpServerSession::createSessionFcn(const char *host,
  158. PRUint16 portnum,
  159. SEC_HTTP_SERVER_SESSION *pSession)
  160. {
  161. if (!host || !pSession)
  162. return SECFailure;
  163. nsNSSHttpServerSession *hss = new nsNSSHttpServerSession;
  164. if (!hss)
  165. return SECFailure;
  166. hss->mHost = host;
  167. hss->mPort = portnum;
  168. *pSession = hss;
  169. return SECSuccess;
  170. }
  171. SECStatus nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session,
  172. const char *http_protocol_variant,
  173. const char *path_and_query_string,
  174. const char *http_request_method,
  175. const PRIntervalTime timeout,
  176. SEC_HTTP_REQUEST_SESSION *pRequest)
  177. {
  178. if (!session || !http_protocol_variant || !path_and_query_string ||
  179. !http_request_method || !pRequest)
  180. return SECFailure;
  181. nsNSSHttpServerSession* hss = static_cast<nsNSSHttpServerSession*>(session);
  182. if (!hss)
  183. return SECFailure;
  184. nsNSSHttpRequestSession *rs = new nsNSSHttpRequestSession;
  185. if (!rs)
  186. return SECFailure;
  187. rs->mTimeoutInterval = timeout;
  188. // Use a maximum timeout value of 10 seconds because of bug 404059.
  189. // FIXME: Use a better approach once 406120 is ready.
  190. PRUint32 maxBug404059Timeout = PR_TicksPerSecond() * 10;
  191. if (timeout > maxBug404059Timeout) {
  192. rs->mTimeoutInterval = maxBug404059Timeout;
  193. }
  194. rs->mURL.Assign(http_protocol_variant);
  195. rs->mURL.AppendLiteral("://");
  196. rs->mURL.Append(hss->mHost);
  197. rs->mURL.AppendLiteral(":");
  198. rs->mURL.AppendInt(hss->mPort);
  199. rs->mURL.Append(path_and_query_string);
  200. rs->mRequestMethod = http_request_method;
  201. *pRequest = (void*)rs;
  202. return SECSuccess;
  203. }
  204. SECStatus nsNSSHttpRequestSession::setPostDataFcn(const char *http_data,
  205. const PRUint32 http_data_len,
  206. const char *http_content_type)
  207. {
  208. mHasPostData = true;
  209. mPostData.Assign(http_data, http_data_len);
  210. mPostContentType.Assign(http_content_type);
  211. return SECSuccess;
  212. }
  213. SECStatus nsNSSHttpRequestSession::addHeaderFcn(const char *http_header_name,
  214. const char *http_header_value)
  215. {
  216. return SECFailure; // not yet implemented
  217. // All http code needs to be postponed to the UI thread.
  218. // Once this gets implemented, we need to add a string list member to
  219. // nsNSSHttpRequestSession and queue up the headers,
  220. // so they can be added in HandleHTTPDownloadPLEvent.
  221. //
  222. // The header will need to be set using
  223. // mHttpChannel->SetRequestHeader(nsDependentCString(http_header_name),
  224. // nsDependentCString(http_header_value),
  225. // false)));
  226. }
  227. SECStatus nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc **pPollDesc,
  228. PRUint16 *http_response_code,
  229. const char **http_response_content_type,
  230. const char **http_response_headers,
  231. const char **http_response_data,
  232. PRUint32 *http_response_data_len)
  233. {
  234. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  235. ("nsNSSHttpRequestSession::trySendAndReceiveFcn to %s\n", mURL.get()));
  236. const int max_retries = 2;
  237. int retry_count = 0;
  238. bool retryable_error = false;
  239. SECStatus result_sec_status = SECFailure;
  240. do
  241. {
  242. if (retry_count > 0)
  243. {
  244. if (retryable_error)
  245. {
  246. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  247. ("nsNSSHttpRequestSession::trySendAndReceiveFcn - sleeping and retrying: %d of %d\n",
  248. retry_count, max_retries));
  249. }
  250. PR_Sleep( PR_MillisecondsToInterval(300) * retry_count );
  251. }
  252. ++retry_count;
  253. retryable_error = false;
  254. result_sec_status =
  255. internal_send_receive_attempt(retryable_error, pPollDesc, http_response_code,
  256. http_response_content_type, http_response_headers,
  257. http_response_data, http_response_data_len);
  258. }
  259. while (retryable_error &&
  260. retry_count < max_retries);
  261. #ifdef PR_LOGGING
  262. if (retry_count > 1)
  263. {
  264. if (retryable_error)
  265. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  266. ("nsNSSHttpRequestSession::trySendAndReceiveFcn - still failing, giving up...\n"));
  267. else
  268. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  269. ("nsNSSHttpRequestSession::trySendAndReceiveFcn - success at attempt %d\n",
  270. retry_count));
  271. }
  272. #endif
  273. return result_sec_status;
  274. }
  275. void
  276. nsNSSHttpRequestSession::AddRef()
  277. {
  278. NS_AtomicIncrementRefcnt(mRefCount);
  279. }
  280. void
  281. nsNSSHttpRequestSession::Release()
  282. {
  283. PRInt32 newRefCount = NS_AtomicDecrementRefcnt(mRefCount);
  284. if (!newRefCount) {
  285. delete this;
  286. }
  287. }
  288. SECStatus
  289. nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
  290. PRPollDesc **pPollDesc,
  291. PRUint16 *http_response_code,
  292. const char **http_response_content_type,
  293. const char **http_response_headers,
  294. const char **http_response_data,
  295. PRUint32 *http_response_data_len)
  296. {
  297. if (pPollDesc) *pPollDesc = nsnull;
  298. if (http_response_code) *http_response_code = 0;
  299. if (http_response_content_type) *http_response_content_type = 0;
  300. if (http_response_headers) *http_response_headers = 0;
  301. if (http_response_data) *http_response_data = 0;
  302. PRUint32 acceptableResultSize = 0;
  303. if (http_response_data_len)
  304. {
  305. acceptableResultSize = *http_response_data_len;
  306. *http_response_data_len = 0;
  307. }
  308. if (!mListener)
  309. return SECFailure;
  310. Mutex& waitLock = mListener->mLock;
  311. CondVar& waitCondition = mListener->mCondition;
  312. volatile bool &waitFlag = mListener->mWaitFlag;
  313. waitFlag = true;
  314. nsRefPtr<nsHTTPDownloadEvent> event = new nsHTTPDownloadEvent;
  315. if (!event)
  316. return SECFailure;
  317. event->mListener = mListener;
  318. this->AddRef();
  319. event->mRequestSession = this;
  320. nsresult rv = NS_DispatchToMainThread(event);
  321. if (NS_FAILED(rv))
  322. {
  323. event->mResponsibleForDoneSignal = false;
  324. return SECFailure;
  325. }
  326. bool request_canceled = false;
  327. {
  328. MutexAutoLock locker(waitLock);
  329. const PRIntervalTime start_time = PR_IntervalNow();
  330. PRIntervalTime wait_interval;
  331. bool running_on_main_thread = NS_IsMainThread();
  332. if (running_on_main_thread)
  333. {
  334. // let's process events quickly
  335. wait_interval = PR_MicrosecondsToInterval(50);
  336. }
  337. else
  338. {
  339. // On a secondary thread, it's fine to wait some more for
  340. // for the condition variable.
  341. wait_interval = PR_MillisecondsToInterval(250);
  342. }
  343. while (waitFlag)
  344. {
  345. if (running_on_main_thread)
  346. {
  347. // Networking runs on the main thread, which we happen to block here.
  348. // Processing events will allow the OCSP networking to run while we
  349. // are waiting. Thanks a lot to Darin Fisher for rewriting the
  350. // thread manager. Thanks a lot to Christian Biesinger who
  351. // made me aware of this possibility. (kaie)
  352. MutexAutoUnlock unlock(waitLock);
  353. NS_ProcessNextEvent(nsnull);
  354. }
  355. waitCondition.Wait(wait_interval);
  356. if (!waitFlag)
  357. break;
  358. if (!request_canceled)
  359. {
  360. bool timeout =
  361. (PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval;
  362. if (timeout)
  363. {
  364. request_canceled = true;
  365. nsRefPtr<nsCancelHTTPDownloadEvent> cancelevent = new nsCancelHTTPDownloadEvent;
  366. cancelevent->mListener = mListener;
  367. rv = NS_DispatchToMainThread(cancelevent);
  368. if (NS_FAILED(rv)) {
  369. NS_WARNING("cannot post cancel event");
  370. }
  371. break;
  372. }
  373. }
  374. }
  375. }
  376. if (request_canceled)
  377. return SECFailure;
  378. if (NS_FAILED(mListener->mResultCode))
  379. {
  380. if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED
  381. ||
  382. mListener->mResultCode == NS_ERROR_NET_RESET)
  383. {
  384. retryable_error = true;
  385. }
  386. return SECFailure;
  387. }
  388. if (http_response_code)
  389. *http_response_code = mListener->mHttpResponseCode;
  390. if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) {
  391. *http_response_data_len = mListener->mResultLen;
  392. // acceptableResultSize == 0 means: any size is acceptable
  393. if (acceptableResultSize != 0
  394. &&
  395. acceptableResultSize < mListener->mResultLen)
  396. {
  397. return SECFailure;
  398. }
  399. // return data by reference, result data will be valid
  400. // until "this" gets destroyed by NSS
  401. *http_response_data = (const char*)mListener->mResultData;
  402. }
  403. if (mListener->mHttpRequestSucceeded && http_response_content_type) {
  404. if (mListener->mHttpResponseContentType.Length()) {
  405. *http_response_content_type = mListener->mHttpResponseContentType.get();
  406. }
  407. }
  408. return SECSuccess;
  409. }
  410. SECStatus nsNSSHttpRequestSession::cancelFcn()
  411. {
  412. // As of today, only the blocking variant of the http interface
  413. // has been implemented. Implementing cancelFcn will be necessary
  414. // as soon as we implement the nonblocking variant.
  415. return SECSuccess;
  416. }
  417. SECStatus nsNSSHttpRequestSession::freeFcn()
  418. {
  419. Release();
  420. return SECSuccess;
  421. }
  422. nsNSSHttpRequestSession::nsNSSHttpRequestSession()
  423. : mRefCount(1),
  424. mHasPostData(false),
  425. mTimeoutInterval(0),
  426. mListener(new nsHTTPListener)
  427. {
  428. }
  429. nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
  430. {
  431. }
  432. SEC_HttpClientFcn nsNSSHttpInterface::sNSSInterfaceTable;
  433. void nsNSSHttpInterface::initTable()
  434. {
  435. sNSSInterfaceTable.version = 1;
  436. SEC_HttpClientFcnV1 &v1 = sNSSInterfaceTable.fcnTable.ftable1;
  437. v1.createSessionFcn = createSessionFcn;
  438. v1.keepAliveSessionFcn = keepAliveFcn;
  439. v1.freeSessionFcn = freeSessionFcn;
  440. v1.createFcn = createFcn;
  441. v1.setPostDataFcn = setPostDataFcn;
  442. v1.addHeaderFcn = addHeaderFcn;
  443. v1.trySendAndReceiveFcn = trySendAndReceiveFcn;
  444. v1.cancelFcn = cancelFcn;
  445. v1.freeFcn = freeFcn;
  446. }
  447. void nsNSSHttpInterface::registerHttpClient()
  448. {
  449. SEC_RegisterDefaultHttpClient(&sNSSInterfaceTable);
  450. }
  451. void nsNSSHttpInterface::unregisterHttpClient()
  452. {
  453. SEC_RegisterDefaultHttpClient(nsnull);
  454. }
  455. nsHTTPListener::nsHTTPListener()
  456. : mResultData(nsnull),
  457. mResultLen(0),
  458. mLock("nsHTTPListener.mLock"),
  459. mCondition(mLock, "nsHTTPListener.mCondition"),
  460. mWaitFlag(true),
  461. mResponsibleForDoneSignal(false),
  462. mLoadGroup(nsnull),
  463. mLoadGroupOwnerThread(nsnull)
  464. {
  465. }
  466. nsHTTPListener::~nsHTTPListener()
  467. {
  468. if (mResponsibleForDoneSignal)
  469. send_done_signal();
  470. if (mLoader) {
  471. nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
  472. NS_ProxyRelease(mainThread, mLoader);
  473. }
  474. }
  475. NS_IMPL_THREADSAFE_ISUPPORTS1(nsHTTPListener, nsIStreamLoaderObserver)
  476. void
  477. nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
  478. {
  479. nsILoadGroup *lg = nsnull;
  480. MutexAutoLock locker(mLock);
  481. if (mLoadGroup) {
  482. if (mLoadGroupOwnerThread != PR_GetCurrentThread()) {
  483. NS_ASSERTION(false,
  484. "attempt to access nsHTTPDownloadEvent::mLoadGroup on multiple threads, leaking it!");
  485. }
  486. else {
  487. lg = mLoadGroup;
  488. mLoadGroup = nsnull;
  489. }
  490. }
  491. if (lg) {
  492. if (aCancelLoad) {
  493. lg->Cancel(NS_ERROR_ABORT);
  494. }
  495. NS_RELEASE(lg);
  496. }
  497. }
  498. NS_IMETHODIMP
  499. nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
  500. nsISupports* aContext,
  501. nsresult aStatus,
  502. PRUint32 stringLen,
  503. const PRUint8* string)
  504. {
  505. mResultCode = aStatus;
  506. FreeLoadGroup(false);
  507. nsCOMPtr<nsIRequest> req;
  508. nsCOMPtr<nsIHttpChannel> hchan;
  509. nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
  510. #ifdef PR_LOGGING
  511. if (NS_FAILED(aStatus))
  512. {
  513. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  514. ("nsHTTPListener::OnStreamComplete status failed %d", aStatus));
  515. }
  516. #endif
  517. if (NS_SUCCEEDED(rv))
  518. hchan = do_QueryInterface(req, &rv);
  519. if (NS_SUCCEEDED(rv))
  520. {
  521. rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
  522. if (NS_FAILED(rv))
  523. mHttpRequestSucceeded = false;
  524. mResultLen = stringLen;
  525. mResultData = string; // reference. Make sure loader lives as long as this
  526. unsigned int rcode;
  527. rv = hchan->GetResponseStatus(&rcode);
  528. if (NS_FAILED(rv))
  529. mHttpResponseCode = 500;
  530. else
  531. mHttpResponseCode = rcode;
  532. hchan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
  533. mHttpResponseContentType);
  534. }
  535. if (mResponsibleForDoneSignal)
  536. send_done_signal();
  537. return aStatus;
  538. }
  539. void nsHTTPListener::send_done_signal()
  540. {
  541. mResponsibleForDoneSignal = false;
  542. {
  543. MutexAutoLock locker(mLock);
  544. mWaitFlag = false;
  545. mCondition.NotifyAll();
  546. }
  547. }
  548. static char*
  549. ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIInterfaceRequestor *ir)
  550. {
  551. if (!NS_IsMainThread()) {
  552. NS_ERROR("ShowProtectedAuthPrompt called off the main thread");
  553. return nsnull;
  554. }
  555. char* protAuthRetVal = nsnull;
  556. // Get protected auth dialogs
  557. nsITokenDialogs* dialogs = 0;
  558. nsresult nsrv = getNSSDialogs((void**)&dialogs,
  559. NS_GET_IID(nsITokenDialogs),
  560. NS_TOKENDIALOGS_CONTRACTID);
  561. if (NS_SUCCEEDED(nsrv))
  562. {
  563. nsProtectedAuthThread* protectedAuthRunnable = new nsProtectedAuthThread();
  564. if (protectedAuthRunnable)
  565. {
  566. NS_ADDREF(protectedAuthRunnable);
  567. protectedAuthRunnable->SetParams(slot);
  568. nsCOMPtr<nsIProtectedAuthThread> runnable = do_QueryInterface(protectedAuthRunnable);
  569. if (runnable)
  570. {
  571. nsrv = dialogs->DisplayProtectedAuth(ir, runnable);
  572. // We call join on the thread,
  573. // so we can be sure that no simultaneous access will happen.
  574. protectedAuthRunnable->Join();
  575. if (NS_SUCCEEDED(nsrv))
  576. {
  577. SECStatus rv = protectedAuthRunnable->GetResult();
  578. switch (rv)
  579. {
  580. case SECSuccess:
  581. protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
  582. break;
  583. case SECWouldBlock:
  584. protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_RETRY));
  585. break;
  586. default:
  587. protAuthRetVal = nsnull;
  588. break;
  589. }
  590. }
  591. }
  592. NS_RELEASE(protectedAuthRunnable);
  593. }
  594. NS_RELEASE(dialogs);
  595. }
  596. return protAuthRetVal;
  597. }
  598. class PK11PasswordPromptRunnable : public SyncRunnableBase
  599. {
  600. public:
  601. PK11PasswordPromptRunnable(PK11SlotInfo* slot,
  602. nsIInterfaceRequestor* ir)
  603. : mResult(nsnull),
  604. mSlot(slot),
  605. mIR(ir)
  606. {
  607. }
  608. char * mResult; // out
  609. virtual void RunOnTargetThread();
  610. private:
  611. PK11SlotInfo* const mSlot; // in
  612. nsIInterfaceRequestor* const mIR; // in
  613. };
  614. void PK11PasswordPromptRunnable::RunOnTargetThread()
  615. {
  616. nsNSSShutDownPreventionLock locker;
  617. nsresult rv = NS_OK;
  618. PRUnichar *password = nsnull;
  619. bool value = false;
  620. nsCOMPtr<nsIPrompt> prompt;
  621. /* TODO: Retry should generate a different dialog message */
  622. /*
  623. if (retry)
  624. return nsnull;
  625. */
  626. if (!mIR)
  627. {
  628. nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
  629. }
  630. else
  631. {
  632. prompt = do_GetInterface(mIR);
  633. NS_ASSERTION(prompt != nsnull, "callbacks does not implement nsIPrompt");
  634. }
  635. if (!prompt)
  636. return;
  637. if (PK11_ProtectedAuthenticationPath(mSlot)) {
  638. mResult = ShowProtectedAuthPrompt(mSlot, mIR);
  639. return;
  640. }
  641. nsAutoString promptString;
  642. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  643. if (NS_FAILED(rv))
  644. return;
  645. const PRUnichar* formatStrings[1] = {
  646. ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)))
  647. };
  648. rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
  649. formatStrings, 1,
  650. promptString);
  651. nsMemory::Free(const_cast<PRUnichar*>(formatStrings[0]));
  652. if (NS_FAILED(rv))
  653. return;
  654. {
  655. nsPSMUITracker tracker;
  656. if (tracker.isUIForbidden()) {
  657. rv = NS_ERROR_NOT_AVAILABLE;
  658. }
  659. else {
  660. // Although the exact value is ignored, we must not pass invalid
  661. // bool values through XPConnect.
  662. bool checkState = false;
  663. rv = prompt->PromptPassword(nsnull, promptString.get(),
  664. &password, nsnull, &checkState, &value);
  665. }
  666. }
  667. if (NS_SUCCEEDED(rv) && value) {
  668. mResult = ToNewUTF8String(nsDependentString(password));
  669. NS_Free(password);
  670. }
  671. }
  672. char* PR_CALLBACK
  673. PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
  674. {
  675. nsRefPtr<PK11PasswordPromptRunnable> runnable =
  676. new PK11PasswordPromptRunnable(slot,
  677. static_cast<nsIInterfaceRequestor*>(arg));
  678. runnable->DispatchToMainThreadAndWait();
  679. return runnable->mResult;
  680. }
  681. void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
  682. nsNSSShutDownPreventionLock locker;
  683. PRInt32 sslStatus;
  684. char* signer = nsnull;
  685. char* cipherName = nsnull;
  686. PRInt32 keyLength;
  687. nsresult rv;
  688. PRInt32 encryptBits;
  689. nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
  690. // If the handshake completed, then we know the site is TLS tolerant (if this
  691. // was a TLS connection).
  692. nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);
  693. if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
  694. &encryptBits, &signer, nsnull)) {
  695. return;
  696. }
  697. PRInt32 secStatus;
  698. if (sslStatus == SSL_SECURITY_STATUS_OFF)
  699. secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
  700. else if (encryptBits >= 90)
  701. secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
  702. nsIWebProgressListener::STATE_SECURE_HIGH);
  703. else
  704. secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
  705. nsIWebProgressListener::STATE_SECURE_LOW);
  706. PRBool siteSupportsSafeRenego;
  707. if (SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn, &siteSupportsSafeRenego) != SECSuccess
  708. || !siteSupportsSafeRenego) {
  709. bool wantWarning = (nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746() > 0);
  710. nsCOMPtr<nsIConsoleService> console;
  711. if (infoObject && wantWarning) {
  712. console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
  713. if (console) {
  714. nsXPIDLCString hostName;
  715. infoObject->GetHostName(getter_Copies(hostName));
  716. nsAutoString msg;
  717. msg.Append(NS_ConvertASCIItoUTF16(hostName));
  718. msg.Append(NS_LITERAL_STRING(" : server does not support RFC 5746, see CVE-2009-3555"));
  719. console->LogStringMessage(msg.get());
  720. }
  721. }
  722. if (nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()) {
  723. secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
  724. }
  725. }
  726. CERTCertificate *peerCert = SSL_PeerCertificate(fd);
  727. const char* caName = nsnull; // caName is a pointer only, no ownership
  728. char* certOrgName = CERT_GetOrgName(&peerCert->issuer);
  729. CERT_DestroyCertificate(peerCert);
  730. caName = certOrgName ? certOrgName : signer;
  731. const char* verisignName = "Verisign, Inc.";
  732. // If the CA name is RSA Data Security, then change the name to the real
  733. // name of the company i.e. VeriSign, Inc.
  734. if (nsCRT::strcmp((const char*)caName, "RSA Data Security, Inc.") == 0) {
  735. caName = verisignName;
  736. }
  737. nsAutoString shortDesc;
  738. const PRUnichar* formatStrings[1] = { ToNewUnicode(NS_ConvertUTF8toUTF16(caName)) };
  739. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  740. if (NS_SUCCEEDED(rv)) {
  741. rv = nssComponent->PIPBundleFormatStringFromName("SignedBy",
  742. formatStrings, 1,
  743. shortDesc);
  744. nsMemory::Free(const_cast<PRUnichar*>(formatStrings[0]));
  745. nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
  746. infoObject->SetSecurityState(secStatus);
  747. infoObject->SetShortSecurityDescription(shortDesc.get());
  748. /* Set the SSL Status information */
  749. nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
  750. if (!status) {
  751. status = new nsSSLStatus();
  752. infoObject->SetSSLStatus(status);
  753. }
  754. nsSSLIOLayerHelpers::mHostsWithCertErrors->LookupCertErrorBits(
  755. infoObject, status);
  756. CERTCertificate *serverCert = SSL_PeerCertificate(fd);
  757. if (serverCert) {
  758. nsRefPtr<nsNSSCertificate> nssc = nsNSSCertificate::Create(serverCert);
  759. CERT_DestroyCertificate(serverCert);
  760. serverCert = nsnull;
  761. nsCOMPtr<nsIX509Cert> prevcert;
  762. infoObject->GetPreviousCert(getter_AddRefs(prevcert));
  763. bool equals_previous = false;
  764. if (prevcert && nssc) {
  765. nsresult rv = nssc->Equals(prevcert, &equals_previous);
  766. if (NS_FAILED(rv)) {
  767. equals_previous = false;
  768. }
  769. }
  770. if (equals_previous) {
  771. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  772. ("HandshakeCallback using PREV cert %p\n", prevcert.get()));
  773. status->mServerCert = prevcert;
  774. }
  775. else {
  776. if (status->mServerCert) {
  777. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  778. ("HandshakeCallback KEEPING cert %p\n", status->mServerCert.get()));
  779. }
  780. else {
  781. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  782. ("HandshakeCallback using NEW cert %p\n", nssc.get()));
  783. status->mServerCert = nssc;
  784. }
  785. }
  786. }
  787. status->mHaveKeyLengthAndCipher = true;
  788. status->mKeyLength = keyLength;
  789. status->mSecretKeyLength = encryptBits;
  790. status->mCipherName.Assign(cipherName);
  791. // Get the NPN value. Do this on the stack and copy it into
  792. // a string rather than preallocating the string because right
  793. // now we expect NPN to fail more often than it succeeds.
  794. SSLNextProtoState state;
  795. unsigned char npnbuf[256];
  796. unsigned int npnlen;
  797. if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess &&
  798. state == SSL_NEXT_PROTO_NEGOTIATED)
  799. infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
  800. else
  801. infoObject->SetNegotiatedNPN(nsnull, 0);
  802. infoObject->SetHandshakeCompleted();
  803. }
  804. PORT_Free(cipherName);
  805. PR_FREEIF(certOrgName);
  806. PR_Free(signer);
  807. }
  808. struct OCSPDefaultResponders {
  809. const char *issuerName_string;
  810. CERTName *issuerName;
  811. const char *issuerKeyID_base64;
  812. SECItem *issuerKeyID;
  813. const char *ocspUrl;
  814. };
  815. static struct OCSPDefaultResponders myDefaultOCSPResponders[] = {
  816. /* COMODO */
  817. {
  818. "CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE",
  819. nsnull, "rb2YejS0Jvf6xCZU7wO94CTLVBo=", nsnull,
  820. "http://ocsp.comodoca.com"
  821. },
  822. {
  823. "CN=COMODO Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB",
  824. nsnull, "C1jli8ZMFTekQKkwqSG+RzZaVv8=", nsnull,
  825. "http://ocsp.comodoca.com"
  826. },
  827. {
  828. "CN=COMODO EV SGC CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB",
  829. nsnull, "f/ZMNigUrs0eN6/eWvJbw6CsK/4=", nsnull,
  830. "http://ocsp.comodoca.com"
  831. },
  832. {
  833. "CN=COMODO EV SSL CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB",
  834. nsnull, "aRZJ7LZ1ZFrpAyNgL1RipTRcPuI=", nsnull,
  835. "http://ocsp.comodoca.com"
  836. },
  837. {
  838. "CN=UTN - DATACorp SGC,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US",
  839. nsnull, "UzLRs89/+uDxoF2FTpLSnkUdtE8=", nsnull,
  840. "http://ocsp.usertrust.com"
  841. },
  842. {
  843. "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US",
  844. nsnull, "oXJfJhsomEOVXQc31YWWnUvSw0U=", nsnull,
  845. "http://ocsp.usertrust.com"
  846. },
  847. /* Network Solutions */
  848. {
  849. "CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US",
  850. nsnull, "ITDJ+wDXTpjah6oq0KcusUAxp0w=", nsnull,
  851. "http://ocsp.netsolssl.com"
  852. },
  853. {
  854. "CN=Network Solutions EV SSL CA,O=Network Solutions L.L.C.,C=US",
  855. nsnull, "tk6FnYQfGx3UUolOB5Yt+d7xj8w=", nsnull,
  856. "http://ocsp.netsolssl.com"
  857. },
  858. /* GlobalSign */
  859. {
  860. "CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE",
  861. nsnull, "YHtmGkUNl8qJUC99BM00qP/8/Us=", nsnull,
  862. "http://ocsp.globalsign.com/ExtendedSSLCACross"
  863. },
  864. {
  865. "CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R2",
  866. nsnull, "m+IHV2ccHsBqBt5ZtJot39wZhi4=", nsnull,
  867. "http://ocsp.globalsign.com/ExtendedSSLCA"
  868. },
  869. {
  870. "CN=GlobalSign Extended Validation CA,O=GlobalSign,OU=Extended Validation CA",
  871. nsnull, "NLH5yYxrNUTMCGkK7uOjuVy/FuA=", nsnull,
  872. "http://ocsp.globalsign.com/ExtendedSSL"
  873. },
  874. /* Trustwave */
  875. {
  876. "CN=SecureTrust CA,O=SecureTrust Corporation,C=US",
  877. nsnull, "QjK2FvoE/f5dS3rD/fdMQB1aQ68=", nsnull,
  878. "http://ocsp.trustwave.com"
  879. }
  880. };
  881. static const unsigned int numResponders =
  882. (sizeof myDefaultOCSPResponders) / (sizeof myDefaultOCSPResponders[0]);
  883. static CERT_StringFromCertFcn oldOCSPAIAInfoCallback = nsnull;
  884. /*
  885. * See if we have a hard-coded default responder for this certificate's
  886. * issuer (unless this certificate is a root certificate).
  887. *
  888. * The result needs to be freed (PORT_Free) when no longer in use.
  889. */
  890. char* PR_CALLBACK MyAlternateOCSPAIAInfoCallback(CERTCertificate *cert) {
  891. if (cert && !cert->isRoot) {
  892. unsigned int i;
  893. for (i=0; i < numResponders; i++) {
  894. if (!(myDefaultOCSPResponders[i].issuerName));
  895. else if (!(myDefaultOCSPResponders[i].issuerKeyID));
  896. else if (!(cert->authKeyID));
  897. else if (CERT_CompareName(myDefaultOCSPResponders[i].issuerName,
  898. &(cert->issuer)) != SECEqual);
  899. else if (SECITEM_CompareItem(myDefaultOCSPResponders[i].issuerKeyID,
  900. &(cert->authKeyID->keyID)) != SECEqual);
  901. else // Issuer Name and Key Identifier match, so use this OCSP URL.
  902. return PORT_Strdup(myDefaultOCSPResponders[i].ocspUrl);
  903. }
  904. }
  905. // If we've not found a hard-coded default responder, chain to the old
  906. // callback function (if there is one).
  907. if (oldOCSPAIAInfoCallback)
  908. return (*oldOCSPAIAInfoCallback)(cert);
  909. return nsnull;
  910. }
  911. void cleanUpMyDefaultOCSPResponders() {
  912. unsigned int i;
  913. for (i=0; i < numResponders; i++) {
  914. if (myDefaultOCSPResponders[i].issuerName) {
  915. CERT_DestroyName(myDefaultOCSPResponders[i].issuerName);
  916. myDefaultOCSPResponders[i].issuerName = nsnull;
  917. }
  918. if (myDefaultOCSPResponders[i].issuerKeyID) {
  919. SECITEM_FreeItem(myDefaultOCSPResponders[i].issuerKeyID, true);
  920. myDefaultOCSPResponders[i].issuerKeyID = nsnull;
  921. }
  922. }
  923. }
  924. SECStatus RegisterMyOCSPAIAInfoCallback() {
  925. // Prevent multiple registrations.
  926. if (myDefaultOCSPResponders[0].issuerName)
  927. return SECSuccess; // Already registered ok.
  928. // Populate various fields in the myDefaultOCSPResponders[] array.
  929. SECStatus rv = SECFailure;
  930. unsigned int i;
  931. for (i=0; i < numResponders; i++) {
  932. // Create a CERTName structure from the issuer name string.
  933. myDefaultOCSPResponders[i].issuerName = CERT_AsciiToName(
  934. const_cast<char*>(myDefaultOCSPResponders[i].issuerName_string));
  935. if (!(myDefaultOCSPResponders[i].issuerName))
  936. goto loser;
  937. // Create a SECItem from the Base64 authority key identifier keyID.
  938. myDefaultOCSPResponders[i].issuerKeyID = NSSBase64_DecodeBuffer(nsnull,
  939. nsnull, myDefaultOCSPResponders[i].issuerKeyID_base64,
  940. (PRUint32)PORT_Strlen(myDefaultOCSPResponders[i].issuerKeyID_base64));
  941. if (!(myDefaultOCSPResponders[i].issuerKeyID))
  942. goto loser;
  943. }
  944. // Register our alternate OCSP Responder URL lookup function.
  945. rv = CERT_RegisterAlternateOCSPAIAInfoCallBack(MyAlternateOCSPAIAInfoCallback,
  946. &oldOCSPAIAInfoCallback);
  947. if (rv != SECSuccess)
  948. goto loser;
  949. return SECSuccess;
  950. loser:
  951. cleanUpMyDefaultOCSPResponders();
  952. return rv;
  953. }
  954. SECStatus UnregisterMyOCSPAIAInfoCallback() {
  955. SECStatus rv;
  956. // Only allow unregistration if we're already registered.
  957. if (!(myDefaultOCSPResponders[0].issuerName))
  958. return SECFailure;
  959. // Unregister our alternate OCSP Responder URL lookup function.
  960. rv = CERT_RegisterAlternateOCSPAIAInfoCallBack(oldOCSPAIAInfoCallback,
  961. nsnull);
  962. if (rv != SECSuccess)
  963. return rv;
  964. // Tidy up.
  965. oldOCSPAIAInfoCallback = nsnull;
  966. cleanUpMyDefaultOCSPResponders();
  967. return SECSuccess;
  968. }