LCOV - code coverage report
Current view: directory - security/manager/ssl/src - SSLServerCertVerification.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 422 131 31.0 %
Date: 2012-06-02 Functions: 32 19 59.4 %

       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                 : 
      44                 : /* 
      45                 :  * For connections that are not processed on the socket transport thread, we do
      46                 :  * NOT use the async logic described below. Instead, we authenticate the
      47                 :  * certificate on the thread that the connection's I/O happens on,
      48                 :  * synchronously. This allows us to do certificate verification for blocking
      49                 :  * (not non-blocking) sockets and sockets that have their I/O processed on a
      50                 :  * thread other than the socket transport service thread. Also, we DO NOT
      51                 :  * support blocking sockets on the socket transport service thread at all.
      52                 :  *
      53                 :  * During certificate authentication, we call CERT_PKIXVerifyCert or
      54                 :  * CERT_VerifyCert. These functions may make zero or more HTTP requests
      55                 :  * for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
      56                 :  * for these requests processes them on the socket transport service thread.
      57                 :  *
      58                 :  * If the connection for which we are verifying the certificate is happening
      59                 :  * on the socket transport thread (the usually case, at least for HTTP), then
      60                 :  * if our cert auth hook were to call the CERT_*Verify* functions directly,
      61                 :  * there would be a deadlock: The CERT_*Verify* function would cause an event
      62                 :  * to be asynchronously posted to the socket transport thread, and then it
      63                 :  * would block the socket transport thread waiting to be notified of the HTTP
      64                 :  * response. However, the HTTP request would never actually be processed
      65                 :  * because the socket transport thread would be blocked and so it wouldn't be
      66                 :  * able process HTTP requests. (i.e. Deadlock.)
      67                 :  *
      68                 :  * Consequently, when we are asked to verify a certificate on the socket
      69                 :  * transport service thread, we must always call the CERT_*Verify* cert
      70                 :  * functions on another thread. To accomplish this, our auth cert hook
      71                 :  * dispatches a SSLServerCertVerificationJob to a pool of background threads,
      72                 :  * and then immediatley return SECWouldBlock to libssl. These jobs are where
      73                 :  * the CERT_*Verify* functions are actually called. 
      74                 :  *
      75                 :  * When our auth cert hook returns SECWouldBlock, libssl will carry on the
      76                 :  * handshake while we validate the certificate. This will free up the socket
      77                 :  * transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
      78                 :  * requests needed for cert verification as mentioned above--can be processed.
      79                 :  *
      80                 :  * Once the CERT_*Verify* function returns, the cert verification job
      81                 :  * dispatches a SSLServerCertVerificationResult to the socket transport thread;
      82                 :  * the SSLServerCertVerificationResult will notify libssl that the certificate
      83                 :  * authentication is complete. Once libssl is notified that the authentication
      84                 :  * is complete, it will continue the SSL handshake (if it hasn't already
      85                 :  * finished) and it will begin allowing us to send/receive data on the
      86                 :  * connection.
      87                 :  *
      88                 :  * Timeline of events (for connections managed by the socket transport service):
      89                 :  *
      90                 :  *    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
      91                 :  *      transport thread.
      92                 :  *    * SSLServerCertVerificationJob::Dispatch queues a job
      93                 :  *      (instance of SSLServerCertVerificationJob) to its background thread
      94                 :  *      pool and returns.
      95                 :  *    * One of the background threads calls CERT_*Verify*, which may enqueue
      96                 :  *      some HTTP request(s) onto the socket transport thread, and then
      97                 :  *      blocks that background thread waiting for the responses and/or timeouts
      98                 :  *      or errors for those requests.
      99                 :  *    * Once those HTTP responses have all come back or failed, the
     100                 :  *      CERT_*Verify* function returns a result indicating that the validation
     101                 :  *      succeeded or failed.
     102                 :  *    * If the validation succeeded, then a SSLServerCertVerificationResult
     103                 :  *      event is posted to the socket transport thread, and the cert
     104                 :  *      verification thread becomes free to verify other certificates.
     105                 :  *    * Otherwise, a CertErrorRunnable is posted to the socket transport thread
     106                 :  *      and then to the main thread (blocking both, see CertErrorRunnable) to
     107                 :  *      do cert override processing and bad cert listener notification. Then
     108                 :  *      the cert verification thread becomes free to verify other certificates.
     109                 :  *    * After processing cert overrides, the CertErrorRunnable will dispatch a
     110                 :  *      SSLServerCertVerificationResult event to the socket transport thread to
     111                 :  *      notify it of the result of the override processing; then it returns,
     112                 :  *      freeing up the main thread.
     113                 :  *    * The SSLServerCertVerificationResult event will either wake up the 
     114                 :  *      socket (using SSL_RestartHandshakeAfterServerCert) if validation
     115                 :  *      succeeded or there was an error override, or it will set an error flag
     116                 :  *      so that the next I/O operation on the socket will fail, causing the
     117                 :  *      socket transport thread to close the connection.
     118                 :  *
     119                 :  * Cert override processing must happen on the main thread because it accesses
     120                 :  * the nsICertOverrideService, and that service must be accessed on the main 
     121                 :  * thread because some extensions (Selenium, in particular) replace it with a
     122                 :  * Javascript implementation, and chrome JS must always be run on the main
     123                 :  * thread.
     124                 :  *
     125                 :  * SSLServerCertVerificationResult must be dispatched to the socket transport
     126                 :  * thread because we must only call SSL_* functions on the socket transport
     127                 :  * thread since they may do I/O, because many parts of nsNSSSocketInfo and
     128                 :  * the PSM NSS I/O layer are not thread-safe, and because we need the event to
     129                 :  * interrupt the PR_Poll that may waiting for I/O on the socket for which we
     130                 :  * are validating the cert.
     131                 :  */
     132                 : 
     133                 : #include "SSLServerCertVerification.h"
     134                 : #include "nsIBadCertListener2.h"
     135                 : #include "nsICertOverrideService.h"
     136                 : #include "nsIStrictTransportSecurityService.h"
     137                 : #include "nsNSSComponent.h"
     138                 : #include "nsNSSCleaner.h"
     139                 : #include "nsRecentBadCerts.h"
     140                 : #include "nsNSSIOLayer.h"
     141                 : 
     142                 : #include "mozilla/Assertions.h"
     143                 : #include "nsIThreadPool.h"
     144                 : #include "nsXPCOMCIDInternal.h"
     145                 : #include "nsComponentManagerUtils.h"
     146                 : #include "nsServiceManagerUtils.h"
     147                 : #include "PSMRunnable.h"
     148                 : 
     149                 : #include "ssl.h"
     150                 : #include "secerr.h"
     151                 : #include "secport.h"
     152                 : #include "sslerr.h"
     153                 : 
     154                 : #ifdef PR_LOGGING
     155                 : extern PRLogModuleInfo* gPIPNSSLog;
     156                 : #endif
     157                 : 
     158                 : namespace mozilla { namespace psm {
     159                 : 
     160                 : namespace {
     161                 : 
     162                 : NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     163                 : 
     164               8 : NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
     165               0 : NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, false)
     166                 : 
     167                 : // do not use a nsCOMPtr to avoid static initializer/destructor
     168                 : nsIThreadPool * gCertVerificationThreadPool = nsnull;
     169                 : } // unnamed namespace
     170                 : 
     171                 : // Called when the socket transport thread starts, to initialize the SSL cert
     172                 : // verification thread pool. By tying the thread pool startup/shutdown directly
     173                 : // to the STS thread's lifetime, we ensure that they are *always* available for
     174                 : // SSL connections and that there are no races during startup and especially
     175                 : // shutdown. (Previously, we have had multiple problems with races in PSM
     176                 : // background threads, and the race-prevention/shutdown logic used there is
     177                 : // brittle. Since this service is critical to things like downloading updates,
     178                 : // we take no chances.) Also, by doing things this way, we avoid the need for
     179                 : // locks, since gCertVerificationThreadPool is only ever accessed on the socket
     180                 : // transport thread.
     181                 : void
     182            1426 : InitializeSSLServerCertVerificationThreads()
     183                 : {
     184                 :   // TODO: tuning, make parameters preferences
     185                 :   // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
     186                 :   // Currently, the nsThreadPool.h header isn't exported for us to do so.
     187                 :   nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
     188            1426 :                                    &gCertVerificationThreadPool);
     189            1426 :   if (NS_FAILED(rv)) {
     190               0 :     NS_WARNING("Failed to create SSL cert verification threads.");
     191               0 :     return;
     192                 :   }
     193                 : 
     194            1426 :   (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
     195            1426 :   (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
     196            1426 :   (void) gCertVerificationThreadPool->SetThreadLimit(5);
     197                 : }
     198                 : 
     199                 : // Called when the socket transport thread finishes, to destroy the thread
     200                 : // pool. Since the socket transport service has stopped processing events, it
     201                 : // will not attempt any more SSL I/O operations, so it is clearly safe to shut
     202                 : // down the SSL cert verification infrastructure. Also, the STS will not
     203                 : // dispatch many SSL verification result events at this point, so any pending
     204                 : // cert verifications will (correctly) fail at the point they are dispatched.
     205                 : //
     206                 : // The other shutdown race condition that is possible is a race condition with
     207                 : // shutdown of the nsNSSComponent service. We use the
     208                 : // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
     209            1426 : void StopSSLServerCertVerificationThreads()
     210                 : {
     211            1426 :   if (gCertVerificationThreadPool) {
     212            1426 :     gCertVerificationThreadPool->Shutdown();
     213            1426 :     NS_RELEASE(gCertVerificationThreadPool);
     214                 :   }
     215            1426 : }
     216                 : 
     217                 : namespace {
     218                 : 
     219                 : // Dispatched to the STS thread to notify the socketInfo of the verification
     220                 : // result.
     221                 : //
     222                 : // This will cause the PR_Poll in the STS thread to return, so things work
     223                 : // correctly even if the STS thread is blocked polling (only) on the file
     224                 : // descriptor that is waiting for this result.
     225                 : class SSLServerCertVerificationResult : public nsRunnable
     226              16 : {
     227                 : public:
     228                 :   NS_DECL_NSIRUNNABLE
     229                 : 
     230                 :   SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
     231                 :                                   PRErrorCode errorCode,
     232                 :                                   SSLErrorMessageType errorMessageType = 
     233                 :                                       PlainErrorMessage);
     234                 : 
     235                 :   void Dispatch();
     236                 : private:
     237                 :   const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
     238                 : public:
     239                 :   const PRErrorCode mErrorCode;
     240                 :   const SSLErrorMessageType mErrorMessageType;
     241                 : };
     242                 : 
     243                 : class CertErrorRunnable : public SyncRunnableBase
     244               0 : {
     245                 :  public:
     246               0 :   CertErrorRunnable(const void * fdForLogging,
     247                 :                     nsIX509Cert * cert,
     248                 :                     nsNSSSocketInfo * infoObject,
     249                 :                     PRErrorCode defaultErrorCodeToReport,
     250                 :                     PRUint32 collectedErrors,
     251                 :                     PRErrorCode errorCodeTrust,
     252                 :                     PRErrorCode errorCodeMismatch,
     253                 :                     PRErrorCode errorCodeExpired)
     254                 :     : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
     255                 :       mDefaultErrorCodeToReport(defaultErrorCodeToReport),
     256                 :       mCollectedErrors(collectedErrors),
     257                 :       mErrorCodeTrust(errorCodeTrust),
     258                 :       mErrorCodeMismatch(errorCodeMismatch),
     259               0 :       mErrorCodeExpired(errorCodeExpired)
     260                 :   {
     261               0 :   }
     262                 : 
     263                 :   virtual void RunOnTargetThread();
     264                 :   nsRefPtr<SSLServerCertVerificationResult> mResult; // out
     265                 : private:
     266                 :   SSLServerCertVerificationResult* CheckCertOverrides();
     267                 :   
     268                 :   const void * const mFdForLogging; // may become an invalid pointer; do not dereference
     269                 :   const nsCOMPtr<nsIX509Cert> mCert;
     270                 :   const nsRefPtr<nsNSSSocketInfo> mInfoObject;
     271                 :   const PRErrorCode mDefaultErrorCodeToReport;
     272                 :   const PRUint32 mCollectedErrors;
     273                 :   const PRErrorCode mErrorCodeTrust;
     274                 :   const PRErrorCode mErrorCodeMismatch;
     275                 :   const PRErrorCode mErrorCodeExpired;
     276                 : };
     277                 : 
     278                 : SSLServerCertVerificationResult *
     279               0 : CertErrorRunnable::CheckCertOverrides()
     280                 : {
     281               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
     282                 :                                     mFdForLogging, this));
     283                 : 
     284               0 :   if (!NS_IsMainThread()) {
     285               0 :     NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
     286               0 :     return new SSLServerCertVerificationResult(*mInfoObject,
     287               0 :                                                mDefaultErrorCodeToReport);
     288                 :   }
     289                 : 
     290                 :   PRInt32 port;
     291               0 :   mInfoObject->GetPort(&port);
     292                 : 
     293               0 :   nsCString hostWithPortString;
     294               0 :   hostWithPortString.AppendASCII(mInfoObject->GetHostName());
     295               0 :   hostWithPortString.AppendLiteral(":");
     296               0 :   hostWithPortString.AppendInt(port);
     297                 : 
     298               0 :   PRUint32 remaining_display_errors = mCollectedErrors;
     299                 : 
     300                 :   nsresult nsrv;
     301                 : 
     302                 :   // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
     303                 :   // connections must be dropped when there are any certificate errors
     304                 :   // (STS Spec section 7.3).
     305               0 :   bool strictTransportSecurityEnabled = false;
     306                 :   nsCOMPtr<nsIStrictTransportSecurityService> stss
     307               0 :     = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
     308               0 :   if (NS_SUCCEEDED(nsrv)) {
     309               0 :     nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
     310               0 :                            &strictTransportSecurityEnabled);
     311                 :   }
     312               0 :   if (NS_FAILED(nsrv)) {
     313               0 :     return new SSLServerCertVerificationResult(*mInfoObject,
     314               0 :                                                mDefaultErrorCodeToReport);
     315                 :   }
     316                 : 
     317               0 :   if (!strictTransportSecurityEnabled) {
     318                 :     nsCOMPtr<nsICertOverrideService> overrideService =
     319               0 :       do_GetService(NS_CERTOVERRIDE_CONTRACTID);
     320                 :     // it is fine to continue without the nsICertOverrideService
     321                 : 
     322               0 :     PRUint32 overrideBits = 0;
     323                 : 
     324               0 :     if (overrideService)
     325                 :     {
     326                 :       bool haveOverride;
     327                 :       bool isTemporaryOverride; // we don't care
     328               0 :       nsCString hostString(mInfoObject->GetHostName());
     329               0 :       nsrv = overrideService->HasMatchingOverride(hostString, port,
     330                 :                                                   mCert,
     331                 :                                                   &overrideBits,
     332                 :                                                   &isTemporaryOverride, 
     333               0 :                                                   &haveOverride);
     334               0 :       if (NS_SUCCEEDED(nsrv) && haveOverride) 
     335                 :       {
     336                 :        // remove the errors that are already overriden
     337               0 :         remaining_display_errors -= overrideBits;
     338                 :       }
     339                 :     }
     340                 : 
     341               0 :     if (!remaining_display_errors) {
     342                 :       // all errors are covered by override rules, so let's accept the cert
     343               0 :       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     344                 :              ("[%p][%p] All errors covered by override rules\n",
     345                 :              mFdForLogging, this));
     346               0 :       return new SSLServerCertVerificationResult(*mInfoObject, 0);
     347                 :     }
     348                 :   } else {
     349               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     350                 :            ("[%p][%p] Strict-Transport-Security is violated: untrusted "
     351                 :             "transport layer\n", mFdForLogging, this));
     352                 :   }
     353                 : 
     354               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     355                 :          ("[%p][%p] Certificate error was not overridden\n",
     356                 :          mFdForLogging, this));
     357                 : 
     358                 :   // Ok, this is a full stop.
     359                 :   // First, deliver the technical details of the broken SSL status.
     360                 : 
     361                 :   // Try to get a nsIBadCertListener2 implementation from the socket consumer.
     362               0 :   nsCOMPtr<nsIInterfaceRequestor> cb;
     363               0 :   mInfoObject->GetNotificationCallbacks(getter_AddRefs(cb));
     364               0 :   if (cb) {
     365               0 :     nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
     366               0 :     if (bcl) {
     367               0 :       nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(mInfoObject);
     368               0 :       bool suppressMessage = false; // obsolete, ignored
     369               0 :       nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
     370               0 :                                     hostWithPortString, &suppressMessage);
     371                 :     }
     372                 :   }
     373                 : 
     374                 :   nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService = 
     375               0 :     do_GetService(NS_RECENTBADCERTS_CONTRACTID);
     376                 :  
     377               0 :   if (recentBadCertsService) {
     378               0 :     NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
     379               0 :     recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
     380               0 :                                       mInfoObject->SSLStatus());
     381                 :   }
     382                 : 
     383                 :   // pick the error code to report by priority
     384                 :   PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
     385                 :                                 : mErrorCodeMismatch ? mErrorCodeMismatch
     386                 :                                 : mErrorCodeExpired  ? mErrorCodeExpired
     387               0 :                                 : mDefaultErrorCodeToReport;
     388                 : 
     389               0 :   return new SSLServerCertVerificationResult(*mInfoObject, errorCodeToReport,
     390               0 :                                              OverridableCertErrorMessage);
     391                 : }
     392                 : 
     393                 : void 
     394               0 : CertErrorRunnable::RunOnTargetThread()
     395                 : {
     396               0 :   MOZ_ASSERT(NS_IsMainThread());
     397                 : 
     398               0 :   mResult = CheckCertOverrides();
     399                 :   
     400               0 :   MOZ_ASSERT(mResult);
     401               0 : }
     402                 : 
     403                 : // Returns null with the error code (PR_GetError()) set if it does not create
     404                 : // the CertErrorRunnable.
     405                 : CertErrorRunnable *
     406               0 : CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
     407                 :                         nsNSSSocketInfo * socketInfo,
     408                 :                         CERTCertificate * cert,
     409                 :                         const void * fdForLogging)
     410                 : {
     411               0 :   MOZ_ASSERT(socketInfo);
     412               0 :   MOZ_ASSERT(cert);
     413                 :   
     414                 :   // cert was revoked, don't do anything else
     415               0 :   if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
     416               0 :     PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
     417               0 :     return nsnull;
     418                 :   }
     419                 : 
     420               0 :   if (defaultErrorCodeToReport == 0) {
     421               0 :     NS_ERROR("No error code set during certificate validation failure.");
     422               0 :     PR_SetError(PR_INVALID_STATE_ERROR, 0);
     423               0 :     return nsnull;
     424                 :   }
     425                 : 
     426               0 :   nsRefPtr<nsNSSCertificate> nssCert;
     427               0 :   nssCert = nsNSSCertificate::Create(cert);
     428               0 :   if (!nssCert) {
     429               0 :     NS_ERROR("nsNSSCertificate::Create failed");
     430               0 :     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
     431               0 :     return nsnull;
     432                 :   }
     433                 : 
     434                 :   SECStatus srv;
     435                 :   nsresult nsrv;
     436                 : 
     437               0 :   nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
     438               0 :   if (!inss) {
     439               0 :     NS_ERROR("do_GetService(kNSSComponentCID) failed");
     440               0 :     PR_SetError(defaultErrorCodeToReport, 0);
     441               0 :     return nsnull;
     442                 :   }
     443                 : 
     444               0 :   nsRefPtr<nsCERTValInParamWrapper> survivingParams;
     445               0 :   nsrv = inss->GetDefaultCERTValInParam(survivingParams);
     446               0 :   if (NS_FAILED(nsrv)) {
     447               0 :     NS_ERROR("GetDefaultCERTValInParam failed");
     448               0 :     PR_SetError(defaultErrorCodeToReport, 0);
     449               0 :     return nsnull;
     450                 :   }
     451                 :   
     452               0 :   PRArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     453               0 :   PRArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
     454               0 :   if (!log_arena) {
     455               0 :     NS_ERROR("PORT_NewArena failed");
     456               0 :     return nsnull; // PORT_NewArena set error code
     457                 :   }
     458                 : 
     459               0 :   CERTVerifyLog *verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
     460               0 :   if (!verify_log) {
     461               0 :     NS_ERROR("PORT_ArenaZNew failed");
     462               0 :     return nsnull; // PORT_ArenaZNew set error code
     463                 :   }
     464               0 :   CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
     465               0 :   verify_log->arena = log_arena;
     466                 : 
     467               0 :   if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
     468                 :     srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert,
     469                 :                                 true, certificateUsageSSLServer,
     470                 :                                 PR_Now(), static_cast<void*>(socketInfo),
     471               0 :                                 verify_log, NULL);
     472                 :   }
     473                 :   else {
     474                 :     CERTValOutParam cvout[2];
     475               0 :     cvout[0].type = cert_po_errorLog;
     476               0 :     cvout[0].value.pointer.log = verify_log;
     477               0 :     cvout[1].type = cert_po_end;
     478                 : 
     479                 :     srv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
     480                 :                               survivingParams->GetRawPointerForNSS(),
     481               0 :                               cvout, static_cast<void*>(socketInfo));
     482                 :   }
     483                 : 
     484                 :   // We ignore the result code of the cert verification.
     485                 :   // Either it is a failure, which is expected, and we'll process the
     486                 :   //                         verify log below.
     487                 :   // Or it is a success, then a domain mismatch is the only 
     488                 :   //                     possible failure. 
     489                 : 
     490               0 :   PRErrorCode errorCodeMismatch = 0;
     491               0 :   PRErrorCode errorCodeTrust = 0;
     492               0 :   PRErrorCode errorCodeExpired = 0;
     493                 : 
     494               0 :   PRUint32 collected_errors = 0;
     495                 : 
     496               0 :   if (socketInfo->IsCertIssuerBlacklisted()) {
     497               0 :     collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
     498               0 :     errorCodeTrust = defaultErrorCodeToReport;
     499                 :   }
     500                 : 
     501                 :   // Check the name field against the desired hostname.
     502               0 :   if (CERT_VerifyCertName(cert, socketInfo->GetHostName()) != SECSuccess) {
     503               0 :     collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
     504               0 :     errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
     505                 :   }
     506                 : 
     507                 :   CERTVerifyLogNode *i_node;
     508               0 :   for (i_node = verify_log->head; i_node; i_node = i_node->next)
     509                 :   {
     510               0 :     switch (i_node->error)
     511                 :     {
     512                 :       case SEC_ERROR_UNKNOWN_ISSUER:
     513                 :       case SEC_ERROR_CA_CERT_INVALID:
     514                 :       case SEC_ERROR_UNTRUSTED_ISSUER:
     515                 :       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     516                 :       case SEC_ERROR_UNTRUSTED_CERT:
     517                 :       case SEC_ERROR_INADEQUATE_KEY_USAGE:
     518                 :         // We group all these errors as "cert not trusted"
     519               0 :         collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
     520               0 :         if (errorCodeTrust == SECSuccess) {
     521               0 :           errorCodeTrust = i_node->error;
     522                 :         }
     523               0 :         break;
     524                 :       case SSL_ERROR_BAD_CERT_DOMAIN:
     525               0 :         collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
     526               0 :         if (errorCodeMismatch == SECSuccess) {
     527               0 :           errorCodeMismatch = i_node->error;
     528                 :         }
     529               0 :         break;
     530                 :       case SEC_ERROR_EXPIRED_CERTIFICATE:
     531               0 :         collected_errors |= nsICertOverrideService::ERROR_TIME;
     532               0 :         if (errorCodeExpired == SECSuccess) {
     533               0 :           errorCodeExpired = i_node->error;
     534                 :         }
     535               0 :         break;
     536                 :       default:
     537               0 :         PR_SetError(i_node->error, 0);
     538               0 :         return nsnull;
     539                 :     }
     540                 :   }
     541                 : 
     542               0 :   if (!collected_errors)
     543                 :   {
     544                 :     // This will happen when CERT_*Verify* only returned error(s) that are
     545                 :     // not on our whitelist of overridable certificate errors.
     546               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
     547                 :            fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
     548               0 :     PR_SetError(defaultErrorCodeToReport, 0);
     549               0 :     return nsnull;
     550                 :   }
     551                 : 
     552               0 :   socketInfo->SetStatusErrorBits(*nssCert, collected_errors);
     553                 : 
     554                 :   return new CertErrorRunnable(fdForLogging, 
     555               0 :                                static_cast<nsIX509Cert*>(nssCert.get()),
     556                 :                                socketInfo, defaultErrorCodeToReport, 
     557                 :                                collected_errors, errorCodeTrust, 
     558               0 :                                errorCodeMismatch, errorCodeExpired);
     559                 : }
     560                 : 
     561                 : // When doing async cert processing, we dispatch one of these runnables to the
     562                 : // socket transport service thread, which blocks the socket transport
     563                 : // service thread while it waits for the inner CertErrorRunnable to execute
     564                 : // CheckCertOverrides on the main thread. CheckCertOverrides must block events
     565                 : // on both of these threads because it calls nsNSSSocketInfo::GetInterface(), 
     566                 : // which may call nsHttpConnection::GetInterface() through
     567                 : // nsNSSSocketInfo::mCallbacks. nsHttpConnection::GetInterface must always
     568                 : // execute on the main thread, with the socket transport service thread
     569                 : // blocked.
     570                 : class CertErrorRunnableRunnable : public nsRunnable
     571               0 : {
     572                 : public:
     573               0 :   CertErrorRunnableRunnable(CertErrorRunnable * certErrorRunnable)
     574               0 :     : mCertErrorRunnable(certErrorRunnable)
     575                 :   {
     576               0 :   }
     577                 : private:
     578               0 :   NS_IMETHOD Run()
     579                 :   {
     580               0 :     nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
     581                 :     // The result must run on the socket transport thread, which we are already
     582                 :     // on, so we can just run it directly, instead of dispatching it.
     583               0 :     if (NS_SUCCEEDED(rv)) {
     584               0 :       rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
     585               0 :                                        : NS_ERROR_UNEXPECTED;
     586                 :     }
     587               0 :     return rv;
     588                 :   }
     589                 :   nsRefPtr<CertErrorRunnable> mCertErrorRunnable;
     590                 : };
     591                 : 
     592                 : class SSLServerCertVerificationJob : public nsRunnable
     593                 : {
     594                 : public:
     595                 :   // Must be called only on the socket transport thread
     596                 :   static SECStatus Dispatch(const void * fdForLogging,
     597                 :                             nsNSSSocketInfo * infoObject,
     598                 :                             CERTCertificate * serverCert);
     599                 : private:
     600                 :   NS_DECL_NSIRUNNABLE
     601                 : 
     602                 :   // Must be called only on the socket transport thread
     603                 :   SSLServerCertVerificationJob(const void * fdForLogging,
     604                 :                                nsNSSSocketInfo & socketInfo, 
     605                 :                                CERTCertificate & cert);
     606                 :   ~SSLServerCertVerificationJob();
     607                 : 
     608                 :   const void * const mFdForLogging;
     609                 :   const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
     610                 :   CERTCertificate * const mCert;
     611                 : };
     612                 : 
     613               4 : SSLServerCertVerificationJob::SSLServerCertVerificationJob(
     614                 :     const void * fdForLogging, nsNSSSocketInfo & socketInfo,
     615                 :     CERTCertificate & cert)
     616                 :   : mFdForLogging(fdForLogging)
     617                 :   , mSocketInfo(&socketInfo)
     618               4 :   , mCert(CERT_DupCertificate(&cert))
     619                 : {
     620               4 : }
     621                 : 
     622              12 : SSLServerCertVerificationJob::~SSLServerCertVerificationJob()
     623                 : {
     624               4 :   CERT_DestroyCertificate(mCert);
     625              16 : }
     626                 : 
     627                 : SECStatus
     628               4 : PSM_SSL_PKIX_AuthCertificate(CERTCertificate *peerCert, void * pinarg,
     629                 :                              const char * hostname)
     630                 : {
     631                 :     SECStatus          rv;
     632                 :     
     633               4 :     if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
     634                 :         rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, true,
     635               4 :                                 certUsageSSLServer, pinarg);
     636                 :     }
     637                 :     else {
     638                 :         nsresult nsrv;
     639               0 :         nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
     640               0 :         if (!inss)
     641               0 :           return SECFailure;
     642               0 :         nsRefPtr<nsCERTValInParamWrapper> survivingParams;
     643               0 :         if (NS_FAILED(inss->GetDefaultCERTValInParam(survivingParams)))
     644               0 :           return SECFailure;
     645                 : 
     646                 :         CERTValOutParam cvout[1];
     647               0 :         cvout[0].type = cert_po_end;
     648                 : 
     649                 :         rv = CERT_PKIXVerifyCert(peerCert, certificateUsageSSLServer,
     650                 :                                 survivingParams->GetRawPointerForNSS(),
     651               0 :                                 cvout, pinarg);
     652                 :     }
     653                 : 
     654               4 :     if (rv == SECSuccess) {
     655                 :         /* cert is OK.  This is the client side of an SSL connection.
     656                 :         * Now check the name field in the cert against the desired hostname.
     657                 :         * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
     658                 :         */
     659               4 :         if (hostname && hostname[0])
     660               4 :             rv = CERT_VerifyCertName(peerCert, hostname);
     661                 :         else
     662               0 :             rv = SECFailure;
     663               4 :         if (rv != SECSuccess)
     664               0 :             PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
     665                 :     }
     666                 :         
     667               4 :     return rv;
     668                 : }
     669                 : 
     670                 : struct nsSerialBinaryBlacklistEntry
     671                 : {
     672                 :   unsigned int len;
     673                 :   const char *binary_serial;
     674                 : };
     675                 : 
     676                 : // bug 642395
     677                 : static struct nsSerialBinaryBlacklistEntry myUTNBlacklistEntries[] = {
     678                 :   { 17, "\x00\x92\x39\xd5\x34\x8f\x40\xd1\x69\x5a\x74\x54\x70\xe1\xf2\x3f\x43" },
     679                 :   { 17, "\x00\xd8\xf3\x5f\x4e\xb7\x87\x2b\x2d\xab\x06\x92\xe3\x15\x38\x2f\xb0" },
     680                 :   { 16, "\x72\x03\x21\x05\xc5\x0c\x08\x57\x3d\x8e\xa5\x30\x4e\xfe\xe8\xb0" },
     681                 :   { 17, "\x00\xb0\xb7\x13\x3e\xd0\x96\xf9\xb5\x6f\xae\x91\xc8\x74\xbd\x3a\xc0" },
     682                 :   { 16, "\x39\x2a\x43\x4f\x0e\x07\xdf\x1f\x8a\xa3\x05\xde\x34\xe0\xc2\x29" },
     683                 :   { 16, "\x3e\x75\xce\xd4\x6b\x69\x30\x21\x21\x88\x30\xae\x86\xa8\x2a\x71" },
     684                 :   { 17, "\x00\xe9\x02\x8b\x95\x78\xe4\x15\xdc\x1a\x71\x0a\x2b\x88\x15\x44\x47" },
     685                 :   { 17, "\x00\xd7\x55\x8f\xda\xf5\xf1\x10\x5b\xb2\x13\x28\x2b\x70\x77\x29\xa3" },
     686                 :   { 16, "\x04\x7e\xcb\xe9\xfc\xa5\x5f\x7b\xd0\x9e\xae\x36\xe1\x0c\xae\x1e" },
     687                 :   { 17, "\x00\xf5\xc8\x6a\xf3\x61\x62\xf1\x3a\x64\xf5\x4f\x6d\xc9\x58\x7c\x06" },
     688                 :   { 0, 0 } // end marker
     689                 : };
     690                 : 
     691                 : // Call this if we have already decided that a cert should be treated as INVALID,
     692                 : // in order to check if we to worsen the error to REVOKED.
     693                 : PRErrorCode
     694               0 : PSM_SSL_DigiNotarTreatAsRevoked(CERTCertificate * serverCert,
     695                 :                                 CERTCertList * serverCertChain)
     696                 : {
     697                 :   // If any involved cert was issued by DigiNotar, 
     698                 :   // and serverCert was issued after 01-JUL-2011,
     699                 :   // then worsen the error to revoked.
     700                 :   
     701               0 :   PRTime cutoff = 0;
     702               0 :   PRStatus status = PR_ParseTimeString("01-JUL-2011 00:00", true, &cutoff);
     703               0 :   if (status != PR_SUCCESS) {
     704               0 :     NS_ASSERTION(status == PR_SUCCESS, "PR_ParseTimeString failed");
     705                 :     // be safe, assume it's afterwards, keep going
     706                 :   } else {
     707               0 :     PRTime notBefore = 0, notAfter = 0;
     708               0 :     if (CERT_GetCertTimes(serverCert, &notBefore, &notAfter) == SECSuccess &&
     709                 :            notBefore < cutoff) {
     710                 :       // no worsening for certs issued before the cutoff date
     711               0 :       return 0;
     712                 :     }
     713                 :   }
     714                 :   
     715               0 :   for (CERTCertListNode *node = CERT_LIST_HEAD(serverCertChain);
     716               0 :        !CERT_LIST_END(node, serverCertChain);
     717                 :        node = CERT_LIST_NEXT(node)) {
     718               0 :     if (node->cert->issuerName &&
     719               0 :         strstr(node->cert->issuerName, "CN=DigiNotar")) {
     720               0 :       return SEC_ERROR_REVOKED_CERTIFICATE;
     721                 :     }
     722                 :   }
     723                 :   
     724               0 :   return 0;
     725                 : }
     726                 : 
     727                 : // Call this only if a cert has been reported by NSS as VALID
     728                 : PRErrorCode
     729               4 : PSM_SSL_BlacklistDigiNotar(CERTCertificate * serverCert,
     730                 :                            CERTCertList * serverCertChain)
     731                 : {
     732               4 :   bool isDigiNotarIssuedCert = false;
     733                 : 
     734              32 :   for (CERTCertListNode *node = CERT_LIST_HEAD(serverCertChain);
     735              16 :        !CERT_LIST_END(node, serverCertChain);
     736                 :        node = CERT_LIST_NEXT(node)) {
     737              12 :     if (!node->cert->issuerName)
     738               0 :       continue;
     739                 : 
     740              12 :     if (strstr(node->cert->issuerName, "CN=DigiNotar")) {
     741               0 :       isDigiNotarIssuedCert = true;
     742                 :     }
     743                 :   }
     744                 : 
     745               4 :   if (isDigiNotarIssuedCert) {
     746                 :     // let's see if we want to worsen the error code to revoked.
     747               0 :     PRErrorCode revoked_code = PSM_SSL_DigiNotarTreatAsRevoked(serverCert, serverCertChain);
     748               0 :     return (revoked_code != 0) ? revoked_code : SEC_ERROR_UNTRUSTED_ISSUER;
     749                 :   }
     750                 : 
     751               4 :   return 0;
     752                 : }
     753                 : 
     754                 : // This function assumes that we will only use the SPDY connection coalescing
     755                 : // feature on connections where we have negotiated SPDY using NPN. If we ever
     756                 : // talk SPDY without having negotiated it with SPDY, this code will give wrong
     757                 : // and perhaps unsafe results.
     758                 : //
     759                 : // Returns SECSuccess on the initial handshake of all connections, on
     760                 : // renegotiations for any connections where we did not negotiate SPDY, or on any
     761                 : // SPDY connection where the server's certificate did not change.
     762                 : //
     763                 : // Prohibit changing the server cert only if we negotiated SPDY,
     764                 : // in order to support SPDY's cross-origin connection pooling.
     765                 : 
     766                 : static SECStatus
     767               4 : BlockServerCertChangeForSpdy(nsNSSSocketInfo *infoObject,
     768                 :                              CERTCertificate *serverCert)
     769                 : {
     770                 :   // Get the existing cert. If there isn't one, then there is
     771                 :   // no cert change to worry about.
     772               8 :   nsCOMPtr<nsIX509Cert> cert;
     773               8 :   nsCOMPtr<nsIX509Cert2> cert2;
     774                 : 
     775               8 :   nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus();
     776               4 :   if (!status) {
     777                 :     // If we didn't have a status, then this is the
     778                 :     // first handshake on this connection, not a
     779                 :     // renegotiation.
     780               4 :     return SECSuccess;
     781                 :   }
     782                 :   
     783               0 :   status->GetServerCert(getter_AddRefs(cert));
     784               0 :   cert2 = do_QueryInterface(cert);
     785               0 :   if (!cert2) {
     786                 :     NS_NOTREACHED("every nsSSLStatus must have a cert"
     787               0 :                   "that implements nsIX509Cert2");
     788               0 :     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
     789               0 :     return SECFailure;
     790                 :   }
     791                 : 
     792                 :   // Filter out sockets that did not neogtiate SPDY via NPN
     793               0 :   nsCAutoString negotiatedNPN;
     794               0 :   nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
     795               0 :   NS_ASSERTION(NS_SUCCEEDED(rv),
     796                 :                "GetNegotiatedNPN() failed during renegotiation");
     797                 : 
     798               0 :   if (NS_SUCCEEDED(rv) && !negotiatedNPN.Equals(NS_LITERAL_CSTRING("spdy/2")))
     799               0 :     return SECSuccess;
     800                 : 
     801                 :   // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
     802               0 :   if (NS_FAILED(rv))
     803               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     804                 :            ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
     805                 :             " Assuming spdy.\n"));
     806                 : 
     807                 :   // Check to see if the cert has actually changed
     808               0 :   CERTCertificate * c = cert2->GetCert();
     809               0 :   NS_ASSERTION(c, "very bad and hopefully impossible state");
     810               0 :   bool sameCert = CERT_CompareCerts(c, serverCert);
     811               0 :   CERT_DestroyCertificate(c);
     812               0 :   if (sameCert)
     813               0 :     return SECSuccess;
     814                 : 
     815                 :   // Report an error - changed cert is confirmed
     816               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     817                 :          ("SPDY Refused to allow new cert during renegotiation\n"));
     818               0 :   PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
     819               0 :   return SECFailure;
     820                 : }
     821                 : 
     822                 : SECStatus
     823               4 : AuthCertificate(nsNSSSocketInfo * socketInfo, CERTCertificate * cert)
     824                 : {
     825               4 :   if (BlockServerCertChangeForSpdy(socketInfo, cert) != SECSuccess)
     826               0 :     return SECFailure;
     827                 : 
     828               8 :   if (cert->serialNumber.data &&
     829                 :       cert->issuerName &&
     830                 :       !strcmp(cert->issuerName, 
     831               4 :         "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) {
     832                 : 
     833               0 :     unsigned char *server_cert_comparison_start = cert->serialNumber.data;
     834               0 :     unsigned int server_cert_comparison_len = cert->serialNumber.len;
     835                 : 
     836               0 :     while (server_cert_comparison_len) {
     837               0 :       if (*server_cert_comparison_start != 0)
     838               0 :         break;
     839                 : 
     840               0 :       ++server_cert_comparison_start;
     841               0 :       --server_cert_comparison_len;
     842                 :     }
     843                 : 
     844               0 :     nsSerialBinaryBlacklistEntry *walk = myUTNBlacklistEntries;
     845               0 :     for ( ; walk && walk->len; ++walk) {
     846                 : 
     847               0 :       unsigned char *locked_cert_comparison_start = (unsigned char*)walk->binary_serial;
     848               0 :       unsigned int locked_cert_comparison_len = walk->len;
     849                 :       
     850               0 :       while (locked_cert_comparison_len) {
     851               0 :         if (*locked_cert_comparison_start != 0)
     852               0 :           break;
     853                 :         
     854               0 :         ++locked_cert_comparison_start;
     855               0 :         --locked_cert_comparison_len;
     856                 :       }
     857                 : 
     858               0 :       if (server_cert_comparison_len == locked_cert_comparison_len &&
     859               0 :           !memcmp(server_cert_comparison_start, locked_cert_comparison_start, locked_cert_comparison_len)) {
     860               0 :         PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
     861               0 :         return SECFailure;
     862                 :       }
     863                 :     }
     864                 :   }
     865                 : 
     866                 :   SECStatus rv = PSM_SSL_PKIX_AuthCertificate(cert, socketInfo,
     867               4 :                                               socketInfo->GetHostName());
     868                 : 
     869                 :   // We want to remember the CA certs in the temp db, so that the application can find the
     870                 :   // complete chain at any time it might need it.
     871                 :   // But we keep only those CA certs in the temp db, that we didn't already know.
     872                 : 
     873               8 :   nsRefPtr<nsSSLStatus> status = socketInfo->SSLStatus();
     874               8 :   nsRefPtr<nsNSSCertificate> nsc;
     875                 : 
     876               4 :   if (!status || !status->mServerCert) {
     877               4 :     nsc = nsNSSCertificate::Create(cert);
     878                 :   }
     879                 : 
     880               4 :   CERTCertList *certList = nsnull;
     881               4 :   certList = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageSSLCA);
     882               4 :   if (!certList) {
     883               0 :     rv = SECFailure;
     884                 :   } else {
     885                 :     PRErrorCode blacklistErrorCode;
     886               4 :     if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
     887               4 :       blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(cert, certList);
     888                 :     } else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
     889               0 :       PRErrorCode savedErrorCode = PORT_GetError();
     890                 :       // Check if we want to worsen the error code to "revoked".
     891               0 :       blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(cert, certList);
     892               0 :       if (blacklistErrorCode == 0) {
     893                 :         // we don't worsen the code, let's keep the original error code from NSS
     894               0 :         PORT_SetError(savedErrorCode);
     895                 :       }
     896                 :     }
     897                 :       
     898               4 :     if (blacklistErrorCode != 0) {
     899               0 :       socketInfo->SetCertIssuerBlacklisted();
     900               0 :       PORT_SetError(blacklistErrorCode);
     901               0 :       rv = SECFailure;
     902                 :     }
     903                 :   }
     904                 : 
     905               4 :   if (rv == SECSuccess) {
     906               4 :     if (nsc) {
     907                 :       bool dummyIsEV;
     908               4 :       nsc->GetIsExtendedValidation(&dummyIsEV); // the nsc object will cache the status
     909                 :     }
     910                 :     
     911               8 :     nsCOMPtr<nsINSSComponent> nssComponent;
     912                 :       
     913              32 :     for (CERTCertListNode *node = CERT_LIST_HEAD(certList);
     914              16 :          !CERT_LIST_END(node, certList);
     915                 :          node = CERT_LIST_NEXT(node)) {
     916                 : 
     917              12 :       if (node->cert->slot) {
     918                 :         // This cert was found on a token, no need to remember it in the temp db.
     919               4 :         continue;
     920                 :       }
     921                 : 
     922               8 :       if (node->cert->isperm) {
     923                 :         // We don't need to remember certs already stored in perm db.
     924               0 :         continue;
     925                 :       }
     926                 :         
     927               8 :       if (node->cert == cert) {
     928                 :         // We don't want to remember the server cert, 
     929                 :         // the code that cares for displaying page info does this already.
     930               4 :         continue;
     931                 :       }
     932                 : 
     933                 :       // We have found a signer cert that we want to remember.
     934               4 :       char* nickname = nsNSSCertificate::defaultServerNickname(node->cert);
     935               4 :       if (nickname && *nickname) {
     936               4 :         PK11SlotInfo *slot = PK11_GetInternalKeySlot();
     937               4 :         if (slot) {
     938                 :           PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE, 
     939               4 :                           nickname, false);
     940               4 :           PK11_FreeSlot(slot);
     941                 :         }
     942                 :       }
     943               4 :       PR_FREEIF(nickname);
     944                 :     }
     945                 : 
     946               4 :     if (certList) {
     947               4 :       CERT_DestroyCertList(certList);
     948                 :     }
     949                 : 
     950                 :     // The connection may get terminated, for example, if the server requires
     951                 :     // a client cert. Let's provide a minimal SSLStatus
     952                 :     // to the caller that contains at least the cert and its status.
     953               4 :     if (!status) {
     954               4 :       status = new nsSSLStatus();
     955               4 :       socketInfo->SetSSLStatus(status);
     956                 :     }
     957                 : 
     958               4 :     if (rv == SECSuccess) {
     959                 :       // Certificate verification succeeded delete any potential record
     960                 :       // of certificate error bits.
     961                 :       nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
     962               4 :         socketInfo, nsnull, rv);
     963                 :     }
     964                 :     else {
     965                 :       // Certificate verification failed, update the status' bits.
     966                 :       nsSSLIOLayerHelpers::mHostsWithCertErrors->LookupCertErrorBits(
     967               0 :         socketInfo, status);
     968                 :     }
     969                 : 
     970               4 :     if (status && !status->mServerCert) {
     971               4 :       status->mServerCert = nsc;
     972               4 :       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
     973                 :              ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
     974                 :     }
     975                 :   }
     976                 : 
     977               4 :   return rv;
     978                 : }
     979                 : 
     980                 : /*static*/ SECStatus
     981               4 : SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
     982                 :                                        nsNSSSocketInfo * socketInfo,
     983                 :                                        CERTCertificate * serverCert)
     984                 : {
     985                 :   // Runs on the socket transport thread
     986               4 :   if (!socketInfo || !serverCert) {
     987               0 :     NS_ERROR("Invalid parameters for SSL server cert validation");
     988               0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     989               0 :     return SECFailure;
     990                 :   }
     991                 :   
     992                 :   nsRefPtr<SSLServerCertVerificationJob> job
     993               8 :     = new SSLServerCertVerificationJob(fdForLogging, *socketInfo, *serverCert);
     994                 : 
     995               4 :   socketInfo->SetCertVerificationWaiting();
     996                 :   nsresult nrv;
     997               4 :   if (!gCertVerificationThreadPool) {
     998               0 :     nrv = NS_ERROR_NOT_INITIALIZED;
     999                 :   } else {
    1000               4 :     nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
    1001                 :   }
    1002               4 :   if (NS_FAILED(nrv)) {
    1003                 :     // We can't call SetCertVerificationResult here to change
    1004                 :     // mCertVerificationState because SetCertVerificationResult will call
    1005                 :     // libssl functions that acquire SSL locks that are already being held at
    1006                 :     // this point. socketInfo->mCertVerificationState will be stuck at
    1007                 :     // waiting_for_cert_verification here, but that is OK because we already
    1008                 :     // have to be able to handle cases where we encounter non-cert errors while
    1009                 :     // in that state.
    1010                 :     PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
    1011                 :                       ? SEC_ERROR_NO_MEMORY
    1012               0 :                       : PR_INVALID_STATE_ERROR;
    1013               0 :     PORT_SetError(error);
    1014               0 :     return SECFailure;
    1015                 :   }
    1016                 : 
    1017               4 :   PORT_SetError(PR_WOULD_BLOCK_ERROR);
    1018               4 :   return SECWouldBlock;    
    1019                 : }
    1020                 : 
    1021                 : NS_IMETHODIMP
    1022               4 : SSLServerCertVerificationJob::Run()
    1023                 : {
    1024                 :   // Runs on a cert verification thread
    1025                 : 
    1026               4 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    1027                 :           ("[%p] SSLServerCertVerificationJob::Run\n", mSocketInfo.get()));
    1028                 : 
    1029                 :   PRErrorCode error;
    1030                 : 
    1031               8 :   nsNSSShutDownPreventionLock nssShutdownPrevention;
    1032               4 :   if (mSocketInfo->isAlreadyShutDown()) {
    1033               0 :     error = SEC_ERROR_USER_CANCELLED;
    1034                 :   } else {
    1035                 :     // Reset the error code here so we can detect if AuthCertificate fails to
    1036                 :     // set the error code if/when it fails.
    1037               4 :     PR_SetError(0, 0); 
    1038               4 :     SECStatus rv = AuthCertificate(mSocketInfo, mCert);
    1039               4 :     if (rv == SECSuccess) {
    1040                 :       nsRefPtr<SSLServerCertVerificationResult> restart 
    1041              12 :         = new SSLServerCertVerificationResult(*mSocketInfo, 0);
    1042               4 :       restart->Dispatch();
    1043               4 :       return NS_OK;
    1044                 :     }
    1045                 : 
    1046               0 :     error = PR_GetError();
    1047               0 :     if (error != 0) {
    1048                 :       nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
    1049               0 :               error, mSocketInfo, mCert, mFdForLogging);
    1050               0 :       if (!runnable) {
    1051                 :         // CreateCertErrorRunnable set a new error code
    1052               0 :         error = PR_GetError(); 
    1053                 :       } else {
    1054                 :         // We must block the the socket transport service thread while the
    1055                 :         // main thread executes the CertErrorRunnable. The CertErrorRunnable
    1056                 :         // will dispatch the result asynchronously, so we don't have to block
    1057                 :         // this thread waiting for it.
    1058                 : 
    1059               0 :         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    1060                 :                 ("[%p][%p] Before dispatching CertErrorRunnable\n",
    1061                 :                 mFdForLogging, runnable.get()));
    1062                 : 
    1063                 :         nsresult nrv;
    1064                 :         nsCOMPtr<nsIEventTarget> stsTarget
    1065               0 :           = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    1066               0 :         if (NS_SUCCEEDED(nrv)) {
    1067               0 :           nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
    1068               0 :                                     NS_DISPATCH_NORMAL);
    1069                 :         }
    1070               0 :         if (NS_SUCCEEDED(nrv)) {
    1071               0 :           return NS_OK;
    1072                 :         }
    1073                 : 
    1074               0 :         NS_ERROR("Failed to dispatch CertErrorRunnable");
    1075               0 :         error = PR_INVALID_STATE_ERROR;
    1076                 :       }
    1077                 :     }
    1078                 :   }
    1079                 : 
    1080               0 :   if (error == 0) {
    1081               0 :     NS_NOTREACHED("no error set during certificate validation failure");
    1082               0 :     error = PR_INVALID_STATE_ERROR;
    1083                 :   }
    1084                 : 
    1085                 :   nsRefPtr<SSLServerCertVerificationResult> failure
    1086               0 :     = new SSLServerCertVerificationResult(*mSocketInfo, error);
    1087               0 :   failure->Dispatch();
    1088               0 :   return NS_OK;
    1089                 : }
    1090                 : 
    1091                 : } // unnamed namespace
    1092                 : 
    1093                 : // Extracts whatever information we need out of fd (using SSL_*) and passes it
    1094                 : // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
    1095                 : // never do anything with fd except logging.
    1096                 : SECStatus
    1097               4 : AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
    1098                 : {
    1099                 :   // Runs on the socket transport thread
    1100                 : 
    1101               4 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    1102                 :          ("[%p] starting AuthCertificateHook\n", fd));
    1103                 : 
    1104                 :   // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
    1105                 :   // doing verification without checking signatures.
    1106               4 :   NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
    1107                 : 
    1108                 :   // PSM never causes libssl to call this function with PR_TRUE for isServer,
    1109                 :   // and many things in PSM assume that we are a client.
    1110               4 :   NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
    1111                 : 
    1112               4 :   if (!checkSig || isServer) {
    1113               0 :       PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1114               0 :       return SECFailure;
    1115                 :   }
    1116                 :       
    1117               4 :   CERTCertificate *serverCert = SSL_PeerCertificate(fd);
    1118               8 :   CERTCertificateCleaner serverCertCleaner(serverCert);
    1119                 : 
    1120               4 :   nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);
    1121                 : 
    1122                 :   bool onSTSThread;
    1123                 :   nsresult nrv;
    1124                 :   nsCOMPtr<nsIEventTarget> sts
    1125               8 :     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    1126               4 :   if (NS_SUCCEEDED(nrv)) {
    1127               4 :     nrv = sts->IsOnCurrentThread(&onSTSThread);
    1128                 :   }
    1129                 : 
    1130               4 :   if (NS_FAILED(nrv)) {
    1131               0 :     NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
    1132               0 :     PR_SetError(PR_UNKNOWN_ERROR, 0);
    1133               0 :     return SECFailure;
    1134                 :   }
    1135                 :   
    1136               4 :   if (onSTSThread) {
    1137                 :     // We *must* do certificate verification on a background thread because
    1138                 :     // we need the socket transport thread to be free for our OCSP requests,
    1139                 :     // and we *want* to do certificate verification on a background thread
    1140                 :     // because of the performance benefits of doing so.
    1141                 :     SECStatus rv = SSLServerCertVerificationJob::Dispatch(
    1142               4 :                         static_cast<const void *>(fd), socketInfo, serverCert);
    1143               4 :     return rv;
    1144                 :   }
    1145                 :   
    1146                 :   // We can't do certificate verification on a background thread, because the
    1147                 :   // thread doing the network I/O may not interrupt its network I/O on receipt
    1148                 :   // of our SSLServerCertVerificationResult event, and/or it might not even be
    1149                 :   // a non-blocking socket.
    1150               0 :   SECStatus rv = AuthCertificate(socketInfo, serverCert);
    1151               0 :   if (rv == SECSuccess) {
    1152               0 :     return SECSuccess;
    1153                 :   }
    1154                 : 
    1155               0 :   PRErrorCode error = PR_GetError();
    1156               0 :   if (error != 0) {
    1157                 :     nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
    1158                 :                     error, socketInfo, serverCert,
    1159               0 :                     static_cast<const void *>(fd));
    1160               0 :     if (!runnable) {
    1161                 :       // CreateCertErrorRunnable sets a new error code when it fails
    1162               0 :       error = PR_GetError();
    1163                 :     } else {
    1164                 :       // We have to return SECSuccess or SECFailure based on the result of the
    1165                 :       // override processing, so we must block this thread waiting for it. The
    1166                 :       // CertErrorRunnable will NOT dispatch the result at all, since we passed
    1167                 :       // false for CreateCertErrorRunnable's async parameter
    1168               0 :       nrv = runnable->DispatchToMainThreadAndWait();
    1169               0 :       if (NS_FAILED(nrv)) {
    1170               0 :         NS_ERROR("Failed to dispatch CertErrorRunnable");
    1171               0 :         PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1172               0 :         return SECFailure;
    1173                 :       }
    1174                 : 
    1175               0 :       if (!runnable->mResult) {
    1176               0 :         NS_ERROR("CertErrorRunnable did not set result");
    1177               0 :         PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1178               0 :         return SECFailure;
    1179                 :       }
    1180                 : 
    1181               0 :       if (runnable->mResult->mErrorCode == 0) {
    1182               0 :         return SECSuccess; // cert error override occurred.
    1183                 :       }
    1184                 : 
    1185                 :       // We must call SetCanceled here to set the error message type
    1186                 :       // in case it isn't PlainErrorMessage, which is what we would
    1187                 :       // default to if we just called
    1188                 :       // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
    1189                 :       // SECFailure without doing this.
    1190               0 :       socketInfo->SetCanceled(runnable->mResult->mErrorCode,
    1191               0 :                               runnable->mResult->mErrorMessageType);
    1192               0 :       error = runnable->mResult->mErrorCode;
    1193                 :     }
    1194                 :   }
    1195                 : 
    1196               0 :   if (error == 0) {
    1197               0 :     NS_ERROR("error code not set");
    1198               0 :     error = PR_UNKNOWN_ERROR;
    1199                 :   }
    1200                 : 
    1201               0 :   PR_SetError(error, 0);
    1202               0 :   return SECFailure;
    1203                 : }
    1204                 : 
    1205               4 : SSLServerCertVerificationResult::SSLServerCertVerificationResult(
    1206                 :         nsNSSSocketInfo & socketInfo, PRErrorCode errorCode,
    1207                 :         SSLErrorMessageType errorMessageType)
    1208                 :   : mSocketInfo(&socketInfo)
    1209                 :   , mErrorCode(errorCode)
    1210               4 :   , mErrorMessageType(errorMessageType)
    1211                 : {
    1212               4 : }
    1213                 : 
    1214                 : void
    1215               4 : SSLServerCertVerificationResult::Dispatch()
    1216                 : {
    1217                 :   nsresult rv;
    1218                 :   nsCOMPtr<nsIEventTarget> stsTarget
    1219               8 :     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1220               4 :   NS_ASSERTION(stsTarget,
    1221                 :                "Failed to get socket transport service event target");
    1222               4 :   rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
    1223               4 :   NS_ASSERTION(NS_SUCCEEDED(rv), 
    1224                 :                "Failed to dispatch SSLServerCertVerificationResult");
    1225               4 : }
    1226                 : 
    1227                 : NS_IMETHODIMP
    1228               4 : SSLServerCertVerificationResult::Run()
    1229                 : {
    1230                 :   // TODO: Assert that we're on the socket transport thread
    1231               4 :   mSocketInfo->SetCertVerificationResult(mErrorCode, mErrorMessageType);
    1232               4 :   return NS_OK;
    1233                 : }
    1234                 : 
    1235                 : } } // namespace mozilla::psm

Generated by: LCOV version 1.7