1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * For connections that are not processed on the socket transport thread, we do
9 * NOT use the async logic described below. Instead, we authenticate the
10 * certificate on the thread that the connection's I/O happens on,
11 * synchronously. This allows us to do certificate verification for blocking
12 * (not non-blocking) sockets and sockets that have their I/O processed on a
13 * thread other than the socket transport service thread. Also, we DO NOT
14 * support blocking sockets on the socket transport service thread at all.
16 * During certificate authentication, we call CERT_PKIXVerifyCert or
17 * CERT_VerifyCert. These functions may make zero or more HTTP requests
18 * for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
19 * for these requests processes them on the socket transport service thread.
21 * If the connection for which we are verifying the certificate is happening
22 * on the socket transport thread (the usually case, at least for HTTP), then
23 * if our cert auth hook were to call the CERT_*Verify* functions directly,
24 * there would be a deadlock: The CERT_*Verify* function would cause an event
25 * to be asynchronously posted to the socket transport thread, and then it
26 * would block the socket transport thread waiting to be notified of the HTTP
27 * response. However, the HTTP request would never actually be processed
28 * because the socket transport thread would be blocked and so it wouldn't be
29 * able process HTTP requests. (i.e. Deadlock.)
31 * Consequently, when we are asked to verify a certificate on the socket
32 * transport service thread, we must always call the CERT_*Verify* cert
33 * functions on another thread. To accomplish this, our auth cert hook
34 * dispatches a SSLServerCertVerificationJob to a pool of background threads,
35 * and then immediatley return SECWouldBlock to libssl. These jobs are where
36 * the CERT_*Verify* functions are actually called.
38 * When our auth cert hook returns SECWouldBlock, libssl will carry on the
39 * handshake while we validate the certificate. This will free up the socket
40 * transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
41 * requests needed for cert verification as mentioned above--can be processed.
43 * Once the CERT_*Verify* function returns, the cert verification job
44 * dispatches a SSLServerCertVerificationResult to the socket transport thread;
45 * the SSLServerCertVerificationResult will notify libssl that the certificate
46 * authentication is complete. Once libssl is notified that the authentication
47 * is complete, it will continue the SSL handshake (if it hasn't already
48 * finished) and it will begin allowing us to send/receive data on the
51 * Timeline of events (for connections managed by the socket transport service):
53 * * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
55 * * SSLServerCertVerificationJob::Dispatch queues a job
56 * (instance of SSLServerCertVerificationJob) to its background thread
58 * * One of the background threads calls CERT_*Verify*, which may enqueue
59 * some HTTP request(s) onto the socket transport thread, and then
60 * blocks that background thread waiting for the responses and/or timeouts
61 * or errors for those requests.
62 * * Once those HTTP responses have all come back or failed, the
63 * CERT_*Verify* function returns a result indicating that the validation
64 * succeeded or failed.
65 * * If the validation succeeded, then a SSLServerCertVerificationResult
66 * event is posted to the socket transport thread, and the cert
67 * verification thread becomes free to verify other certificates.
68 * * Otherwise, a CertErrorRunnable is posted to the socket transport thread
69 * and then to the main thread (blocking both, see CertErrorRunnable) to
70 * do cert override processing and bad cert listener notification. Then
71 * the cert verification thread becomes free to verify other certificates.
72 * * After processing cert overrides, the CertErrorRunnable will dispatch a
73 * SSLServerCertVerificationResult event to the socket transport thread to
74 * notify it of the result of the override processing; then it returns,
75 * freeing up the main thread.
76 * * The SSLServerCertVerificationResult event will either wake up the
77 * socket (using SSL_RestartHandshakeAfterServerCert) if validation
78 * succeeded or there was an error override, or it will set an error flag
79 * so that the next I/O operation on the socket will fail, causing the
80 * socket transport thread to close the connection.
82 * Cert override processing must happen on the main thread because it accesses
83 * the nsICertOverrideService, and that service must be accessed on the main
84 * thread because some extensions (Selenium, in particular) replace it with a
85 * Javascript implementation, and chrome JS must always be run on the main
88 * SSLServerCertVerificationResult must be dispatched to the socket transport
89 * thread because we must only call SSL_* functions on the socket transport
90 * thread since they may do I/O, because many parts of nsNSSSocketInfo (the
91 * subclass of TransportSecurityInfo used when validating certificates during
92 * an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
93 * we need the event to interrupt the PR_Poll that may waiting for I/O on the
94 * socket for which we are validating the cert.
97 #include "SSLServerCertVerification.h"
98 #include "CertVerifier.h"
99 #include "nsIBadCertListener2.h"
100 #include "nsICertOverrideService.h"
101 #include "nsIStrictTransportSecurityService.h"
102 #include "nsNSSComponent.h"
103 #include "nsNSSCleaner.h"
104 #include "nsRecentBadCerts.h"
105 #include "nsNSSIOLayer.h"
106 #include "nsNSSShutDown.h"
108 #include "mozilla/Assertions.h"
109 #include "mozilla/Mutex.h"
110 #include "mozilla/Telemetry.h"
111 #include "nsIThreadPool.h"
112 #include "nsNetUtil.h"
113 #include "nsXPCOMCIDInternal.h"
114 #include "nsComponentManagerUtils.h"
115 #include "nsServiceManagerUtils.h"
116 #include "nsIConsoleService.h"
117 #include "PSMRunnable.h"
118 #include "SharedSSLState.h"
127 extern PRLogModuleInfo
* gPIPNSSLog
;
130 namespace mozilla
{ namespace psm
{
134 NS_DEFINE_CID(kNSSComponentCID
, NS_NSSCOMPONENT_CID
);
136 NSSCleanupAutoPtrClass(CERTCertificate
, CERT_DestroyCertificate
)
137 NSSCleanupAutoPtrClass_WithParam(PLArenaPool
, PORT_FreeArena
, FalseParam
, false)
139 // do not use a nsCOMPtr to avoid static initializer/destructor
140 nsIThreadPool
* gCertVerificationThreadPool
= nullptr;
142 // We avoid using a mutex for the success case to avoid lock-related
143 // performance issues. However, we do use a lock in the error case to simplify
144 // the code, since performance in the error case is not important.
145 Mutex
*gSSLVerificationTelemetryMutex
= nullptr;
147 } // unnamed namespace
149 // Called when the socket transport thread starts, to initialize the SSL cert
150 // verification thread pool. By tying the thread pool startup/shutdown directly
151 // to the STS thread's lifetime, we ensure that they are *always* available for
152 // SSL connections and that there are no races during startup and especially
153 // shutdown. (Previously, we have had multiple problems with races in PSM
154 // background threads, and the race-prevention/shutdown logic used there is
155 // brittle. Since this service is critical to things like downloading updates,
156 // we take no chances.) Also, by doing things this way, we avoid the need for
157 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
160 InitializeSSLServerCertVerificationThreads()
162 gSSLVerificationTelemetryMutex
= new Mutex("SSLVerificationTelemetryMutex");
163 // TODO: tuning, make parameters preferences
164 // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
165 // Currently, the nsThreadPool.h header isn't exported for us to do so.
166 nsresult rv
= CallCreateInstance(NS_THREADPOOL_CONTRACTID
,
167 &gCertVerificationThreadPool
);
169 NS_WARNING("Failed to create SSL cert verification threads.");
173 (void) gCertVerificationThreadPool
->SetIdleThreadLimit(5);
174 (void) gCertVerificationThreadPool
->SetIdleThreadTimeout(30 * 1000);
175 (void) gCertVerificationThreadPool
->SetThreadLimit(5);
176 (void) gCertVerificationThreadPool
->SetName(NS_LITERAL_CSTRING("SSL Cert"));
179 // Called when the socket transport thread finishes, to destroy the thread
180 // pool. Since the socket transport service has stopped processing events, it
181 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
182 // down the SSL cert verification infrastructure. Also, the STS will not
183 // dispatch many SSL verification result events at this point, so any pending
184 // cert verifications will (correctly) fail at the point they are dispatched.
186 // The other shutdown race condition that is possible is a race condition with
187 // shutdown of the nsNSSComponent service. We use the
188 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
189 void StopSSLServerCertVerificationThreads()
191 if (gCertVerificationThreadPool
) {
192 gCertVerificationThreadPool
->Shutdown();
193 NS_RELEASE(gCertVerificationThreadPool
);
195 if (gSSLVerificationTelemetryMutex
) {
196 delete gSSLVerificationTelemetryMutex
;
197 gSSLVerificationTelemetryMutex
= nullptr;
204 LogInvalidCertError(TransportSecurityInfo
*socketInfo
,
205 const nsACString
&host
,
206 const nsACString
&hostWithPort
,
208 PRErrorCode errorCode
,
209 ::mozilla::psm::SSLErrorMessageType errorMessageType
,
213 socketInfo
->GetErrorLogMessage(errorCode
, errorMessageType
, message
);
215 if (!message
.IsEmpty()) {
216 nsCOMPtr
<nsIConsoleService
> console
;
217 console
= do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
219 console
->LogStringMessage(message
.get());
224 // Dispatched to the STS thread to notify the infoObject of the verification
227 // This will cause the PR_Poll in the STS thread to return, so things work
228 // correctly even if the STS thread is blocked polling (only) on the file
229 // descriptor that is waiting for this result.
230 class SSLServerCertVerificationResult
: public nsRunnable
235 SSLServerCertVerificationResult(TransportSecurityInfo
* infoObject
,
236 PRErrorCode errorCode
,
237 Telemetry::ID telemetryID
= Telemetry::HistogramCount
,
238 uint32_t telemetryValue
= -1,
239 SSLErrorMessageType errorMessageType
=
244 const RefPtr
<TransportSecurityInfo
> mInfoObject
;
246 const PRErrorCode mErrorCode
;
247 const SSLErrorMessageType mErrorMessageType
;
248 const Telemetry::ID mTelemetryID
;
249 const uint32_t mTelemetryValue
;
252 class CertErrorRunnable
: public SyncRunnableBase
255 CertErrorRunnable(const void * fdForLogging
,
257 TransportSecurityInfo
* infoObject
,
258 PRErrorCode defaultErrorCodeToReport
,
259 uint32_t collectedErrors
,
260 PRErrorCode errorCodeTrust
,
261 PRErrorCode errorCodeMismatch
,
262 PRErrorCode errorCodeExpired
,
263 uint32_t providerFlags
)
264 : mFdForLogging(fdForLogging
), mCert(cert
), mInfoObject(infoObject
),
265 mDefaultErrorCodeToReport(defaultErrorCodeToReport
),
266 mCollectedErrors(collectedErrors
),
267 mErrorCodeTrust(errorCodeTrust
),
268 mErrorCodeMismatch(errorCodeMismatch
),
269 mErrorCodeExpired(errorCodeExpired
),
270 mProviderFlags(providerFlags
)
274 virtual void RunOnTargetThread();
275 RefPtr
<SSLServerCertVerificationResult
> mResult
; // out
277 SSLServerCertVerificationResult
*CheckCertOverrides();
279 const void * const mFdForLogging
; // may become an invalid pointer; do not dereference
280 const nsCOMPtr
<nsIX509Cert
> mCert
;
281 const RefPtr
<TransportSecurityInfo
> mInfoObject
;
282 const PRErrorCode mDefaultErrorCodeToReport
;
283 const uint32_t mCollectedErrors
;
284 const PRErrorCode mErrorCodeTrust
;
285 const PRErrorCode mErrorCodeMismatch
;
286 const PRErrorCode mErrorCodeExpired
;
287 const uint32_t mProviderFlags
;
290 SSLServerCertVerificationResult
*
291 CertErrorRunnable::CheckCertOverrides()
293 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
, ("[%p][%p] top of CheckCertOverrides\n",
294 mFdForLogging
, this));
296 if (!NS_IsMainThread()) {
297 NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
298 return new SSLServerCertVerificationResult(mInfoObject
,
299 mDefaultErrorCodeToReport
);
303 mInfoObject
->GetPort(&port
);
305 nsCString hostWithPortString
;
306 hostWithPortString
.AppendASCII(mInfoObject
->GetHostName());
307 hostWithPortString
.AppendLiteral(":");
308 hostWithPortString
.AppendInt(port
);
310 uint32_t remaining_display_errors
= mCollectedErrors
;
314 // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
315 // connections must be dropped when there are any certificate errors
316 // (STS Spec section 7.3).
317 bool strictTransportSecurityEnabled
= false;
318 nsCOMPtr
<nsIStrictTransportSecurityService
> stss
319 = do_GetService(NS_STSSERVICE_CONTRACTID
, &nsrv
);
320 if (NS_SUCCEEDED(nsrv
)) {
321 nsCOMPtr
<nsISSLSocketControl
> sslSocketControl
= do_QueryInterface(
322 NS_ISUPPORTS_CAST(nsITransportSecurityInfo
*, mInfoObject
));
323 nsrv
= stss
->IsStsHost(mInfoObject
->GetHostName(),
325 &strictTransportSecurityEnabled
);
327 if (NS_FAILED(nsrv
)) {
328 return new SSLServerCertVerificationResult(mInfoObject
,
329 mDefaultErrorCodeToReport
);
332 if (!strictTransportSecurityEnabled
) {
333 nsCOMPtr
<nsICertOverrideService
> overrideService
=
334 do_GetService(NS_CERTOVERRIDE_CONTRACTID
);
335 // it is fine to continue without the nsICertOverrideService
337 uint32_t overrideBits
= 0;
342 bool isTemporaryOverride
; // we don't care
343 nsCString
hostString(mInfoObject
->GetHostName());
344 nsrv
= overrideService
->HasMatchingOverride(hostString
, port
,
347 &isTemporaryOverride
,
349 if (NS_SUCCEEDED(nsrv
) && haveOverride
)
351 // remove the errors that are already overriden
352 remaining_display_errors
&= ~overrideBits
;
356 if (!remaining_display_errors
) {
357 // all errors are covered by override rules, so let's accept the cert
358 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
359 ("[%p][%p] All errors covered by override rules\n",
360 mFdForLogging
, this));
361 return new SSLServerCertVerificationResult(mInfoObject
, 0);
364 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
365 ("[%p][%p] Strict-Transport-Security is violated: untrusted "
366 "transport layer\n", mFdForLogging
, this));
369 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
370 ("[%p][%p] Certificate error was not overridden\n",
371 mFdForLogging
, this));
373 // Ok, this is a full stop.
374 // First, deliver the technical details of the broken SSL status.
376 // Try to get a nsIBadCertListener2 implementation from the socket consumer.
377 nsCOMPtr
<nsISSLSocketControl
> sslSocketControl
= do_QueryInterface(
378 NS_ISUPPORTS_CAST(nsITransportSecurityInfo
*, mInfoObject
));
379 if (sslSocketControl
) {
380 nsCOMPtr
<nsIInterfaceRequestor
> cb
;
381 sslSocketControl
->GetNotificationCallbacks(getter_AddRefs(cb
));
383 nsCOMPtr
<nsIBadCertListener2
> bcl
= do_GetInterface(cb
);
385 nsIInterfaceRequestor
*csi
386 = static_cast<nsIInterfaceRequestor
*>(mInfoObject
);
387 bool suppressMessage
= false; // obsolete, ignored
388 nsrv
= bcl
->NotifyCertProblem(csi
, mInfoObject
->SSLStatus(),
389 hostWithPortString
, &suppressMessage
);
394 nsCOMPtr
<nsIX509CertDB
> certdb
= do_GetService(NS_X509CERTDB_CONTRACTID
);
395 nsCOMPtr
<nsIRecentBadCerts
> recentBadCertsService
;
397 bool isPrivate
= mProviderFlags
& nsISocketProvider::NO_PERMANENT_STORAGE
;
398 certdb
->GetRecentBadCerts(isPrivate
, getter_AddRefs(recentBadCertsService
));
401 if (recentBadCertsService
) {
402 NS_ConvertUTF8toUTF16
hostWithPortStringUTF16(hostWithPortString
);
403 recentBadCertsService
->AddBadCert(hostWithPortStringUTF16
,
404 mInfoObject
->SSLStatus());
407 // pick the error code to report by priority
408 PRErrorCode errorCodeToReport
= mErrorCodeTrust
? mErrorCodeTrust
409 : mErrorCodeMismatch
? mErrorCodeMismatch
410 : mErrorCodeExpired
? mErrorCodeExpired
411 : mDefaultErrorCodeToReport
;
413 SSLServerCertVerificationResult
*result
=
414 new SSLServerCertVerificationResult(mInfoObject
,
416 Telemetry::HistogramCount
,
418 OverridableCertErrorMessage
);
420 LogInvalidCertError(mInfoObject
,
421 nsDependentCString(mInfoObject
->GetHostName()),
425 result
->mErrorMessageType
,
432 CertErrorRunnable::RunOnTargetThread()
434 MOZ_ASSERT(NS_IsMainThread());
436 mResult
= CheckCertOverrides();
441 // Returns null with the error code (PR_GetError()) set if it does not create
442 // the CertErrorRunnable.
444 CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport
,
445 TransportSecurityInfo
* infoObject
,
446 CERTCertificate
* cert
,
447 const void * fdForLogging
,
448 uint32_t providerFlags
,
451 MOZ_ASSERT(infoObject
);
454 // cert was revoked, don't do anything else
455 if (defaultErrorCodeToReport
== SEC_ERROR_REVOKED_CERTIFICATE
) {
456 PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE
, 0);
460 if (defaultErrorCodeToReport
== 0) {
461 NS_ERROR("No error code set during certificate validation failure.");
462 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
466 RefPtr
<nsNSSCertificate
> nssCert(nsNSSCertificate::Create(cert
));
468 NS_ERROR("nsNSSCertificate::Create failed");
469 PR_SetError(SEC_ERROR_NO_MEMORY
, 0);
475 RefPtr
<CertVerifier
> certVerifier(GetDefaultCertVerifier());
477 NS_ERROR("GetDefaultCerVerifier failed");
478 PR_SetError(defaultErrorCodeToReport
, 0);
482 PLArenaPool
*log_arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
483 PLArenaPoolCleanerFalseParam
log_arena_cleaner(log_arena
);
485 NS_ERROR("PORT_NewArena failed");
486 return nullptr; // PORT_NewArena set error code
489 CERTVerifyLog
* verify_log
= PORT_ArenaZNew(log_arena
, CERTVerifyLog
);
491 NS_ERROR("PORT_ArenaZNew failed");
492 return nullptr; // PORT_ArenaZNew set error code
494 CERTVerifyLogContentsCleaner
verify_log_cleaner(verify_log
);
495 verify_log
->arena
= log_arena
;
497 srv
= certVerifier
->VerifyCert(cert
, certificateUsageSSLServer
, now
,
498 infoObject
, 0, nullptr, nullptr, verify_log
);
500 // We ignore the result code of the cert verification.
501 // Either it is a failure, which is expected, and we'll process the
503 // Or it is a success, then a domain mismatch is the only
506 PRErrorCode errorCodeMismatch
= 0;
507 PRErrorCode errorCodeTrust
= 0;
508 PRErrorCode errorCodeExpired
= 0;
510 uint32_t collected_errors
= 0;
512 if (infoObject
->IsCertIssuerBlacklisted()) {
513 collected_errors
|= nsICertOverrideService::ERROR_UNTRUSTED
;
514 errorCodeTrust
= defaultErrorCodeToReport
;
517 // Check the name field against the desired hostname.
518 if (CERT_VerifyCertName(cert
, infoObject
->GetHostName()) != SECSuccess
) {
519 collected_errors
|= nsICertOverrideService::ERROR_MISMATCH
;
520 errorCodeMismatch
= SSL_ERROR_BAD_CERT_DOMAIN
;
523 CERTVerifyLogNode
*i_node
;
524 for (i_node
= verify_log
->head
; i_node
; i_node
= i_node
->next
)
526 switch (i_node
->error
)
528 case SEC_ERROR_UNKNOWN_ISSUER
:
529 case SEC_ERROR_CA_CERT_INVALID
:
530 case SEC_ERROR_UNTRUSTED_ISSUER
:
531 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE
:
532 case SEC_ERROR_UNTRUSTED_CERT
:
533 case SEC_ERROR_INADEQUATE_KEY_USAGE
:
534 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
:
535 // We group all these errors as "cert not trusted"
536 collected_errors
|= nsICertOverrideService::ERROR_UNTRUSTED
;
537 if (errorCodeTrust
== SECSuccess
) {
538 errorCodeTrust
= i_node
->error
;
541 case SSL_ERROR_BAD_CERT_DOMAIN
:
542 collected_errors
|= nsICertOverrideService::ERROR_MISMATCH
;
543 if (errorCodeMismatch
== SECSuccess
) {
544 errorCodeMismatch
= i_node
->error
;
547 case SEC_ERROR_EXPIRED_CERTIFICATE
:
548 collected_errors
|= nsICertOverrideService::ERROR_TIME
;
549 if (errorCodeExpired
== SECSuccess
) {
550 errorCodeExpired
= i_node
->error
;
554 PR_SetError(i_node
->error
, 0);
559 if (!collected_errors
)
561 // This will happen when CERT_*Verify* only returned error(s) that are
562 // not on our whitelist of overridable certificate errors.
563 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
, ("[%p] !collected_errors: %d\n",
564 fdForLogging
, static_cast<int>(defaultErrorCodeToReport
)));
565 PR_SetError(defaultErrorCodeToReport
, 0);
569 infoObject
->SetStatusErrorBits(*nssCert
, collected_errors
);
571 return new CertErrorRunnable(fdForLogging
,
572 static_cast<nsIX509Cert
*>(nssCert
.get()),
573 infoObject
, defaultErrorCodeToReport
,
574 collected_errors
, errorCodeTrust
,
575 errorCodeMismatch
, errorCodeExpired
,
579 // When doing async cert processing, we dispatch one of these runnables to the
580 // socket transport service thread, which blocks the socket transport
581 // service thread while it waits for the inner CertErrorRunnable to execute
582 // CheckCertOverrides on the main thread. CheckCertOverrides must block events
583 // on both of these threads because it calls TransportSecurityInfo::GetInterface(),
584 // which may call nsHttpConnection::GetInterface() through
585 // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always
586 // execute on the main thread, with the socket transport service thread
588 class CertErrorRunnableRunnable
: public nsRunnable
591 CertErrorRunnableRunnable(CertErrorRunnable
* certErrorRunnable
)
592 : mCertErrorRunnable(certErrorRunnable
)
598 nsresult rv
= mCertErrorRunnable
->DispatchToMainThreadAndWait();
599 // The result must run on the socket transport thread, which we are already
600 // on, so we can just run it directly, instead of dispatching it.
601 if (NS_SUCCEEDED(rv
)) {
602 rv
= mCertErrorRunnable
->mResult
? mCertErrorRunnable
->mResult
->Run()
603 : NS_ERROR_UNEXPECTED
;
607 RefPtr
<CertErrorRunnable
> mCertErrorRunnable
;
610 class SSLServerCertVerificationJob
: public nsRunnable
613 // Must be called only on the socket transport thread
614 static SECStatus
Dispatch(const void * fdForLogging
,
615 TransportSecurityInfo
* infoObject
,
616 CERTCertificate
* serverCert
,
617 SECItem
* stapledOCSPResponse
,
618 uint32_t providerFlags
);
622 // Must be called only on the socket transport thread
623 SSLServerCertVerificationJob(const void * fdForLogging
,
624 TransportSecurityInfo
* infoObject
,
625 CERTCertificate
* cert
,
626 SECItem
* stapledOCSPResponse
,
627 uint32_t providerFlags
);
628 const void * const mFdForLogging
;
629 const RefPtr
<TransportSecurityInfo
> mInfoObject
;
630 const ScopedCERTCertificate mCert
;
631 const uint32_t mProviderFlags
;
632 const TimeStamp mJobStartTime
;
633 const ScopedSECItem mStapledOCSPResponse
;
636 SSLServerCertVerificationJob::SSLServerCertVerificationJob(
637 const void * fdForLogging
, TransportSecurityInfo
* infoObject
,
638 CERTCertificate
* cert
, SECItem
* stapledOCSPResponse
,
639 uint32_t providerFlags
)
640 : mFdForLogging(fdForLogging
)
641 , mInfoObject(infoObject
)
642 , mCert(CERT_DupCertificate(cert
))
643 , mProviderFlags(providerFlags
)
644 , mJobStartTime(TimeStamp::Now())
645 , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse
))
650 PSM_SSL_PKIX_AuthCertificate(CERTCertificate
*peerCert
,
651 nsIInterfaceRequestor
* pinarg
,
652 const char * hostname
,
653 CERTCertList
**validationChain
,
654 SECOidTag
*evOidPolicy
)
656 RefPtr
<CertVerifier
> certVerifier(GetDefaultCertVerifier());
658 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
662 SECStatus rv
= certVerifier
->VerifyCert(peerCert
,
663 certificateUsageSSLServer
, PR_Now(),
664 pinarg
, 0, validationChain
, evOidPolicy
);
666 if (rv
== SECSuccess
) {
667 /* cert is OK. This is the client side of an SSL connection.
668 * Now check the name field in the cert against the desired hostname.
669 * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
671 if (hostname
&& hostname
[0])
672 rv
= CERT_VerifyCertName(peerCert
, hostname
);
675 if (rv
!= SECSuccess
)
676 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN
);
682 struct nsSerialBinaryBlacklistEntry
685 const char *binary_serial
;
689 static struct nsSerialBinaryBlacklistEntry myUTNBlacklistEntries
[] = {
690 { 17, "\x00\x92\x39\xd5\x34\x8f\x40\xd1\x69\x5a\x74\x54\x70\xe1\xf2\x3f\x43" },
691 { 17, "\x00\xd8\xf3\x5f\x4e\xb7\x87\x2b\x2d\xab\x06\x92\xe3\x15\x38\x2f\xb0" },
692 { 16, "\x72\x03\x21\x05\xc5\x0c\x08\x57\x3d\x8e\xa5\x30\x4e\xfe\xe8\xb0" },
693 { 17, "\x00\xb0\xb7\x13\x3e\xd0\x96\xf9\xb5\x6f\xae\x91\xc8\x74\xbd\x3a\xc0" },
694 { 16, "\x39\x2a\x43\x4f\x0e\x07\xdf\x1f\x8a\xa3\x05\xde\x34\xe0\xc2\x29" },
695 { 16, "\x3e\x75\xce\xd4\x6b\x69\x30\x21\x21\x88\x30\xae\x86\xa8\x2a\x71" },
696 { 17, "\x00\xe9\x02\x8b\x95\x78\xe4\x15\xdc\x1a\x71\x0a\x2b\x88\x15\x44\x47" },
697 { 17, "\x00\xd7\x55\x8f\xda\xf5\xf1\x10\x5b\xb2\x13\x28\x2b\x70\x77\x29\xa3" },
698 { 16, "\x04\x7e\xcb\xe9\xfc\xa5\x5f\x7b\xd0\x9e\xae\x36\xe1\x0c\xae\x1e" },
699 { 17, "\x00\xf5\xc8\x6a\xf3\x61\x62\xf1\x3a\x64\xf5\x4f\x6d\xc9\x58\x7c\x06" },
700 { 0, 0 } // end marker
703 // Call this if we have already decided that a cert should be treated as INVALID,
704 // in order to check if we to worsen the error to REVOKED.
706 PSM_SSL_DigiNotarTreatAsRevoked(CERTCertificate
* serverCert
,
707 CERTCertList
* serverCertChain
)
709 // If any involved cert was issued by DigiNotar,
710 // and serverCert was issued after 01-JUL-2011,
711 // then worsen the error to revoked.
714 PRStatus status
= PR_ParseTimeString("01-JUL-2011 00:00", true, &cutoff
);
715 if (status
!= PR_SUCCESS
) {
716 NS_ASSERTION(status
== PR_SUCCESS
, "PR_ParseTimeString failed");
717 // be safe, assume it's afterwards, keep going
719 PRTime notBefore
= 0, notAfter
= 0;
720 if (CERT_GetCertTimes(serverCert
, ¬Before
, ¬After
) == SECSuccess
&&
721 notBefore
< cutoff
) {
722 // no worsening for certs issued before the cutoff date
727 for (CERTCertListNode
*node
= CERT_LIST_HEAD(serverCertChain
);
728 !CERT_LIST_END(node
, serverCertChain
);
729 node
= CERT_LIST_NEXT(node
)) {
730 if (node
->cert
->issuerName
&&
731 strstr(node
->cert
->issuerName
, "CN=DigiNotar")) {
732 return SEC_ERROR_REVOKED_CERTIFICATE
;
739 // Call this only if a cert has been reported by NSS as VALID
741 PSM_SSL_BlacklistDigiNotar(CERTCertificate
* serverCert
,
742 CERTCertList
* serverCertChain
)
744 bool isDigiNotarIssuedCert
= false;
746 for (CERTCertListNode
*node
= CERT_LIST_HEAD(serverCertChain
);
747 !CERT_LIST_END(node
, serverCertChain
);
748 node
= CERT_LIST_NEXT(node
)) {
749 if (!node
->cert
->issuerName
)
752 if (strstr(node
->cert
->issuerName
, "CN=DigiNotar")) {
753 isDigiNotarIssuedCert
= true;
757 if (isDigiNotarIssuedCert
) {
758 // let's see if we want to worsen the error code to revoked.
759 PRErrorCode revoked_code
= PSM_SSL_DigiNotarTreatAsRevoked(serverCert
, serverCertChain
);
760 return (revoked_code
!= 0) ? revoked_code
: SEC_ERROR_UNTRUSTED_ISSUER
;
766 // This function assumes that we will only use the SPDY connection coalescing
767 // feature on connections where we have negotiated SPDY using NPN. If we ever
768 // talk SPDY without having negotiated it with SPDY, this code will give wrong
769 // and perhaps unsafe results.
771 // Returns SECSuccess on the initial handshake of all connections, on
772 // renegotiations for any connections where we did not negotiate SPDY, or on any
773 // SPDY connection where the server's certificate did not change.
775 // Prohibit changing the server cert only if we negotiated SPDY,
776 // in order to support SPDY's cross-origin connection pooling.
779 BlockServerCertChangeForSpdy(nsNSSSocketInfo
*infoObject
,
780 CERTCertificate
*serverCert
)
782 // Get the existing cert. If there isn't one, then there is
783 // no cert change to worry about.
784 nsCOMPtr
<nsIX509Cert
> cert
;
785 nsCOMPtr
<nsIX509Cert2
> cert2
;
787 RefPtr
<nsSSLStatus
> status(infoObject
->SSLStatus());
789 // If we didn't have a status, then this is the
790 // first handshake on this connection, not a
795 status
->GetServerCert(getter_AddRefs(cert
));
796 cert2
= do_QueryInterface(cert
);
798 NS_NOTREACHED("every nsSSLStatus must have a cert"
799 "that implements nsIX509Cert2");
800 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
804 // Filter out sockets that did not neogtiate SPDY via NPN
805 nsAutoCString negotiatedNPN
;
806 nsresult rv
= infoObject
->GetNegotiatedNPN(negotiatedNPN
);
807 NS_ASSERTION(NS_SUCCEEDED(rv
),
808 "GetNegotiatedNPN() failed during renegotiation");
810 if (NS_SUCCEEDED(rv
) && !StringBeginsWith(negotiatedNPN
,
811 NS_LITERAL_CSTRING("spdy/")))
814 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
816 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
817 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
818 " Assuming spdy.\n"));
821 // Check to see if the cert has actually changed
822 ScopedCERTCertificate
c(cert2
->GetCert());
823 NS_ASSERTION(c
, "very bad and hopefully impossible state");
824 bool sameCert
= CERT_CompareCerts(c
, serverCert
);
828 // Report an error - changed cert is confirmed
829 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
830 ("SPDY Refused to allow new cert during renegotiation\n"));
831 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED
, 0);
836 AuthCertificate(TransportSecurityInfo
* infoObject
, CERTCertificate
* cert
,
837 SECItem
* stapledOCSPResponse
, uint32_t providerFlags
)
839 if (cert
->serialNumber
.data
&&
841 !strcmp(cert
->issuerName
,
842 "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) {
844 unsigned char *server_cert_comparison_start
= cert
->serialNumber
.data
;
845 unsigned int server_cert_comparison_len
= cert
->serialNumber
.len
;
847 while (server_cert_comparison_len
) {
848 if (*server_cert_comparison_start
!= 0)
851 ++server_cert_comparison_start
;
852 --server_cert_comparison_len
;
855 nsSerialBinaryBlacklistEntry
*walk
= myUTNBlacklistEntries
;
856 for ( ; walk
&& walk
->len
; ++walk
) {
858 unsigned char *locked_cert_comparison_start
= (unsigned char*)walk
->binary_serial
;
859 unsigned int locked_cert_comparison_len
= walk
->len
;
861 while (locked_cert_comparison_len
) {
862 if (*locked_cert_comparison_start
!= 0)
865 ++locked_cert_comparison_start
;
866 --locked_cert_comparison_len
;
869 if (server_cert_comparison_len
== locked_cert_comparison_len
&&
870 !memcmp(server_cert_comparison_start
, locked_cert_comparison_start
, locked_cert_comparison_len
)) {
871 PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE
, 0);
878 if (stapledOCSPResponse
) {
879 CERTCertDBHandle
*handle
= CERT_GetDefaultCertDB();
880 rv
= CERT_CacheOCSPResponseFromSideChannel(handle
, cert
, PR_Now(),
883 if (rv
!= SECSuccess
) {
888 CERTCertList
*verifyCertChain
= nullptr;
889 SECOidTag evOidPolicy
;
890 rv
= PSM_SSL_PKIX_AuthCertificate(cert
, infoObject
, infoObject
->GetHostName(),
891 &verifyCertChain
, &evOidPolicy
);
893 // We want to remember the CA certs in the temp db, so that the application can find the
894 // complete chain at any time it might need it.
895 // But we keep only those CA certs in the temp db, that we didn't already know.
897 RefPtr
<nsSSLStatus
> status(infoObject
->SSLStatus());
898 RefPtr
<nsNSSCertificate
> nsc
;
900 if (!status
|| !status
->mServerCert
) {
901 if( rv
== SECSuccess
){
902 nsc
= nsNSSCertificate::Create(cert
, &evOidPolicy
);
905 nsc
= nsNSSCertificate::Create(cert
);
909 ScopedCERTCertList
certList(verifyCertChain
);
914 PRErrorCode blacklistErrorCode
;
915 if (rv
== SECSuccess
) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
916 blacklistErrorCode
= PSM_SSL_BlacklistDigiNotar(cert
, certList
);
917 } else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
918 PRErrorCode savedErrorCode
= PORT_GetError();
919 // Check if we want to worsen the error code to "revoked".
920 blacklistErrorCode
= PSM_SSL_DigiNotarTreatAsRevoked(cert
, certList
);
921 if (blacklistErrorCode
== 0) {
922 // we don't worsen the code, let's keep the original error code from NSS
923 PORT_SetError(savedErrorCode
);
927 if (blacklistErrorCode
!= 0) {
928 infoObject
->SetCertIssuerBlacklisted();
929 PORT_SetError(blacklistErrorCode
);
934 if (rv
== SECSuccess
) {
935 // We want to avoid storing any intermediate cert information when browsing
936 // in private, transient contexts.
937 if (!(providerFlags
& nsISocketProvider::NO_PERMANENT_STORAGE
)) {
938 for (CERTCertListNode
*node
= CERT_LIST_HEAD(certList
);
939 !CERT_LIST_END(node
, certList
);
940 node
= CERT_LIST_NEXT(node
)) {
942 if (node
->cert
->slot
) {
943 // This cert was found on a token, no need to remember it in the temp db.
947 if (node
->cert
->isperm
) {
948 // We don't need to remember certs already stored in perm db.
952 if (node
->cert
== cert
) {
953 // We don't want to remember the server cert,
954 // the code that cares for displaying page info does this already.
958 // We have found a signer cert that we want to remember.
959 char* nickname
= nsNSSCertificate::defaultServerNickname(node
->cert
);
960 if (nickname
&& *nickname
) {
961 ScopedPK11SlotInfo
slot(PK11_GetInternalKeySlot());
963 PK11_ImportCert(slot
, node
->cert
, CK_INVALID_HANDLE
,
971 // The connection may get terminated, for example, if the server requires
972 // a client cert. Let's provide a minimal SSLStatus
973 // to the caller that contains at least the cert and its status.
975 status
= new nsSSLStatus();
976 infoObject
->SetSSLStatus(status
);
979 if (rv
== SECSuccess
) {
980 // Certificate verification succeeded delete any potential record
981 // of certificate error bits.
982 RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject
,
986 // Certificate verification failed, update the status' bits.
987 RememberCertErrorsTable::GetInstance().LookupCertErrorBits(
991 if (status
&& !status
->mServerCert
) {
992 status
->mServerCert
= nsc
;
993 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
994 ("AuthCertificate setting NEW cert %p\n", status
->mServerCert
.get()));
1001 /*static*/ SECStatus
1002 SSLServerCertVerificationJob::Dispatch(const void * fdForLogging
,
1003 TransportSecurityInfo
* infoObject
,
1004 CERTCertificate
* serverCert
,
1005 SECItem
* stapledOCSPResponse
,
1006 uint32_t providerFlags
)
1008 // Runs on the socket transport thread
1009 if (!infoObject
|| !serverCert
) {
1010 NS_ERROR("Invalid parameters for SSL server cert validation");
1011 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1015 RefPtr
<SSLServerCertVerificationJob
> job(
1016 new SSLServerCertVerificationJob(fdForLogging
, infoObject
, serverCert
,
1017 stapledOCSPResponse
, providerFlags
));
1020 if (!gCertVerificationThreadPool
) {
1021 nrv
= NS_ERROR_NOT_INITIALIZED
;
1023 nrv
= gCertVerificationThreadPool
->Dispatch(job
, NS_DISPATCH_NORMAL
);
1025 if (NS_FAILED(nrv
)) {
1026 // We can't call SetCertVerificationResult here to change
1027 // mCertVerificationState because SetCertVerificationResult will call
1028 // libssl functions that acquire SSL locks that are already being held at
1029 // this point. infoObject->mCertVerificationState will be stuck at
1030 // waiting_for_cert_verification here, but that is OK because we already
1031 // have to be able to handle cases where we encounter non-cert errors while
1033 PRErrorCode error
= nrv
== NS_ERROR_OUT_OF_MEMORY
1034 ? SEC_ERROR_NO_MEMORY
1035 : PR_INVALID_STATE_ERROR
;
1036 PORT_SetError(error
);
1040 PORT_SetError(PR_WOULD_BLOCK_ERROR
);
1041 return SECWouldBlock
;
1045 SSLServerCertVerificationJob::Run()
1047 // Runs on a cert verification thread
1049 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
1050 ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject
.get()));
1054 nsNSSShutDownPreventionLock nssShutdownPrevention
;
1055 if (mInfoObject
->isAlreadyShutDown()) {
1056 error
= SEC_ERROR_USER_CANCELLED
;
1058 // Reset the error code here so we can detect if AuthCertificate fails to
1059 // set the error code if/when it fails.
1061 SECStatus rv
= AuthCertificate(mInfoObject
, mCert
, mStapledOCSPResponse
,
1063 if (rv
== SECSuccess
) {
1064 uint32_t interval
= (uint32_t) ((TimeStamp::Now() - mJobStartTime
).ToMilliseconds());
1065 Telemetry::ID telemetryID
;
1066 #ifndef NSS_NO_LIBPKIX
1067 if(nsNSSComponent::globalConstFlagUsePKIXVerification
){
1068 telemetryID
= Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_LIBPKIX
;
1072 telemetryID
= Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_CLASSIC
;
1073 #ifndef NSS_NO_LIBPKIX
1076 RefPtr
<SSLServerCertVerificationResult
> restart(
1077 new SSLServerCertVerificationResult(mInfoObject
, 0,
1078 telemetryID
, interval
));
1079 restart
->Dispatch();
1083 // Note: the interval is not calculated once as PR_GetError MUST be called
1084 // before any other function call
1085 error
= PR_GetError();
1087 TimeStamp now
= TimeStamp::Now();
1088 Telemetry::ID telemetryID
;
1089 #ifndef NSS_NO_LIBPKIX
1090 if(nsNSSComponent::globalConstFlagUsePKIXVerification
){
1091 telemetryID
= Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_LIBPKIX
;
1095 telemetryID
= Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_CLASSIC
;
1096 #ifndef NSS_NO_LIBPKIX
1099 MutexAutoLock
telemetryMutex(*gSSLVerificationTelemetryMutex
);
1100 Telemetry::AccumulateTimeDelta(telemetryID
,
1105 RefPtr
<CertErrorRunnable
> runnable(CreateCertErrorRunnable(
1106 error
, mInfoObject
, mCert
, mFdForLogging
, mProviderFlags
, PR_Now()));
1108 // CreateCertErrorRunnable set a new error code
1109 error
= PR_GetError();
1111 // We must block the the socket transport service thread while the
1112 // main thread executes the CertErrorRunnable. The CertErrorRunnable
1113 // will dispatch the result asynchronously, so we don't have to block
1114 // this thread waiting for it.
1116 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
1117 ("[%p][%p] Before dispatching CertErrorRunnable\n",
1118 mFdForLogging
, runnable
.get()));
1121 nsCOMPtr
<nsIEventTarget
> stsTarget
1122 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &nrv
);
1123 if (NS_SUCCEEDED(nrv
)) {
1124 nrv
= stsTarget
->Dispatch(new CertErrorRunnableRunnable(runnable
),
1125 NS_DISPATCH_NORMAL
);
1127 if (NS_SUCCEEDED(nrv
)) {
1131 NS_ERROR("Failed to dispatch CertErrorRunnable");
1132 error
= PR_INVALID_STATE_ERROR
;
1138 NS_NOTREACHED("no error set during certificate validation failure");
1139 error
= PR_INVALID_STATE_ERROR
;
1142 RefPtr
<SSLServerCertVerificationResult
> failure(
1143 new SSLServerCertVerificationResult(mInfoObject
, error
));
1144 failure
->Dispatch();
1148 } // unnamed namespace
1150 // Extracts whatever information we need out of fd (using SSL_*) and passes it
1151 // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
1152 // never do anything with fd except logging.
1154 AuthCertificateHook(void *arg
, PRFileDesc
*fd
, PRBool checkSig
, PRBool isServer
)
1156 // Runs on the socket transport thread
1158 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
,
1159 ("[%p] starting AuthCertificateHook\n", fd
));
1161 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
1162 // doing verification without checking signatures.
1163 NS_ASSERTION(checkSig
, "AuthCertificateHook: checkSig unexpectedly false");
1165 // PSM never causes libssl to call this function with PR_TRUE for isServer,
1166 // and many things in PSM assume that we are a client.
1167 NS_ASSERTION(!isServer
, "AuthCertificateHook: isServer unexpectedly true");
1169 nsNSSSocketInfo
*socketInfo
= static_cast<nsNSSSocketInfo
*>(arg
);
1172 // This is the first callback during full handshakes.
1173 socketInfo
->SetFirstServerHelloReceived();
1176 ScopedCERTCertificate
serverCert(SSL_PeerCertificate(fd
));
1178 if (!checkSig
|| isServer
|| !socketInfo
|| !serverCert
) {
1179 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
1183 if (BlockServerCertChangeForSpdy(socketInfo
, serverCert
) != SECSuccess
)
1188 nsCOMPtr
<nsIEventTarget
> sts
1189 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &nrv
);
1190 if (NS_SUCCEEDED(nrv
)) {
1191 nrv
= sts
->IsOnCurrentThread(&onSTSThread
);
1194 if (NS_FAILED(nrv
)) {
1195 NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
1196 PR_SetError(PR_UNKNOWN_ERROR
, 0);
1200 // SSL_PeerStapledOCSPResponses will never return a non-empty response if
1201 // OCSP stapling wasn't enabled because libssl wouldn't have let the server
1202 // return a stapled OCSP response.
1203 // We don't own these pointers.
1204 const SECItemArray
*csa
= SSL_PeerStapledOCSPResponses(fd
);
1205 SECItem
*stapledOCSPResponse
= nullptr;
1206 // we currently only support single stapled responses
1207 if (csa
&& csa
->len
== 1) {
1208 stapledOCSPResponse
= &csa
->items
[0];
1211 uint32_t providerFlags
= 0;
1212 socketInfo
->GetProviderFlags(&providerFlags
);
1216 // We *must* do certificate verification on a background thread because
1217 // we need the socket transport thread to be free for our OCSP requests,
1218 // and we *want* to do certificate verification on a background thread
1219 // because of the performance benefits of doing so.
1220 socketInfo
->SetCertVerificationWaiting();
1221 SECStatus rv
= SSLServerCertVerificationJob::Dispatch(
1222 static_cast<const void *>(fd
), socketInfo
, serverCert
,
1223 stapledOCSPResponse
, providerFlags
);
1227 // We can't do certificate verification on a background thread, because the
1228 // thread doing the network I/O may not interrupt its network I/O on receipt
1229 // of our SSLServerCertVerificationResult event, and/or it might not even be
1230 // a non-blocking socket.
1232 SECStatus rv
= AuthCertificate(socketInfo
, serverCert
, stapledOCSPResponse
,
1234 if (rv
== SECSuccess
) {
1238 PRErrorCode error
= PR_GetError();
1240 RefPtr
<CertErrorRunnable
> runnable(CreateCertErrorRunnable(
1241 error
, socketInfo
, serverCert
,
1242 static_cast<const void *>(fd
), providerFlags
, PR_Now()));
1244 // CreateCertErrorRunnable sets a new error code when it fails
1245 error
= PR_GetError();
1247 // We have to return SECSuccess or SECFailure based on the result of the
1248 // override processing, so we must block this thread waiting for it. The
1249 // CertErrorRunnable will NOT dispatch the result at all, since we passed
1250 // false for CreateCertErrorRunnable's async parameter
1251 nrv
= runnable
->DispatchToMainThreadAndWait();
1252 if (NS_FAILED(nrv
)) {
1253 NS_ERROR("Failed to dispatch CertErrorRunnable");
1254 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
1258 if (!runnable
->mResult
) {
1259 NS_ERROR("CertErrorRunnable did not set result");
1260 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
1264 if (runnable
->mResult
->mErrorCode
== 0) {
1265 return SECSuccess
; // cert error override occurred.
1268 // We must call SetCanceled here to set the error message type
1269 // in case it isn't PlainErrorMessage, which is what we would
1270 // default to if we just called
1271 // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
1272 // SECFailure without doing this.
1273 socketInfo
->SetCanceled(runnable
->mResult
->mErrorCode
,
1274 runnable
->mResult
->mErrorMessageType
);
1275 error
= runnable
->mResult
->mErrorCode
;
1280 NS_ERROR("error code not set");
1281 error
= PR_UNKNOWN_ERROR
;
1284 PR_SetError(error
, 0);
1288 #ifndef NSS_NO_LIBPKIX
1289 class InitializeIdentityInfo
: public nsRunnable
1290 , public nsNSSShutDownObject
1295 nsNSSShutDownPreventionLock nssShutdownPrevention
;
1296 if (isAlreadyShutDown())
1300 nsCOMPtr
<nsINSSComponent
> inss
= do_GetService(PSM_COMPONENT_CONTRACTID
, &rv
);
1301 if (NS_SUCCEEDED(rv
))
1302 inss
->EnsureIdentityInfoLoaded();
1306 virtual void virtualDestroyNSSReference()
1310 ~InitializeIdentityInfo()
1312 nsNSSShutDownPreventionLock nssShutdownPrevention
;
1313 if (!isAlreadyShutDown())
1314 shutdown(calledFromObject
);
1319 void EnsureServerVerificationInitialized()
1321 #ifndef NSS_NO_LIBPKIX
1322 // Should only be called from socket transport thread due to the static
1323 // variable and the reference to gCertVerificationThreadPool
1325 static bool triggeredCertVerifierInit
= false;
1326 if (triggeredCertVerifierInit
)
1328 triggeredCertVerifierInit
= true;
1330 RefPtr
<InitializeIdentityInfo
> initJob
= new InitializeIdentityInfo();
1331 if (gCertVerificationThreadPool
)
1332 gCertVerificationThreadPool
->Dispatch(initJob
, NS_DISPATCH_NORMAL
);
1336 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
1337 TransportSecurityInfo
* infoObject
, PRErrorCode errorCode
,
1338 Telemetry::ID telemetryID
, uint32_t telemetryValue
,
1339 SSLErrorMessageType errorMessageType
)
1340 : mInfoObject(infoObject
)
1341 , mErrorCode(errorCode
)
1342 , mErrorMessageType(errorMessageType
)
1343 , mTelemetryID(telemetryID
)
1344 , mTelemetryValue(telemetryValue
)
1346 // We accumulate telemetry for (only) successful validations on the main thread
1347 // to avoid adversely affecting performance by acquiring the mutex that we use
1348 // when accumulating the telemetry for unsuccessful validations. Unsuccessful
1349 // validations times are accumulated elsewhere.
1350 MOZ_ASSERT(telemetryID
== Telemetry::HistogramCount
|| errorCode
== 0);
1354 SSLServerCertVerificationResult::Dispatch()
1357 nsCOMPtr
<nsIEventTarget
> stsTarget
1358 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &rv
);
1359 NS_ASSERTION(stsTarget
,
1360 "Failed to get socket transport service event target");
1361 rv
= stsTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
1362 NS_ASSERTION(NS_SUCCEEDED(rv
),
1363 "Failed to dispatch SSLServerCertVerificationResult");
1367 SSLServerCertVerificationResult::Run()
1369 // TODO: Assert that we're on the socket transport thread
1370 if (mTelemetryID
!= Telemetry::HistogramCount
) {
1371 Telemetry::Accumulate(mTelemetryID
, mTelemetryValue
);
1373 // XXX: This cast will be removed by the next patch
1374 ((nsNSSSocketInfo
*) mInfoObject
.get())
1375 ->SetCertVerificationResult(mErrorCode
, mErrorMessageType
);
1379 } } // namespace mozilla::psm