LCOV - app.info - security/manager/ssl/src/SSLServerCertVerification.cpp

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-04-21 | 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            1372 : 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            1372 :                                    &gCertVerificationThreadPool);
         189            1372 :   if (NS_FAILED(rv)) {
         190               0 :     NS_WARNING("Failed to create SSL cert verification threads.");
         191               0 :     return;
         192                 :   }
         193                 :
         194            1372 :   (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
         195            1372 :   (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
         196            1372 :   (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            1372 : void StopSSLServerCertVerificationThreads()
         210                 : {
         211            1372 :   if (gCertVerificationThreadPool) {
         212            1372 :     gCertVerificationThreadPool->Shutdown();
         213            1372 :     NS_RELEASE(gCertVerificationThreadPool);
         214                 :   }
         215            1372 : }
         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