/security/manager/ssl/src/nsNSSIOLayer.cpp

http://github.com/zpao/v8monkey · C++ · 3656 lines · 2687 code · 541 blank · 428 comment · 506 complexity · 2d05e328bccca59597b112725aedb031 MD5 · raw file

Large files are truncated click here to view the full 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. * Javier Delgadillo <javi@netscape.com>
  26. * Kai Engert <kengert@redhat.com>
  27. *
  28. * Alternatively, the contents of this file may be used under the terms of
  29. * either the GNU General Public License Version 2 or later (the "GPL"), or
  30. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  31. * in which case the provisions of the GPL or the LGPL are applicable instead
  32. * of those above. If you wish to allow use of your version of this file only
  33. * under the terms of either the GPL or the LGPL, and not to allow others to
  34. * use your version of this file under the terms of the MPL, indicate your
  35. * decision by deleting the provisions above and replace them with the notice
  36. * and other provisions required by the GPL or the LGPL. If you do not delete
  37. * the provisions above, a recipient may use your version of this file under
  38. * the terms of any one of the MPL, the GPL or the LGPL.
  39. *
  40. * ***** END LICENSE BLOCK ***** */
  41. #include "nsNSSComponent.h"
  42. #include "nsNSSIOLayer.h"
  43. #include "nsNSSCallbacks.h"
  44. #include "prlog.h"
  45. #include "prnetdb.h"
  46. #include "nsIPrefService.h"
  47. #include "nsIPrefBranch.h"
  48. #include "nsIServiceManager.h"
  49. #include "nsIWebProgressListener.h"
  50. #include "nsIChannel.h"
  51. #include "nsNSSCertificate.h"
  52. #include "nsIX509CertValidity.h"
  53. #include "nsIDateTimeFormat.h"
  54. #include "nsDateTimeFormatCID.h"
  55. #include "nsIClientAuthDialogs.h"
  56. #include "nsClientAuthRemember.h"
  57. #include "nsICertOverrideService.h"
  58. #include "nsISSLErrorListener.h"
  59. #include "nsIObjectInputStream.h"
  60. #include "nsIObjectOutputStream.h"
  61. #include "nsXPIDLString.h"
  62. #include "nsReadableUtils.h"
  63. #include "nsHashSets.h"
  64. #include "nsCRT.h"
  65. #include "nsAutoPtr.h"
  66. #include "nsPrintfCString.h"
  67. #include "SSLServerCertVerification.h"
  68. #include "nsNSSShutDown.h"
  69. #include "nsSSLStatus.h"
  70. #include "nsNSSCertHelper.h"
  71. #include "nsNSSCleaner.h"
  72. #include "nsIDocShell.h"
  73. #include "nsIDocShellTreeItem.h"
  74. #include "nsISecureBrowserUI.h"
  75. #include "nsIClassInfoImpl.h"
  76. #include "nsIProgrammingLanguage.h"
  77. #include "nsIArray.h"
  78. #include "nsCharSeparatedTokenizer.h"
  79. #include "PSMRunnable.h"
  80. #include "ssl.h"
  81. #include "secerr.h"
  82. #include "sslerr.h"
  83. #include "secder.h"
  84. #include "secasn1.h"
  85. #include "certdb.h"
  86. #include "cert.h"
  87. #include "keyhi.h"
  88. #include "mozilla/Util.h"
  89. using namespace mozilla;
  90. using namespace mozilla::psm;
  91. //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
  92. //reports when doing SSL read/write
  93. //#define DUMP_BUFFER //Enable this define along with
  94. //DEBUG_SSL_VERBOSE to dump SSL
  95. //read/write buffer to a log.
  96. //Uses PR_LOG except on Mac where
  97. //we always write out to our own
  98. //file.
  99. NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
  100. NSSCleanupAutoPtrClass(void, PR_FREEIF)
  101. static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  102. /* SSM_UserCertChoice: enum for cert choice info */
  103. typedef enum {ASK, AUTO} SSM_UserCertChoice;
  104. #ifdef PR_LOGGING
  105. extern PRLogModuleInfo* gPIPNSSLog;
  106. #endif
  107. #if defined(DEBUG_SSL_VERBOSE) && defined (XP_MAC)
  108. #ifdef PR_LOG
  109. #undef PR_LOG
  110. #endif
  111. static PRFileDesc *gMyLogFile = nsnull;
  112. #define MAC_LOG_FILE "MAC PIPNSS Log File"
  113. void MyLogFunction(const char *fmt, ...)
  114. {
  115. va_list ap;
  116. va_start(ap,fmt);
  117. if (gMyLogFile == nsnull)
  118. gMyLogFile = PR_Open(MAC_LOG_FILE, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  119. 0600);
  120. if (!gMyLogFile)
  121. return;
  122. PR_vfprintf(gMyLogFile, fmt, ap);
  123. va_end(ap);
  124. }
  125. #define PR_LOG(module,level,args) MyLogFunction args
  126. #endif
  127. nsNSSSocketInfo::nsNSSSocketInfo()
  128. : mMutex("nsNSSSocketInfo::nsNSSSocketInfo"),
  129. mFd(nsnull),
  130. mCertVerificationState(before_cert_verification),
  131. mCertVerificationStarted(0),
  132. mCertVerificationEnded(0),
  133. mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
  134. mSubRequestsHighSecurity(0),
  135. mSubRequestsLowSecurity(0),
  136. mSubRequestsBrokenSecurity(0),
  137. mSubRequestsNoSecurity(0),
  138. mErrorCode(0),
  139. mErrorMessageType(PlainErrorMessage),
  140. mForSTARTTLS(false),
  141. mSSL3Enabled(false),
  142. mTLSEnabled(false),
  143. mHandshakePending(true),
  144. mHasCleartextPhase(false),
  145. mHandshakeInProgress(false),
  146. mAllowTLSIntoleranceTimeout(true),
  147. mRememberClientAuthCertificate(false),
  148. mHandshakeStartTime(0),
  149. mPort(0),
  150. mIsCertIssuerBlacklisted(false),
  151. mNPNCompleted(false),
  152. mHandshakeCompleted(false),
  153. mJoined(false),
  154. mSentClientCert(false)
  155. {
  156. }
  157. nsNSSSocketInfo::~nsNSSSocketInfo()
  158. {
  159. nsNSSShutDownPreventionLock locker;
  160. if (isAlreadyShutDown())
  161. return;
  162. shutdown(calledFromObject);
  163. }
  164. void nsNSSSocketInfo::virtualDestroyNSSReference()
  165. {
  166. }
  167. NS_IMPL_THREADSAFE_ISUPPORTS8(nsNSSSocketInfo,
  168. nsITransportSecurityInfo,
  169. nsISSLSocketControl,
  170. nsIInterfaceRequestor,
  171. nsISSLStatusProvider,
  172. nsIAssociatedContentSecurity,
  173. nsISerializable,
  174. nsIClassInfo,
  175. nsIClientAuthUserDecision)
  176. nsresult
  177. nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending)
  178. {
  179. *aHandshakePending = mHandshakePending;
  180. return NS_OK;
  181. }
  182. nsresult
  183. nsNSSSocketInfo::SetHandshakePending(bool aHandshakePending)
  184. {
  185. mHandshakePending = aHandshakePending;
  186. return NS_OK;
  187. }
  188. nsresult
  189. nsNSSSocketInfo::SetHostName(const char* host)
  190. {
  191. mHostName.Adopt(host ? NS_strdup(host) : 0);
  192. return NS_OK;
  193. }
  194. nsresult
  195. nsNSSSocketInfo::GetHostName(char **host)
  196. {
  197. *host = (mHostName) ? NS_strdup(mHostName) : nsnull;
  198. return NS_OK;
  199. }
  200. nsresult
  201. nsNSSSocketInfo::SetPort(PRInt32 aPort)
  202. {
  203. mPort = aPort;
  204. return NS_OK;
  205. }
  206. nsresult
  207. nsNSSSocketInfo::GetPort(PRInt32 *aPort)
  208. {
  209. *aPort = mPort;
  210. return NS_OK;
  211. }
  212. PRErrorCode
  213. nsNSSSocketInfo::GetErrorCode() const
  214. {
  215. MutexAutoLock lock(mMutex);
  216. return mErrorCode;
  217. }
  218. void
  219. nsNSSSocketInfo::SetCanceled(PRErrorCode errorCode,
  220. SSLErrorMessageType errorMessageType)
  221. {
  222. MutexAutoLock lock(mMutex);
  223. mErrorCode = errorCode;
  224. mErrorMessageType = errorMessageType;
  225. mErrorMessageCached.Truncate();
  226. }
  227. NS_IMETHODIMP nsNSSSocketInfo::GetRememberClientAuthCertificate(bool *aRememberClientAuthCertificate)
  228. {
  229. NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate);
  230. *aRememberClientAuthCertificate = mRememberClientAuthCertificate;
  231. return NS_OK;
  232. }
  233. NS_IMETHODIMP nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRememberClientAuthCertificate)
  234. {
  235. mRememberClientAuthCertificate = aRememberClientAuthCertificate;
  236. return NS_OK;
  237. }
  238. void nsNSSSocketInfo::SetHasCleartextPhase(bool aHasCleartextPhase)
  239. {
  240. mHasCleartextPhase = aHasCleartextPhase;
  241. }
  242. bool nsNSSSocketInfo::GetHasCleartextPhase()
  243. {
  244. return mHasCleartextPhase;
  245. }
  246. NS_IMETHODIMP
  247. nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
  248. {
  249. *aCallbacks = mCallbacks;
  250. NS_IF_ADDREF(*aCallbacks);
  251. return NS_OK;
  252. }
  253. NS_IMETHODIMP
  254. nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
  255. {
  256. if (!aCallbacks) {
  257. mCallbacks = nsnull;
  258. return NS_OK;
  259. }
  260. mCallbacks = aCallbacks;
  261. return NS_OK;
  262. }
  263. static void
  264. getSecureBrowserUI(nsIInterfaceRequestor * callbacks,
  265. nsISecureBrowserUI ** result)
  266. {
  267. NS_ASSERTION(result != nsnull, "result parameter to getSecureBrowserUI is null");
  268. *result = nsnull;
  269. NS_ASSERTION(NS_IsMainThread(),
  270. "getSecureBrowserUI called off the main thread");
  271. if (!callbacks)
  272. return;
  273. nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
  274. if (secureUI) {
  275. secureUI.forget(result);
  276. return;
  277. }
  278. nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
  279. if (item) {
  280. nsCOMPtr<nsIDocShellTreeItem> rootItem;
  281. (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
  282. nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
  283. if (docShell) {
  284. (void) docShell->GetSecurityUI(result);
  285. }
  286. }
  287. }
  288. NS_IMETHODIMP
  289. nsNSSSocketInfo::GetSecurityState(PRUint32* state)
  290. {
  291. *state = mSecurityState;
  292. return NS_OK;
  293. }
  294. nsresult
  295. nsNSSSocketInfo::SetSecurityState(PRUint32 aState)
  296. {
  297. mSecurityState = aState;
  298. return NS_OK;
  299. }
  300. /* attribute unsigned long countSubRequestsHighSecurity; */
  301. NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsHighSecurity(PRInt32 *aSubRequestsHighSecurity)
  302. {
  303. *aSubRequestsHighSecurity = mSubRequestsHighSecurity;
  304. return NS_OK;
  305. }
  306. NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsHighSecurity(PRInt32 aSubRequestsHighSecurity)
  307. {
  308. mSubRequestsHighSecurity = aSubRequestsHighSecurity;
  309. return NS_ERROR_NOT_IMPLEMENTED;
  310. }
  311. /* attribute unsigned long countSubRequestsLowSecurity; */
  312. NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsLowSecurity(PRInt32 *aSubRequestsLowSecurity)
  313. {
  314. *aSubRequestsLowSecurity = mSubRequestsLowSecurity;
  315. return NS_OK;
  316. }
  317. NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsLowSecurity(PRInt32 aSubRequestsLowSecurity)
  318. {
  319. mSubRequestsLowSecurity = aSubRequestsLowSecurity;
  320. return NS_OK;
  321. }
  322. /* attribute unsigned long countSubRequestsBrokenSecurity; */
  323. NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsBrokenSecurity(PRInt32 *aSubRequestsBrokenSecurity)
  324. {
  325. *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
  326. return NS_OK;
  327. }
  328. NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsBrokenSecurity(PRInt32 aSubRequestsBrokenSecurity)
  329. {
  330. mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
  331. return NS_OK;
  332. }
  333. /* attribute unsigned long countSubRequestsNoSecurity; */
  334. NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsNoSecurity(PRInt32 *aSubRequestsNoSecurity)
  335. {
  336. *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
  337. return NS_OK;
  338. }
  339. NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsNoSecurity(PRInt32 aSubRequestsNoSecurity)
  340. {
  341. mSubRequestsNoSecurity = aSubRequestsNoSecurity;
  342. return NS_OK;
  343. }
  344. NS_IMETHODIMP nsNSSSocketInfo::Flush()
  345. {
  346. return NS_OK;
  347. }
  348. NS_IMETHODIMP
  349. nsNSSSocketInfo::GetShortSecurityDescription(PRUnichar** aText) {
  350. if (mShortDesc.IsEmpty())
  351. *aText = nsnull;
  352. else {
  353. *aText = ToNewUnicode(mShortDesc);
  354. NS_ENSURE_TRUE(*aText, NS_ERROR_OUT_OF_MEMORY);
  355. }
  356. return NS_OK;
  357. }
  358. nsresult
  359. nsNSSSocketInfo::SetShortSecurityDescription(const PRUnichar* aText) {
  360. mShortDesc.Assign(aText);
  361. return NS_OK;
  362. }
  363. NS_IMETHODIMP
  364. nsNSSSocketInfo::GetErrorMessage(PRUnichar** aText)
  365. {
  366. NS_ENSURE_ARG_POINTER(aText);
  367. *aText = nsnull;
  368. if (!NS_IsMainThread()) {
  369. NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
  370. return NS_ERROR_NOT_SAME_THREAD;
  371. }
  372. MutexAutoLock lock(mMutex);
  373. nsresult rv = formatErrorMessage(lock);
  374. NS_ENSURE_SUCCESS(rv, rv);
  375. *aText = ToNewUnicode(mErrorMessageCached);
  376. return *aText != nsnull ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  377. }
  378. void
  379. nsNSSSocketInfo::SetNegotiatedNPN(const char *value, PRUint32 length)
  380. {
  381. if (!value)
  382. mNegotiatedNPN.Truncate();
  383. else
  384. mNegotiatedNPN.Assign(value, length);
  385. mNPNCompleted = true;
  386. }
  387. NS_IMETHODIMP
  388. nsNSSSocketInfo::GetNegotiatedNPN(nsACString &aNegotiatedNPN)
  389. {
  390. if (!mNPNCompleted)
  391. return NS_ERROR_NOT_CONNECTED;
  392. aNegotiatedNPN = mNegotiatedNPN;
  393. return NS_OK;
  394. }
  395. NS_IMETHODIMP
  396. nsNSSSocketInfo::JoinConnection(const nsACString & npnProtocol,
  397. const nsACString & hostname,
  398. PRInt32 port,
  399. bool *_retval NS_OUTPARAM)
  400. {
  401. *_retval = false;
  402. // Different ports may not be joined together
  403. if (port != mPort)
  404. return NS_OK;
  405. // Make sure NPN has been completed and matches requested npnProtocol
  406. if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
  407. return NS_OK;
  408. // If this is the same hostname then the certicate status does not
  409. // need to be considered. They are joinable.
  410. if (mHostName && hostname.Equals(mHostName)) {
  411. *_retval = true;
  412. return NS_OK;
  413. }
  414. // Before checking the server certificate we need to make sure the
  415. // handshake has completed.
  416. if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
  417. return NS_OK;
  418. // If the cert has error bits (e.g. it is untrusted) then do not join.
  419. // The value of mHaveCertErrorBits is only reliable because we know that
  420. // the handshake completed.
  421. if (SSLStatus()->mHaveCertErrorBits)
  422. return NS_OK;
  423. // If the connection is using client certificates then do not join
  424. // because the user decides on whether to send client certs to hosts on a
  425. // per-domain basis.
  426. if (mSentClientCert)
  427. return NS_OK;
  428. // Ensure that the server certificate covers the hostname that would
  429. // like to join this connection
  430. CERTCertificate *nssCert = nsnull;
  431. CERTCertificateCleaner nsscertCleaner(nssCert);
  432. nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
  433. if (cert2)
  434. nssCert = cert2->GetCert();
  435. if (!nssCert)
  436. return NS_OK;
  437. if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
  438. SECSuccess)
  439. return NS_OK;
  440. // All tests pass - this is joinable
  441. mJoined = true;
  442. *_retval = true;
  443. return NS_OK;
  444. }
  445. static nsresult
  446. formatPlainErrorMessage(nsXPIDLCString const & host, PRInt32 port,
  447. PRErrorCode err, nsString &returnedMessage);
  448. static nsresult
  449. formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
  450. PRErrorCode errorCodeToReport,
  451. const nsXPIDLCString & host, PRInt32 port,
  452. nsString & returnedMessage);
  453. // XXX: uses nsNSSComponent string bundles off the main thread when called by
  454. // nsNSSSocketInfo::Write(). When we remove the error message from the
  455. // serialization of nsNSSSocketInfo (bug 697781) we can inline
  456. // formatErrorMessage into GetErrorMessage().
  457. nsresult
  458. nsNSSSocketInfo::formatErrorMessage(MutexAutoLock const & proofOfLock)
  459. {
  460. if (mErrorCode == 0 || !mErrorMessageCached.IsEmpty()) {
  461. return NS_OK;
  462. }
  463. nsresult rv;
  464. NS_ConvertASCIItoUTF16 hostNameU(mHostName);
  465. NS_ASSERTION(mErrorMessageType != OverridableCertErrorMessage ||
  466. (mSSLStatus && mSSLStatus->mServerCert &&
  467. mSSLStatus->mHaveCertErrorBits),
  468. "GetErrorMessage called for cert error without cert");
  469. if (mErrorMessageType == OverridableCertErrorMessage &&
  470. mSSLStatus && mSSLStatus->mServerCert) {
  471. rv = formatOverridableCertErrorMessage(*mSSLStatus, mErrorCode,
  472. mHostName, mPort,
  473. mErrorMessageCached);
  474. } else {
  475. rv = formatPlainErrorMessage(mHostName, mPort, mErrorCode,
  476. mErrorMessageCached);
  477. }
  478. if (NS_FAILED(rv)) {
  479. mErrorMessageCached.Truncate();
  480. }
  481. return rv;
  482. }
  483. /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
  484. NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result)
  485. {
  486. if (!NS_IsMainThread()) {
  487. NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
  488. return NS_ERROR_NOT_SAME_THREAD;
  489. }
  490. nsresult rv;
  491. if (!mCallbacks) {
  492. nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
  493. if (!ir)
  494. return NS_ERROR_OUT_OF_MEMORY;
  495. rv = ir->GetInterface(uuid, result);
  496. } else {
  497. rv = mCallbacks->GetInterface(uuid, result);
  498. }
  499. return rv;
  500. }
  501. nsresult
  502. nsNSSSocketInfo::GetForSTARTTLS(bool* aForSTARTTLS)
  503. {
  504. *aForSTARTTLS = mForSTARTTLS;
  505. return NS_OK;
  506. }
  507. nsresult
  508. nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
  509. {
  510. mForSTARTTLS = aForSTARTTLS;
  511. return NS_OK;
  512. }
  513. NS_IMETHODIMP
  514. nsNSSSocketInfo::ProxyStartSSL()
  515. {
  516. return ActivateSSL();
  517. }
  518. NS_IMETHODIMP
  519. nsNSSSocketInfo::StartTLS()
  520. {
  521. return ActivateSSL();
  522. }
  523. NS_IMETHODIMP
  524. nsNSSSocketInfo::SetNPNList(nsTArray<nsCString> &protocolArray)
  525. {
  526. nsNSSShutDownPreventionLock locker;
  527. if (isAlreadyShutDown())
  528. return NS_ERROR_NOT_AVAILABLE;
  529. if (!mFd)
  530. return NS_ERROR_FAILURE;
  531. // the npn list is a concatenated list of 8 bit byte strings.
  532. nsCString npnList;
  533. for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
  534. if (protocolArray[index].IsEmpty() ||
  535. protocolArray[index].Length() > 255)
  536. return NS_ERROR_ILLEGAL_VALUE;
  537. npnList.Append(protocolArray[index].Length());
  538. npnList.Append(protocolArray[index]);
  539. }
  540. if (SSL_SetNextProtoNego(
  541. mFd,
  542. reinterpret_cast<const unsigned char *>(npnList.get()),
  543. npnList.Length()) != SECSuccess)
  544. return NS_ERROR_FAILURE;
  545. return NS_OK;
  546. }
  547. static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
  548. #define NSSSOCKETINFOMAGIC { 0xa9863a23, 0x26b8, 0x4a9c, \
  549. { 0x83, 0xf1, 0xe9, 0xda, 0xdb, 0x36, 0xb8, 0x30 } }
  550. static NS_DEFINE_CID(kNSSSocketInfoMagic, NSSSOCKETINFOMAGIC);
  551. NS_IMETHODIMP
  552. nsNSSSocketInfo::Write(nsIObjectOutputStream* stream) {
  553. stream->WriteID(kNSSSocketInfoMagic);
  554. MutexAutoLock lock(mMutex);
  555. nsRefPtr<nsSSLStatus> status = mSSLStatus;
  556. nsCOMPtr<nsISerializable> certSerializable;
  557. // Write a redundant copy of the certificate for backward compatibility
  558. // with previous versions, which also unnecessarily wrote it.
  559. //
  560. // As we are reading the object our self, not using ReadObject, we have
  561. // to store it here 'manually' as well, mimicking our object stream
  562. // implementation.
  563. if (status) {
  564. nsCOMPtr<nsIX509Cert> cert = status->mServerCert;
  565. certSerializable = do_QueryInterface(cert);
  566. if (!certSerializable) {
  567. NS_ERROR("certificate is missing or isn't serializable");
  568. return NS_ERROR_UNEXPECTED;
  569. }
  570. } else {
  571. NS_WARNING("Serializing nsNSSSocketInfo without mSSLStatus");
  572. }
  573. // Store the flag if there is the certificate present
  574. stream->WriteBoolean(certSerializable);
  575. if (certSerializable) {
  576. stream->WriteID(kNSSCertificateCID);
  577. stream->WriteID(NS_GET_IID(nsISupports));
  578. certSerializable->Write(stream);
  579. }
  580. // Store the version number of the binary stream data format.
  581. // The 0xFFFF0000 mask is included to the version number
  582. // to distinguish version number from mSecurityState
  583. // field stored in times before versioning has been introduced.
  584. // This mask value has been chosen as mSecurityState could
  585. // never be assigned such value.
  586. PRUint32 version = 3;
  587. stream->Write32(version | 0xFFFF0000);
  588. stream->Write32(mSecurityState);
  589. stream->WriteWStringZ(mShortDesc.get());
  590. // XXX: uses nsNSSComponent string bundles off the main thread
  591. nsresult rv = formatErrorMessage(lock);
  592. NS_ENSURE_SUCCESS(rv, rv);
  593. stream->WriteWStringZ(mErrorMessageCached.get());
  594. stream->WriteCompoundObject(NS_ISUPPORTS_CAST(nsISSLStatus*, status),
  595. NS_GET_IID(nsISupports), true);
  596. stream->Write32((PRUint32)mSubRequestsHighSecurity);
  597. stream->Write32((PRUint32)mSubRequestsLowSecurity);
  598. stream->Write32((PRUint32)mSubRequestsBrokenSecurity);
  599. stream->Write32((PRUint32)mSubRequestsNoSecurity);
  600. return NS_OK;
  601. }
  602. static bool CheckUUIDEquals(PRUint32 m0,
  603. nsIObjectInputStream* stream,
  604. const nsCID& id)
  605. {
  606. nsID tempID;
  607. tempID.m0 = m0;
  608. stream->Read16(&tempID.m1);
  609. stream->Read16(&tempID.m2);
  610. for (int i = 0; i < 8; ++i)
  611. stream->Read8(&tempID.m3[i]);
  612. return tempID.Equals(id);
  613. }
  614. NS_IMETHODIMP
  615. nsNSSSocketInfo::Read(nsIObjectInputStream* stream) {
  616. nsresult rv;
  617. PRUint32 version;
  618. bool certificatePresent;
  619. // Check what we have here...
  620. PRUint32 UUID_0;
  621. stream->Read32(&UUID_0);
  622. if (UUID_0 == kNSSSocketInfoMagic.m0) {
  623. // It seems this stream begins with our magic ID, check it really is there
  624. if (!CheckUUIDEquals(UUID_0, stream, kNSSSocketInfoMagic))
  625. return NS_ERROR_FAILURE;
  626. // OK, this seems to be our stream, now continue to check there is
  627. // the certificate
  628. stream->ReadBoolean(&certificatePresent);
  629. stream->Read32(&UUID_0);
  630. }
  631. else {
  632. // There is no magic, assume there is a certificate present as in versions
  633. // prior to those with the magic didn't store that flag; we check the
  634. // certificate is present by cheking the CID then
  635. certificatePresent = true;
  636. }
  637. if (certificatePresent && UUID_0 == kNSSCertificateCID.m0) {
  638. // It seems there is the certificate CID present, check it now; we only
  639. // have this single certificate implementation at this time.
  640. if (!CheckUUIDEquals(UUID_0, stream, kNSSCertificateCID))
  641. return NS_ERROR_FAILURE;
  642. // OK, we have read the CID of the certificate, check the interface ID
  643. nsID tempID;
  644. stream->ReadID(&tempID);
  645. if (!tempID.Equals(NS_GET_IID(nsISupports)))
  646. return NS_ERROR_FAILURE;
  647. nsCOMPtr<nsISerializable> serializable =
  648. do_CreateInstance(kNSSCertificateCID, &rv);
  649. NS_ENSURE_SUCCESS(rv, rv);
  650. // This is the redundant copy of the certificate; just ignore it
  651. serializable->Read(stream);
  652. // We are done with reading the certificate, now read the version
  653. // as we did before.
  654. stream->Read32(&version);
  655. }
  656. else {
  657. // There seems not to be the certificate present in the stream.
  658. version = UUID_0;
  659. }
  660. MutexAutoLock lock(mMutex);
  661. // If the version field we have just read is not masked with 0xFFFF0000
  662. // then it is stored mSecurityState field and this is version 1 of
  663. // the binary data stream format.
  664. if ((version & 0xFFFF0000) == 0xFFFF0000) {
  665. version &= ~0xFFFF0000;
  666. stream->Read32(&mSecurityState);
  667. }
  668. else {
  669. mSecurityState = version;
  670. version = 1;
  671. }
  672. stream->ReadString(mShortDesc);
  673. stream->ReadString(mErrorMessageCached);
  674. mErrorCode = 0;
  675. nsCOMPtr<nsISupports> obj;
  676. stream->ReadObject(true, getter_AddRefs(obj));
  677. mSSLStatus = reinterpret_cast<nsSSLStatus*>(obj.get());
  678. if (!mSSLStatus) {
  679. NS_WARNING("deserializing nsNSSSocketInfo without mSSLStatus");
  680. }
  681. if (version >= 2) {
  682. stream->Read32((PRUint32*)&mSubRequestsHighSecurity);
  683. stream->Read32((PRUint32*)&mSubRequestsLowSecurity);
  684. stream->Read32((PRUint32*)&mSubRequestsBrokenSecurity);
  685. stream->Read32((PRUint32*)&mSubRequestsNoSecurity);
  686. }
  687. else {
  688. mSubRequestsHighSecurity = 0;
  689. mSubRequestsLowSecurity = 0;
  690. mSubRequestsBrokenSecurity = 0;
  691. mSubRequestsNoSecurity = 0;
  692. }
  693. return NS_OK;
  694. }
  695. NS_IMETHODIMP
  696. nsNSSSocketInfo::GetInterfaces(PRUint32 *count, nsIID * **array)
  697. {
  698. *count = 0;
  699. *array = nsnull;
  700. return NS_OK;
  701. }
  702. NS_IMETHODIMP
  703. nsNSSSocketInfo::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
  704. {
  705. *_retval = nsnull;
  706. return NS_OK;
  707. }
  708. NS_IMETHODIMP
  709. nsNSSSocketInfo::GetContractID(char * *aContractID)
  710. {
  711. *aContractID = nsnull;
  712. return NS_OK;
  713. }
  714. NS_IMETHODIMP
  715. nsNSSSocketInfo::GetClassDescription(char * *aClassDescription)
  716. {
  717. *aClassDescription = nsnull;
  718. return NS_OK;
  719. }
  720. NS_IMETHODIMP
  721. nsNSSSocketInfo::GetClassID(nsCID * *aClassID)
  722. {
  723. *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
  724. if (!*aClassID)
  725. return NS_ERROR_OUT_OF_MEMORY;
  726. return GetClassIDNoAlloc(*aClassID);
  727. }
  728. NS_IMETHODIMP
  729. nsNSSSocketInfo::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
  730. {
  731. *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
  732. return NS_OK;
  733. }
  734. NS_IMETHODIMP
  735. nsNSSSocketInfo::GetFlags(PRUint32 *aFlags)
  736. {
  737. *aFlags = 0;
  738. return NS_OK;
  739. }
  740. static NS_DEFINE_CID(kNSSSocketInfoCID, NS_NSSSOCKETINFO_CID);
  741. NS_IMETHODIMP
  742. nsNSSSocketInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
  743. {
  744. *aClassIDNoAlloc = kNSSSocketInfoCID;
  745. return NS_OK;
  746. }
  747. nsresult nsNSSSocketInfo::ActivateSSL()
  748. {
  749. nsNSSShutDownPreventionLock locker;
  750. if (isAlreadyShutDown())
  751. return NS_ERROR_NOT_AVAILABLE;
  752. if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
  753. return NS_ERROR_FAILURE;
  754. if (SECSuccess != SSL_ResetHandshake(mFd, false))
  755. return NS_ERROR_FAILURE;
  756. mHandshakePending = true;
  757. return NS_OK;
  758. }
  759. nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
  760. {
  761. *aFilePtr = mFd;
  762. return NS_OK;
  763. }
  764. nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
  765. {
  766. mFd = aFilePtr;
  767. return NS_OK;
  768. }
  769. class PreviousCertRunnable : public SyncRunnableBase
  770. {
  771. public:
  772. PreviousCertRunnable(nsIInterfaceRequestor * callbacks)
  773. : mCallbacks(callbacks)
  774. {
  775. }
  776. virtual void RunOnTargetThread()
  777. {
  778. nsCOMPtr<nsISecureBrowserUI> secureUI;
  779. getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
  780. nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
  781. if (statusProvider) {
  782. nsCOMPtr<nsISSLStatus> status;
  783. (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
  784. if (status) {
  785. (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
  786. }
  787. }
  788. }
  789. nsCOMPtr<nsIX509Cert> mPreviousCert; // out
  790. private:
  791. nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
  792. };
  793. void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
  794. {
  795. NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
  796. *_result = nsnull;
  797. nsRefPtr<PreviousCertRunnable> runnable = new PreviousCertRunnable(mCallbacks);
  798. nsresult rv = runnable->DispatchToMainThreadAndWait();
  799. NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
  800. runnable->mPreviousCert.forget(_result);
  801. }
  802. void
  803. nsNSSSocketInfo::SetCertVerificationWaiting()
  804. {
  805. // mCertVerificationState may be before_cert_verification for the first
  806. // handshake on the connection, or after_cert_verification for subsequent
  807. // renegotiation handshakes.
  808. NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
  809. "Invalid state transition to waiting_for_cert_verification");
  810. mCertVerificationState = waiting_for_cert_verification;
  811. mCertVerificationStarted = PR_IntervalNow();
  812. }
  813. // Be careful that SetCertVerificationResult does NOT get called while we are
  814. // processing a SSL callback function, because SSL_AuthCertificateComplete will
  815. // attempt to acquire locks that are already held by libssl when it calls
  816. // callbacks.
  817. void
  818. nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
  819. SSLErrorMessageType errorMessageType)
  820. {
  821. NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
  822. "Invalid state transition to cert_verification_finished");
  823. mCertVerificationEnded = PR_IntervalNow();
  824. if (mFd) {
  825. SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
  826. // Only replace errorCode if there was originally no error
  827. if (rv != SECSuccess && errorCode == 0) {
  828. errorCode = PR_GetError();
  829. errorMessageType = PlainErrorMessage;
  830. if (errorCode == 0) {
  831. NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
  832. errorCode = PR_INVALID_STATE_ERROR;
  833. }
  834. }
  835. }
  836. if (errorCode) {
  837. SetCanceled(errorCode, errorMessageType);
  838. }
  839. mCertVerificationState = after_cert_verification;
  840. }
  841. nsresult nsNSSSocketInfo::GetSSLStatus(nsISSLStatus** _result)
  842. {
  843. NS_ENSURE_ARG_POINTER(_result);
  844. *_result = mSSLStatus;
  845. NS_IF_ADDREF(*_result);
  846. return NS_OK;
  847. }
  848. nsresult nsNSSSocketInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
  849. {
  850. mSSLStatus = aSSLStatus;
  851. return NS_OK;
  852. }
  853. void nsNSSSocketInfo::SetHandshakeInProgress(bool aIsIn)
  854. {
  855. mHandshakeInProgress = aIsIn;
  856. if (mHandshakeInProgress && !mHandshakeStartTime)
  857. {
  858. mHandshakeStartTime = PR_IntervalNow();
  859. }
  860. }
  861. void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
  862. {
  863. mAllowTLSIntoleranceTimeout = aAllow;
  864. }
  865. #define HANDSHAKE_TIMEOUT_SECONDS 25
  866. bool nsNSSSocketInfo::HandshakeTimeout()
  867. {
  868. if (mCertVerificationState == waiting_for_cert_verification) {
  869. // Do not do a TLS interlerance timeout during cert verification because:
  870. //
  871. // * If we would have timed out, but cert verification is still ongoing,
  872. // then the handshake probably already completed, and it is probably the
  873. // certificate validation (OCSP responder or similar) that is timing
  874. // out.
  875. // * If certificate validation AND the handshake is slow, then that is a
  876. // good indication that the network is bad, and so the problem probably
  877. // isn't the server being TLS intolerant.
  878. // * When we timeout, we return non-zero flags from PR_Poll, which will
  879. // cause the application to try to read from and/or write to the socket,
  880. // possibly in a loop. But, it is likely that the socket is blocked on
  881. // cert authentication, so those read and/or write calls would result in
  882. // PR_WOULD_BLOCK_ERROR, causing the application to spin.
  883. return false;
  884. }
  885. if (!mHandshakeInProgress || !mAllowTLSIntoleranceTimeout)
  886. return false;
  887. PRIntervalTime now = PR_IntervalNow();
  888. PRIntervalTime certVerificationTime =
  889. mCertVerificationEnded - mCertVerificationStarted;
  890. PRIntervalTime totalTime = now - mHandshakeStartTime;
  891. PRIntervalTime totalTimeExceptCertVerificationTime =
  892. totalTime - certVerificationTime;
  893. return totalTimeExceptCertVerificationTime >
  894. PR_SecondsToInterval(HANDSHAKE_TIMEOUT_SECONDS);
  895. }
  896. void nsSSLIOLayerHelpers::Cleanup()
  897. {
  898. if (mTLSIntolerantSites) {
  899. delete mTLSIntolerantSites;
  900. mTLSIntolerantSites = nsnull;
  901. }
  902. if (mTLSTolerantSites) {
  903. delete mTLSTolerantSites;
  904. mTLSTolerantSites = nsnull;
  905. }
  906. if (mRenegoUnrestrictedSites) {
  907. delete mRenegoUnrestrictedSites;
  908. mRenegoUnrestrictedSites = nsnull;
  909. }
  910. if (mutex) {
  911. delete mutex;
  912. mutex = nsnull;
  913. }
  914. if (mHostsWithCertErrors) {
  915. delete mHostsWithCertErrors;
  916. mHostsWithCertErrors = nsnull;
  917. }
  918. }
  919. /* Formats an error message for non-certificate-related SSL errors
  920. * and non-overridable certificate errors (both are of type
  921. * PlainErrormMessage). Use formatOverridableCertErrorMessage
  922. * for overridable cert errors.
  923. */
  924. static nsresult
  925. formatPlainErrorMessage(const nsXPIDLCString &host, PRInt32 port,
  926. PRErrorCode err, nsString &returnedMessage)
  927. {
  928. const PRUnichar *params[1];
  929. nsresult rv;
  930. nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
  931. NS_ENSURE_SUCCESS(rv, rv);
  932. if (host.Length())
  933. {
  934. nsString hostWithPort;
  935. // For now, hide port when it's 443 and we're reporting the error.
  936. // In the future a better mechanism should be used
  937. // to make a decision about showing the port number, possibly by requiring
  938. // the context object to implement a specific interface.
  939. // The motivation is that Mozilla browser would like to hide the port number
  940. // in error pages in the common case.
  941. hostWithPort.AssignASCII(host);
  942. if (port != 443) {
  943. hostWithPort.AppendLiteral(":");
  944. hostWithPort.AppendInt(port);
  945. }
  946. params[0] = hostWithPort.get();
  947. nsString formattedString;
  948. rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix",
  949. params, 1,
  950. formattedString);
  951. if (NS_SUCCEEDED(rv))
  952. {
  953. returnedMessage.Append(formattedString);
  954. returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
  955. }
  956. }
  957. nsString explanation;
  958. rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
  959. if (NS_SUCCEEDED(rv))
  960. returnedMessage.Append(explanation);
  961. return NS_OK;
  962. }
  963. static void
  964. AppendErrorTextUntrusted(PRErrorCode errTrust,
  965. const nsString &host,
  966. nsIX509Cert* ix509,
  967. nsINSSComponent *component,
  968. nsString &returnedMessage)
  969. {
  970. const char *errorID = nsnull;
  971. nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
  972. if (cert3) {
  973. bool isSelfSigned;
  974. if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
  975. && isSelfSigned) {
  976. errorID = "certErrorTrust_SelfSigned";
  977. }
  978. }
  979. if (!errorID) {
  980. switch (errTrust) {
  981. case SEC_ERROR_UNKNOWN_ISSUER:
  982. {
  983. nsCOMPtr<nsIArray> chain;
  984. ix509->GetChain(getter_AddRefs(chain));
  985. PRUint32 length = 0;
  986. if (chain && NS_FAILED(chain->GetLength(&length)))
  987. length = 0;
  988. if (length == 1)
  989. errorID = "certErrorTrust_MissingChain";
  990. else
  991. errorID = "certErrorTrust_UnknownIssuer";
  992. break;
  993. }
  994. case SEC_ERROR_INADEQUATE_KEY_USAGE:
  995. // Should get an individual string in the future
  996. // For now, use the same as CaInvalid
  997. case SEC_ERROR_CA_CERT_INVALID:
  998. errorID = "certErrorTrust_CaInvalid";
  999. break;
  1000. case SEC_ERROR_UNTRUSTED_ISSUER:
  1001. errorID = "certErrorTrust_Issuer";
  1002. break;
  1003. case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
  1004. errorID = "certErrorTrust_ExpiredIssuer";
  1005. break;
  1006. case SEC_ERROR_UNTRUSTED_CERT:
  1007. default:
  1008. errorID = "certErrorTrust_Untrusted";
  1009. break;
  1010. }
  1011. }
  1012. nsString formattedString;
  1013. nsresult rv = component->GetPIPNSSBundleString(errorID,
  1014. formattedString);
  1015. if (NS_SUCCEEDED(rv))
  1016. {
  1017. returnedMessage.Append(formattedString);
  1018. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1019. }
  1020. }
  1021. // returns TRUE if SAN was used to produce names
  1022. // return FALSE if nothing was produced
  1023. // names => a single name or a list of names
  1024. // multipleNames => whether multiple names were delivered
  1025. static bool
  1026. GetSubjectAltNames(CERTCertificate *nssCert,
  1027. nsINSSComponent *component,
  1028. nsString &allNames,
  1029. PRUint32 &nameCount)
  1030. {
  1031. allNames.Truncate();
  1032. nameCount = 0;
  1033. PRArenaPool *san_arena = nsnull;
  1034. SECItem altNameExtension = {siBuffer, NULL, 0 };
  1035. CERTGeneralName *sanNameList = nsnull;
  1036. nsresult rv;
  1037. rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
  1038. &altNameExtension);
  1039. if (rv != SECSuccess)
  1040. return false;
  1041. san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1042. if (!san_arena)
  1043. return false;
  1044. sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
  1045. if (!sanNameList)
  1046. return false;
  1047. SECITEM_FreeItem(&altNameExtension, false);
  1048. CERTGeneralName *current = sanNameList;
  1049. do {
  1050. nsAutoString name;
  1051. switch (current->type) {
  1052. case certDNSName:
  1053. name.AssignASCII((char*)current->name.other.data, current->name.other.len);
  1054. if (!allNames.IsEmpty()) {
  1055. allNames.Append(NS_LITERAL_STRING(" , "));
  1056. }
  1057. ++nameCount;
  1058. allNames.Append(name);
  1059. break;
  1060. case certIPAddress:
  1061. {
  1062. char buf[INET6_ADDRSTRLEN];
  1063. PRNetAddr addr;
  1064. if (current->name.other.len == 4) {
  1065. addr.inet.family = PR_AF_INET;
  1066. memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
  1067. PR_NetAddrToString(&addr, buf, sizeof(buf));
  1068. name.AssignASCII(buf);
  1069. } else if (current->name.other.len == 16) {
  1070. addr.ipv6.family = PR_AF_INET6;
  1071. memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
  1072. PR_NetAddrToString(&addr, buf, sizeof(buf));
  1073. name.AssignASCII(buf);
  1074. } else {
  1075. /* invalid IP address */
  1076. }
  1077. if (!name.IsEmpty()) {
  1078. if (!allNames.IsEmpty()) {
  1079. allNames.Append(NS_LITERAL_STRING(" , "));
  1080. }
  1081. ++nameCount;
  1082. allNames.Append(name);
  1083. }
  1084. break;
  1085. }
  1086. default: // all other types of names are ignored
  1087. break;
  1088. }
  1089. current = CERT_GetNextGeneralName(current);
  1090. } while (current != sanNameList); // double linked
  1091. PORT_FreeArena(san_arena, false);
  1092. return true;
  1093. }
  1094. static void
  1095. AppendErrorTextMismatch(const nsString &host,
  1096. nsIX509Cert* ix509,
  1097. nsINSSComponent *component,
  1098. nsString &returnedMessage)
  1099. {
  1100. const PRUnichar *params[1];
  1101. nsresult rv;
  1102. CERTCertificate *nssCert = NULL;
  1103. CERTCertificateCleaner nssCertCleaner(nssCert);
  1104. nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
  1105. if (cert2)
  1106. nssCert = cert2->GetCert();
  1107. if (!nssCert) {
  1108. // We are unable to extract the valid names, say "not valid for name".
  1109. params[0] = host.get();
  1110. nsString formattedString;
  1111. rv = component->PIPBundleFormatStringFromName("certErrorMismatch",
  1112. params, 1,
  1113. formattedString);
  1114. if (NS_SUCCEEDED(rv)) {
  1115. returnedMessage.Append(formattedString);
  1116. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1117. }
  1118. return;
  1119. }
  1120. nsString allNames;
  1121. PRUint32 nameCount = 0;
  1122. bool useSAN = false;
  1123. if (nssCert)
  1124. useSAN = GetSubjectAltNames(nssCert, component, allNames, nameCount);
  1125. if (!useSAN) {
  1126. char *certName = nsnull;
  1127. // currently CERT_FindNSStringExtension is not being exported by NSS.
  1128. // If it gets exported, enable the following line.
  1129. // certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
  1130. // However, it has been discussed to treat the extension as obsolete and ignore it.
  1131. if (!certName)
  1132. certName = CERT_GetCommonName(&nssCert->subject);
  1133. if (certName) {
  1134. ++nameCount;
  1135. allNames.AssignASCII(certName);
  1136. PORT_Free(certName);
  1137. }
  1138. }
  1139. if (nameCount > 1) {
  1140. nsString message;
  1141. rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple",
  1142. message);
  1143. if (NS_SUCCEEDED(rv)) {
  1144. returnedMessage.Append(message);
  1145. returnedMessage.Append(NS_LITERAL_STRING("\n "));
  1146. returnedMessage.Append(allNames);
  1147. returnedMessage.Append(NS_LITERAL_STRING(" \n"));
  1148. }
  1149. }
  1150. else if (nameCount == 1) {
  1151. const PRUnichar *params[1];
  1152. params[0] = allNames.get();
  1153. nsString formattedString;
  1154. rv = component->PIPBundleFormatStringFromName("certErrorMismatchSingle2",
  1155. params, 1,
  1156. formattedString);
  1157. if (NS_SUCCEEDED(rv)) {
  1158. returnedMessage.Append(formattedString);
  1159. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1160. }
  1161. }
  1162. else { // nameCount == 0
  1163. nsString message;
  1164. nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
  1165. message);
  1166. if (NS_SUCCEEDED(rv)) {
  1167. returnedMessage.Append(message);
  1168. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1169. }
  1170. }
  1171. }
  1172. static void
  1173. GetDateBoundary(nsIX509Cert* ix509,
  1174. nsString &formattedDate,
  1175. nsString &nowDate,
  1176. bool &trueExpired_falseNotYetValid)
  1177. {
  1178. trueExpired_falseNotYetValid = true;
  1179. formattedDate.Truncate();
  1180. PRTime notAfter, notBefore, timeToUse;
  1181. nsCOMPtr<nsIX509CertValidity> validity;
  1182. nsresult rv;
  1183. rv = ix509->GetValidity(getter_AddRefs(validity));
  1184. if (NS_FAILED(rv))
  1185. return;
  1186. rv = validity->GetNotAfter(&notAfter);
  1187. if (NS_FAILED(rv))
  1188. return;
  1189. rv = validity->GetNotBefore(&notBefore);
  1190. if (NS_FAILED(rv))
  1191. return;
  1192. PRTime now = PR_Now();
  1193. if (LL_CMP(now, >, notAfter)) {
  1194. timeToUse = notAfter;
  1195. } else {
  1196. timeToUse = notBefore;
  1197. trueExpired_falseNotYetValid = false;
  1198. }
  1199. nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
  1200. if (NS_FAILED(rv))
  1201. return;
  1202. dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort,
  1203. kTimeFormatNoSeconds, timeToUse,
  1204. formattedDate);
  1205. dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort,
  1206. kTimeFormatNoSeconds, now,
  1207. nowDate);
  1208. }
  1209. static void
  1210. AppendErrorTextTime(nsIX509Cert* ix509,
  1211. nsINSSComponent *component,
  1212. nsString &returnedMessage)
  1213. {
  1214. nsAutoString formattedDate, nowDate;
  1215. bool trueExpired_falseNotYetValid;
  1216. GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
  1217. const PRUnichar *params[2];
  1218. params[0] = formattedDate.get(); // might be empty, if helper function had a problem
  1219. params[1] = nowDate.get();
  1220. const char *key = trueExpired_falseNotYetValid ?
  1221. "certErrorExpiredNow" : "certErrorNotYetValidNow";
  1222. nsresult rv;
  1223. nsString formattedString;
  1224. rv = component->PIPBundleFormatStringFromName(
  1225. key,
  1226. params,
  1227. ArrayLength(params),
  1228. formattedString);
  1229. if (NS_SUCCEEDED(rv))
  1230. {
  1231. returnedMessage.Append(formattedString);
  1232. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1233. }
  1234. }
  1235. static void
  1236. AppendErrorTextCode(PRErrorCode errorCodeToReport,
  1237. nsINSSComponent *component,
  1238. nsString &returnedMessage)
  1239. {
  1240. const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
  1241. if (codeName)
  1242. {
  1243. nsCString error_id(codeName);
  1244. ToLowerCase(error_id);
  1245. NS_ConvertASCIItoUTF16 idU(error_id);
  1246. const PRUnichar *params[1];
  1247. params[0] = idU.get();
  1248. nsString formattedString;
  1249. nsresult rv;
  1250. rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
  1251. params, 1,
  1252. formattedString);
  1253. if (NS_SUCCEEDED(rv)) {
  1254. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1255. returnedMessage.Append(formattedString);
  1256. returnedMessage.Append(NS_LITERAL_STRING("\n"));
  1257. }
  1258. else {
  1259. returnedMessage.Append(NS_LITERAL_STRING(" ("));
  1260. returnedMessage.Append(idU);
  1261. returnedMessage.Append(NS_LITERAL_STRING(")"));
  1262. }
  1263. }
  1264. }
  1265. /* Formats an error message for overridable certificate errors (of type
  1266. * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
  1267. * non-overridable cert errors and non-cert-related errors.
  1268. */
  1269. static nsresult
  1270. formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
  1271. PRErrorCode errorCodeToReport,
  1272. const nsXPIDLCString & host, PRInt32 port,
  1273. nsString & returnedMessage)
  1274. {
  1275. const PRUnichar *params[1];
  1276. nsresult rv;
  1277. nsAutoString hostWithPort;
  1278. nsAutoString hostWithoutPort;
  1279. // For now, hide port when it's 443 and we're reporting the error.
  1280. // In the future a better mechanism should be used
  1281. // to make a decision about showing the port number, possibly by requiring
  1282. // the context object to implement a specific interface.
  1283. // The motivation is that Mozilla browser would like to hide the port number
  1284. // in error pages in the common case.
  1285. hostWithoutPort.AppendASCII(host);
  1286. if (port == 443) {
  1287. params[0] = hostWithoutPort.get();
  1288. } else {
  1289. hostWithPort.AppendASCII(host);
  1290. hostWithPort.Append(':');
  1291. hostWithPort.AppendInt(port);
  1292. params[0] = hostWithPort.get();
  1293. }
  1294. nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
  1295. NS_ENSURE_SUCCESS(rv, rv);
  1296. returnedMessage.Truncate();
  1297. rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
  1298. returnedMessage);
  1299. NS_ENSURE_SUCCESS(rv, rv);
  1300. returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
  1301. nsRefPtr<nsIX509Cert> ix509;
  1302. rv = sslStatus.GetServerCert(getter_AddRefs(ix509));
  1303. NS_ENSURE_SUCCESS(rv, rv);
  1304. bool isUntrusted;
  1305. rv = sslStatus.GetIsUntrusted(&isUntrusted);
  1306. NS_ENSURE_SUCCESS(rv, rv);
  1307. if (isUntrusted) {
  1308. AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509,
  1309. component, returnedMessage);
  1310. }
  1311. bool isDomainMismatch;
  1312. rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
  1313. NS_ENSURE_SUCCESS(rv, rv);
  1314. if (isDomainMismatch) {
  1315. AppendErrorTextMismatch(hostWithoutPort, ix509, component, returnedMessage);
  1316. }
  1317. bool isNotValidAtThisTime;
  1318. rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
  1319. NS_ENSURE_SUCCESS(rv, rv);
  1320. if (isNotValidAtThisTime) {
  1321. AppendErrorTextTime(ix509, component, returnedMessage);
  1322. }
  1323. AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
  1324. return NS_OK;
  1325. }
  1326. static void
  1327. nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRErrorCode err)
  1328. {
  1329. if (!NS_IsMainThread()) {
  1330. NS_ERROR("nsHandleSSLError called off the main thread");
  1331. return;
  1332. }
  1333. // SetCanceled is only called by the main thread or the socket transport
  1334. // thread. Whenever this function is called on the main thread, the SSL
  1335. // thread is blocked on it. So, no mutex is necessary for
  1336. // SetCanceled()/GetError*().
  1337. if (socketInfo->GetErrorCode()) {
  1338. // If the socket has been flagged as canceled,
  1339. // the code who did was responsible for setting the error code.
  1340. return;
  1341. }
  1342. nsresult rv;
  1343. NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
  1344. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
  1345. if (NS_FAILED(rv))
  1346. return;
  1347. nsXPIDLCString hostName;
  1348. socketInfo->GetHostName(getter_Copies(hostName));
  1349. PRInt32 port;
  1350. socketInfo->GetPort(&port);
  1351. // Try to get a nsISSLErrorListener implementation from the socket consumer.
  1352. nsCOMPtr<nsIInterfaceRequestor> cb;
  1353. socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
  1354. if (cb) {
  1355. nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
  1356. if (sel) {
  1357. nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
  1358. nsCString hostWithPortString = hostName;
  1359. hostWithPortString.AppendLiteral(":");
  1360. hostWithPortString.AppendInt(port);
  1361. bool suppressMessage = false; // obsolete, ignored
  1362. rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
  1363. }
  1364. }
  1365. socketInfo->SetCanceled(err, PlainErrorMessage);
  1366. }
  1367. namespace {
  1368. enum Operation { reading, writing, not_reading_or_writing };
  1369. PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
  1370. PRFileDesc* ssl_layer_fd,
  1371. nsNSSSocketInfo *socketInfo);
  1372. nsNSSSocketInfo *
  1373. getSocketInfoIfRunning(PRFileDesc * fd, Operation op,
  1374. const nsNSSShutDownPreventionLock & /*proofOfLock*/)
  1375. {
  1376. if (!fd || !fd->lower || !fd->secret ||
  1377. fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
  1378. NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
  1379. PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1380. return nsnull;
  1381. }
  1382. nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
  1383. if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
  1384. PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
  1385. return nsnull;
  1386. }
  1387. if (socketInfo->GetErrorCode()) {
  1388. PRErrorCode err = socketInfo->GetErrorCode();
  1389. PR_SetError(err, 0);
  1390. if (op == reading || op == writing) {
  1391. // We must do TLS intolerance checks for reads and writes, for timeouts
  1392. // in particular.
  1393. (void) checkHandshake(-1, op == reading, fd, socketInfo);
  1394. }
  1395. // If we get here, it is probably because cert verification failed and this
  1396. // is the first I/O attempt since that failure.
  1397. return nsnull;
  1398. }
  1399. return socketInfo;
  1400. }
  1401. } // unnnamed namespace
  1402. static PRStatus PR_CALLBACK
  1403. nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
  1404. PRIntervalTime timeout)
  1405. {
  1406. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
  1407. nsNSSShutDownPreventionLock locker;
  1408. if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
  1409. return PR_FAILURE;
  1410. PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
  1411. if (status != PR_SUCCESS) {
  1412. PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
  1413. (void*)fd, PR_GetError()));
  1414. return status;
  1415. }
  1416. PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
  1417. return status;
  1418. }
  1419. // nsPSMRememberCertErrorsTable
  1420. nsPSMRememberCertErrorsTable::nsPSMRememberCertErrorsTable()
  1421. {
  1422. mErrorHosts.Init(16);
  1423. }
  1424. nsresult
  1425. nsPSMRememberCertErrorsTable::GetHostPortKey(nsNSSSocketInfo* infoObject,
  1426. nsCAutoString &result)
  1427. {
  1428. nsresult rv;
  1429. result.Truncate();
  1430. nsXPIDLCString hostName;
  1431. rv = infoObject->GetHostName(getter_Copies(hostName));
  1432. NS_ENSURE_SUCCESS(rv, rv);
  1433. PRInt32 port;
  1434. rv = infoObject->GetPort(&port);
  1435. NS_ENSURE_SUCCESS(rv, rv);
  1436. result.Assign(hostName);
  1437. result.Append(':');
  1438. result.AppendInt(port);
  1439. return NS_OK;
  1440. }
  1441. void
  1442. nsPSMRememberCertErrorsTable::RememberCertHasError(nsNSSSocketInfo* infoObject,
  1443. nsSSLStatus* status,
  1444. SECStatus certVerificationResult)
  1445. {
  1446. nsresult rv;
  1447. nsCAutoString hostPortKey;
  1448. rv = GetHostPortKey(infoObject, hostPortKey);
  1449. if (NS_FAILED(rv))
  1450. return;
  1451. if (certVerificationResult != SECSuccess) {
  1452. NS_ASSERTION(status,
  1453. "Must have nsSSLStatus object when remembering flags");
  1454. if (!status)
  1455. return;
  1456. CertStateBits b